diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 2bec41a37..f88c21c65 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -41,6 +41,8 @@ jobs: ~/.cargo/git/db/ target/ key: cargo-clippy-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }}-${{ steps.toolchain.outputs.cachekey }} + - name: Force regenerate lockfile + run: rm -f Cargo.lock && cargo generate-lockfile - run: cargo clippy --locked --workspace --color always -- -D warnings cargo-test: @@ -76,6 +78,8 @@ jobs: ~/.cargo/git/db/ target/ key: cargo-test-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }}-${{ steps.toolchain.outputs.cachekey }} + - name: Force regenerate lockfile + run: rm -f Cargo.lock && cargo generate-lockfile - name: Generate code coverage run: cargo +nightly llvm-cov --locked --workspace --codecov --output-path lcov.info - name: Upload coverage to Codecov diff --git a/Cargo.lock b/Cargo.lock index 37abf2d79..04d1b7954 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -98,7 +98,7 @@ dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", - "aws-smithy-http", + "aws-smithy-http 0.60.12", "aws-smithy-json 0.60.7", "aws-smithy-runtime", "aws-smithy-runtime-api", @@ -118,7 +118,7 @@ dependencies = [ "aws-runtime", "aws-smithy-async", "aws-smithy-eventstream", - "aws-smithy-http", + "aws-smithy-http 0.60.12", "aws-smithy-json 0.60.7", "aws-smithy-runtime", "aws-smithy-runtime-api", @@ -136,7 +136,7 @@ dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", - "aws-smithy-http", + "aws-smithy-http 0.60.12", "aws-smithy-json 0.60.7", "aws-smithy-runtime", "aws-smithy-runtime-api", @@ -155,7 +155,7 @@ dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", - "aws-smithy-http", + "aws-smithy-http 0.60.12", "aws-smithy-json 0.60.7", "aws-smithy-runtime", "aws-smithy-runtime-api", @@ -175,7 +175,7 @@ dependencies = [ "aws-runtime", "aws-smithy-async", "aws-smithy-eventstream", - "aws-smithy-http", + "aws-smithy-http 0.60.12", "aws-smithy-json 0.60.7", "aws-smithy-runtime", "aws-smithy-runtime-api", @@ -194,7 +194,7 @@ dependencies = [ "aws-http", "aws-runtime", "aws-smithy-async", - "aws-smithy-http", + "aws-smithy-http 0.60.12", "aws-smithy-json 0.60.7", "aws-smithy-runtime", "aws-smithy-runtime-api", @@ -267,11 +267,12 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "3.0.6" +version = "3.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" dependencies = [ "anstyle", + "once_cell", "windows-sys 0.59.0", ] @@ -317,9 +318,9 @@ checksum = "df099ccb16cd014ff054ac1bf392c67feeef57164b05c42f037cd40f5d4357f4" dependencies = [ "clipboard-win", "log", - "objc2", - "objc2-app-kit", - "objc2-foundation", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", "parking_lot", "wl-clipboard-rs", "x11rb", @@ -344,24 +345,21 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "ashpd" -version = "0.10.2" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9c39d707614dbcc6bed00015539f488d8e3fe3e66ed60961efc0c90f4b380b3" +checksum = "6cbdf310d77fd3aaee6ea2093db7011dc2d35d2eb3481e5607f1f8d942ed99df" dependencies = [ "async-fs", "async-net", "enumflags2", "futures-channel", "futures-util", - "rand 0.8.5", + "rand 0.9.0", "raw-window-handle", "serde", "serde_repr", "url", - "wayland-backend", - "wayland-client", - "wayland-protocols 0.32.5", - "zbus 5.2.0", + "zbus 5.5.0", ] [[package]] @@ -427,9 +425,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.18" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df895a515f70646414f4b45c0b79082783b80552b373a68283012928df56f522" +checksum = "c0cf008e5e1a9e9e22a7d3c9a4992e21a350290069e36d8fb72304ed17e8f2d2" dependencies = [ "flate2", "futures-core", @@ -476,7 +474,7 @@ dependencies = [ "futures-lite", "parking", "polling", - "rustix 0.38.43", + "rustix 0.38.44", "slab", "tracing", "windows-sys 0.59.0", @@ -519,7 +517,7 @@ dependencies = [ "cfg-if", "event-listener", "futures-lite", - "rustix 0.38.43", + "rustix 0.38.44", "tracing", ] @@ -546,7 +544,7 @@ dependencies = [ "cfg-if", "futures-core", "futures-io", - "rustix 0.38.43", + "rustix 0.38.44", "signal-hook-registry", "slab", "windows-sys 0.59.0", @@ -560,9 +558,9 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.87" +version = "0.1.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d556ec1359574147ec0c4fc5eb525f3f23263a592b1a9c07e0a75b427de55c97" +checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" dependencies = [ "proc-macro2", "quote", @@ -633,18 +631,18 @@ dependencies = [ [[package]] name = "avif-serialize" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e335041290c43101ca215eed6f43ec437eb5a42125573f600fc3fa42b9bddd62" +checksum = "98922d6a4cfbcb08820c69d8eeccc05bb1f29bfa06b4f5b1dbfe9a868bd7608e" dependencies = [ "arrayvec", ] [[package]] name = "aws-config" -version = "1.5.13" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a50b30228d3af8865ce83376b4e99e1ffa34728220fe2860e4df0bb5278d6" +checksum = "6a84fe2c5e9965fba0fbc2001db252f1d57527d82a905cca85127df227bca748" dependencies = [ "aws-credential-types", "aws-runtime", @@ -652,8 +650,8 @@ dependencies = [ "aws-sdk-ssooidc", "aws-sdk-sts", "aws-smithy-async", - "aws-smithy-http", - "aws-smithy-json 0.61.1", + "aws-smithy-http 0.62.0", + "aws-smithy-json 0.61.3", "aws-smithy-runtime", "aws-smithy-runtime-api", "aws-smithy-types", @@ -661,7 +659,7 @@ dependencies = [ "bytes", "fastrand", "hex", - "http 0.2.12", + "http 1.3.1", "ring", "time", "tokio", @@ -672,9 +670,9 @@ dependencies = [ [[package]] name = "aws-credential-types" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60e8f6b615cb5fc60a98132268508ad104310f0cfb25a1c22eee76efdf9154da" +checksum = "4471bef4c22a06d2c7a1b6492493d3fdf24a805323109d6874f9c94d5906ac14" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", @@ -693,39 +691,37 @@ dependencies = [ [[package]] name = "aws-lc-rs" -version = "1.12.0" +version = "1.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f409eb70b561706bf8abba8ca9c112729c481595893fd06a2dd9af8ed8441148" +checksum = "dabb68eb3a7aa08b46fddfd59a3d55c978243557a90ab804769f7e20e67d2b01" dependencies = [ "aws-lc-sys", - "paste", "zeroize", ] [[package]] name = "aws-lc-sys" -version = "0.24.1" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "923ded50f602b3007e5e63e3f094c479d9c8a9b42d7f4034e4afe456aa48bfd2" +checksum = "77926887776171ced7d662120a75998e444d3750c951abfe07f90da130514b1f" dependencies = [ "bindgen 0.69.5", "cc", "cmake", "dunce", "fs_extra", - "paste", ] [[package]] name = "aws-runtime" -version = "1.5.3" +version = "1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16d1aa50accc11a4b4d5c50f7fb81cc0cf60328259c587d0e6b0f11385bde46" +checksum = "0aff45ffe35196e593ea3b9dd65b320e51e2dda95aff4390bc459e461d09c6ad" dependencies = [ "aws-credential-types", "aws-sigv4", "aws-smithy-async", - "aws-smithy-http", + "aws-smithy-http 0.62.0", "aws-smithy-runtime", "aws-smithy-runtime-api", "aws-smithy-types", @@ -743,15 +739,15 @@ dependencies = [ [[package]] name = "aws-sdk-cognitoidentity" -version = "1.54.0" +version = "1.63.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3a63eeb333e6aac318474715bcb47130ceb02d4ce4caa4ebd632ef456ef1f7a" +checksum = "8291b7298e5d57683486ff28476f28576daf2c350e2b75a6d692f0a4764e252d" dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", - "aws-smithy-http", - "aws-smithy-json 0.61.1", + "aws-smithy-http 0.62.0", + "aws-smithy-json 0.61.3", "aws-smithy-runtime", "aws-smithy-runtime-api", "aws-smithy-types", @@ -765,15 +761,15 @@ dependencies = [ [[package]] name = "aws-sdk-cognitoidentityprovider" -version = "1.63.0" +version = "1.73.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cea251ab30246099e3b57406a312ac9d96a8f4cde3fce0470b7d2109ba27307" +checksum = "42553e06865d586faaf13ab1b4f4117fdecc5fdc89f0ad8386180f02b0ed9dfa" dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", - "aws-smithy-http", - "aws-smithy-json 0.61.1", + "aws-smithy-http 0.62.0", + "aws-smithy-json 0.61.3", "aws-smithy-runtime", "aws-smithy-runtime-api", "aws-smithy-types", @@ -787,15 +783,15 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.53.0" +version = "1.62.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1605dc0bf9f0a4b05b451441a17fcb0bda229db384f23bf5cead3adbab0664ac" +checksum = "1d5330ad4e8a1ff49e9f26b738611caa72b105c41d41733801d1a36e8f9de936" dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", - "aws-smithy-http", - "aws-smithy-json 0.61.1", + "aws-smithy-http 0.62.0", + "aws-smithy-json 0.61.3", "aws-smithy-runtime", "aws-smithy-runtime-api", "aws-smithy-types", @@ -809,15 +805,15 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.54.0" +version = "1.63.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59f3f73466ff24f6ad109095e0f3f2c830bfb4cd6c8b12f744c8e61ebf4d3ba1" +checksum = "7956b1a85d49082347a7d17daa2e32df191f3e23c03d47294b99f95413026a78" dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", - "aws-smithy-http", - "aws-smithy-json 0.61.1", + "aws-smithy-http 0.62.0", + "aws-smithy-json 0.61.3", "aws-smithy-runtime", "aws-smithy-runtime-api", "aws-smithy-types", @@ -831,15 +827,15 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.54.0" +version = "1.63.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "249b2acaa8e02fd4718705a9494e3eb633637139aa4bb09d70965b0448e865db" +checksum = "065c533fbe6f84962af33fcf02b0350b7c1f79285baab5924615d2be3b232855" dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", - "aws-smithy-http", - "aws-smithy-json 0.61.1", + "aws-smithy-http 0.62.0", + "aws-smithy-json 0.61.3", "aws-smithy-query", "aws-smithy-runtime", "aws-smithy-runtime-api", @@ -854,12 +850,12 @@ dependencies = [ [[package]] name = "aws-sigv4" -version = "1.2.6" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d3820e0c08d0737872ff3c7c1f21ebbb6693d832312d6152bf18ef50a5471c2" +checksum = "69d03c3c05ff80d54ff860fe38c726f6f494c639ae975203a101335f223386db" dependencies = [ "aws-credential-types", - "aws-smithy-http", + "aws-smithy-http 0.62.0", "aws-smithy-runtime-api", "aws-smithy-types", "bytes", @@ -867,7 +863,7 @@ dependencies = [ "hex", "hmac", "http 0.2.12", - "http 1.2.0", + "http 1.3.1", "once_cell", "percent-encoding", "sha2", @@ -877,9 +873,9 @@ dependencies = [ [[package]] name = "aws-smithy-async" -version = "1.2.3" +version = "1.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "427cb637d15d63d6f9aae26358e1c9a9c09d5aa490d64b09354c8217cfef0f28" +checksum = "1e190749ea56f8c42bf15dd76c65e14f8f765233e6df9b0506d9d934ebef867c" dependencies = [ "futures-util", "pin-project-lite", @@ -888,9 +884,9 @@ dependencies = [ [[package]] name = "aws-smithy-eventstream" -version = "0.60.5" +version = "0.60.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cef7d0a272725f87e51ba2bf89f8c21e4df61b9e49ae1ac367a6d69916ef7c90" +checksum = "7c45d3dddac16c5c59d553ece225a88870cf81b7b813c9cc17b78cf4685eac7a" dependencies = [ "aws-smithy-types", "bytes", @@ -899,9 +895,9 @@ dependencies = [ [[package]] name = "aws-smithy-http" -version = "0.60.11" +version = "0.60.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8bc3e8fdc6b8d07d976e301c02fe553f72a39b7a9fea820e023268467d7ab6" +checksum = "7809c27ad8da6a6a68c454e651d4962479e81472aa19ae99e59f9aba1f9713cc" dependencies = [ "aws-smithy-eventstream", "aws-smithy-runtime-api", @@ -918,6 +914,61 @@ dependencies = [ "tracing", ] +[[package]] +name = "aws-smithy-http" +version = "0.62.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5949124d11e538ca21142d1fba61ab0a2a2c1bc3ed323cdb3e4b878bfb83166" +dependencies = [ + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "bytes-utils", + "futures-core", + "http 0.2.12", + "http 1.3.1", + "http-body 0.4.6", + "once_cell", + "percent-encoding", + "pin-project-lite", + "pin-utils", + "tracing", +] + +[[package]] +name = "aws-smithy-http-client" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0497ef5d53065b7cd6a35e9c1654bd1fefeae5c52900d91d1b188b0af0f29324" +dependencies = [ + "aws-smithy-async", + "aws-smithy-protocol-test", + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "h2 0.4.8", + "http 0.2.12", + "http 1.3.1", + "http-body 0.4.6", + "http-body 1.0.1", + "hyper 0.14.32", + "hyper 1.6.0", + "hyper-rustls 0.24.2", + "hyper-rustls 0.27.5", + "hyper-util", + "indexmap 2.8.0", + "pin-project-lite", + "rustls 0.21.12", + "rustls 0.23.25", + "rustls-native-certs 0.8.1", + "rustls-pki-types", + "serde", + "serde_json", + "tokio", + "tower", + "tracing", +] + [[package]] name = "aws-smithy-json" version = "0.60.7" @@ -929,18 +980,18 @@ dependencies = [ [[package]] name = "aws-smithy-json" -version = "0.61.1" +version = "0.61.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee4e69cc50921eb913c6b662f8d909131bb3e6ad6cb6090d3a39b66fc5c52095" +checksum = "92144e45819cae7dc62af23eac5a038a58aa544432d2102609654376a900bd07" dependencies = [ "aws-smithy-types", ] [[package]] name = "aws-smithy-protocol-test" -version = "0.63.0" +version = "0.63.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b92b62199921f10685c6b588fdbeb81168ae4e7950ae3e5f50145a01bb5f1ad" +checksum = "5b42f13304bed0b96d7471e4770c270bb3eb4fea277727fb03c811e84cb4bf3a" dependencies = [ "assert-json-diff 1.1.0", "aws-smithy-runtime-api", @@ -967,31 +1018,24 @@ dependencies = [ [[package]] name = "aws-smithy-runtime" -version = "1.7.6" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a05dd41a70fc74051758ee75b5c4db2c0ca070ed9229c3df50e9475cda1cb985" +checksum = "f6328865e36c6fd970094ead6b05efd047d3a80ec5fc3be5e743910da9f2ebf8" dependencies = [ "aws-smithy-async", - "aws-smithy-http", - "aws-smithy-protocol-test", + "aws-smithy-http 0.62.0", + "aws-smithy-http-client", "aws-smithy-runtime-api", "aws-smithy-types", "bytes", "fastrand", - "h2 0.3.26", "http 0.2.12", + "http 1.3.1", "http-body 0.4.6", "http-body 1.0.1", - "httparse", - "hyper 0.14.32", - "hyper-rustls 0.24.2", - "indexmap 2.7.0", "once_cell", "pin-project-lite", "pin-utils", - "rustls 0.21.12", - "serde", - "serde_json", "tokio", "tracing", "tracing-subscriber", @@ -999,15 +1043,15 @@ dependencies = [ [[package]] name = "aws-smithy-runtime-api" -version = "1.7.3" +version = "1.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92165296a47a812b267b4f41032ff8069ab7ff783696d217f0994a0d7ab585cd" +checksum = "3da37cf5d57011cb1753456518ec76e31691f1f474b73934a284eb2a1c76510f" dependencies = [ "aws-smithy-async", "aws-smithy-types", "bytes", "http 0.2.12", - "http 1.2.0", + "http 1.3.1", "pin-project-lite", "tokio", "tracing", @@ -1016,20 +1060,20 @@ dependencies = [ [[package]] name = "aws-smithy-types" -version = "1.2.11" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38ddc9bd6c28aeb303477170ddd183760a956a03e083b3902a990238a7e3792d" +checksum = "836155caafba616c0ff9b07944324785de2ab016141c3550bd1c07882f8cee8f" dependencies = [ "base64-simd", "bytes", "bytes-utils", "futures-core", "http 0.2.12", - "http 1.2.0", + "http 1.3.1", "http-body 0.4.6", "http-body 1.0.1", "http-body-util", - "itoa 1.0.14", + "itoa 1.0.15", "num-integer", "pin-project-lite", "pin-utils", @@ -1064,9 +1108,9 @@ dependencies = [ [[package]] name = "aws-types" -version = "1.3.3" +version = "1.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5221b91b3e441e6675310829fd8984801b772cb1546ef6c0e54dec9f1ac13fef" +checksum = "3873f8deed8927ce8d04487630dc9ff73193bab64742a61d050e57a68dec4125" dependencies = [ "aws-credential-types", "aws-smithy-async", @@ -1178,7 +1222,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "rustc-hash 2.1.0", + "rustc-hash 2.1.1", "shlex", "syn 2.0.100", ] @@ -1246,7 +1290,16 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" dependencies = [ - "objc2", + "objc2 0.5.2", +] + +[[package]] +name = "block2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d59b4c170e16f0405a2e95aff44432a0d41aa97675f3d52623effe95792a037" +dependencies = [ + "objc2 0.6.0", ] [[package]] @@ -1284,21 +1337,21 @@ dependencies = [ [[package]] name = "built" -version = "0.7.5" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c360505aed52b7ec96a3636c3f039d99103c37d1d9b4f7a8c743d3ea9ffcd03b" +checksum = "56ed6191a7e78c36abdb16ab65341eefd73d64d303fffccdbb00d51e4205967b" [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "bytemuck" -version = "1.21.0" +version = "1.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" +checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540" [[package]] name = "byteorder" @@ -1389,9 +1442,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.16" +version = "1.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" +checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a" dependencies = [ "jobserver", "libc", @@ -1454,16 +1507,16 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.39" +version = "0.4.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" +checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" dependencies = [ "android-tzdata", "iana-time-zone", "num-traits", "pure-rust-locales", "serde", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -1540,9 +1593,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.46" +version = "4.5.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5c5508ea23c5366f77e53f5a0070e5a84e51687ec3ef9e0464c86dc8d13ce98" +checksum = "c06f5378ea264ad4f82bbc826628b5aad714a75abf6ece087e923010eb937fb6" dependencies = [ "clap", ] @@ -1586,9 +1639,9 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.52" +version = "0.1.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c682c223677e0e5b6b7f63a64b9351844c3f1b1678a68b7ee617e30fb082620e" +checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" dependencies = [ "cc", ] @@ -1685,11 +1738,10 @@ checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "colored" -version = "2.2.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" +checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e" dependencies = [ - "lazy_static", "windows-sys 0.59.0", ] @@ -1714,9 +1766,9 @@ dependencies = [ [[package]] name = "console" -version = "0.15.10" +version = "0.15.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea3c6ecd8059b57859df5c69830340ed3c41d30e3da0c1cbed90a96ac853041b" +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" dependencies = [ "encode_unicode", "libc", @@ -1841,9 +1893,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ "libc", ] @@ -1938,7 +1990,7 @@ dependencies = [ "futures-core", "mio", "parking_lot", - "rustix 0.38.43", + "rustix 0.38.44", "signal-hook", "signal-hook-mio", "winapi", @@ -1955,9 +2007,9 @@ dependencies = [ [[package]] name = "crunchy" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" [[package]] name = "crypto-common" @@ -2022,9 +2074,9 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.6.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" +checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010" [[package]] name = "dbus" @@ -2046,9 +2098,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.11" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" dependencies = [ "powerfmt", "serde", @@ -2078,9 +2130,9 @@ dependencies = [ [[package]] name = "derive_more" -version = "0.99.18" +version = "0.99.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +checksum = "3da29a38df43d6f156149c9b43ded5e018ddff2a855cf2cfd62e8cd7d079c69f" dependencies = [ "convert_case 0.4.0", "proc-macro2", @@ -2132,7 +2184,16 @@ version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" dependencies = [ - "dirs-sys", + "dirs-sys 0.4.1", +] + +[[package]] +name = "dirs" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys 0.5.0", ] [[package]] @@ -2143,16 +2204,40 @@ checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" dependencies = [ "libc", "option-ext", - "redox_users", + "redox_users 0.4.6", "windows-sys 0.48.0", ] +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users 0.5.0", + "windows-sys 0.59.0", +] + [[package]] name = "dispatch" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "dispatch2" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a0d569e003ff27784e0e14e4a594048698e0c0f0b66cabcb51511be55a7caa0" +dependencies = [ + "bitflags 2.9.0", + "block2 0.6.0", + "libc", + "objc2 0.6.0", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -2164,15 +2249,6 @@ dependencies = [ "syn 2.0.100", ] -[[package]] -name = "dlib" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" -dependencies = [ - "libloading 0.8.6", -] - [[package]] name = "dlopen2" version = "0.7.0" @@ -2213,9 +2289,9 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" [[package]] name = "document-features" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6969eaabd2421f8a2775cfd2471a2b634372b4a25d41e3bd647b79912850a0" +checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" dependencies = [ "litrs", ] @@ -2237,9 +2313,9 @@ dependencies = [ [[package]] name = "dtoa" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" +checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" [[package]] name = "dtoa-short" @@ -2258,9 +2334,9 @@ checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] name = "either" -version = "1.13.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "encode_unicode" @@ -2312,15 +2388,15 @@ dependencies = [ [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "erased-serde" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24e2389d65ab4fab27dc2a5de7b191e1f6617d1f1c8855c0dc569c94a4cbb18d" +checksum = "e004d887f51fcb9fef17317a2f3525c887d8aa3f4f50fed920816a688284a5b7" dependencies = [ "serde", "typeid", @@ -2436,7 +2512,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78" dependencies = [ "cfg-if", - "rustix 1.0.2", + "rustix 1.0.3", "windows-sys 0.59.0", ] @@ -2494,7 +2570,7 @@ dependencies = [ "fig_request", "fig_settings", "fig_util", - "http 1.2.0", + "http 1.3.1", "regex", "serde", "serde_json", @@ -2551,7 +2627,7 @@ dependencies = [ "aws-smithy-runtime-api", "aws-smithy-types", "aws-types", - "http 1.2.0", + "http 1.3.1", "tracing", ] @@ -2591,7 +2667,7 @@ dependencies = [ "freedesktop-icons", "futures", "gtk", - "http 1.2.0", + "http 1.3.1", "image", "infer", "keyboard-types", @@ -2603,9 +2679,9 @@ dependencies = [ "nix 0.29.0", "notify", "objc", - "objc2", - "objc2-app-kit", - "objc2-foundation", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", "parking_lot", "paste", "percent-encoding", @@ -2713,9 +2789,9 @@ dependencies = [ "fig_proto", "fig_util", "macos-utils", - "objc2", - "objc2-app-kit", - "objc2-foundation", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", "objc2-input-method-kit", "plist", "serde", @@ -2773,7 +2849,7 @@ dependencies = [ "clap", "core-foundation 0.10.0", "dbus", - "dirs", + "dirs 5.0.1", "dispatch", "fig_os_shim", "fig_settings", @@ -2837,7 +2913,7 @@ name = "fig_os_shim" version = "1.7.1" dependencies = [ "cfg-if", - "dirs", + "dirs 5.0.1", "nix 0.29.0", "serde", "sysinfo 0.32.1", @@ -2898,7 +2974,7 @@ dependencies = [ "mockito", "reqwest", "reqwest_cookie_store", - "rustls 0.23.23", + "rustls 0.23.25", "rustls-native-certs 0.8.1", "rustls-pemfile 2.2.0", "serde", @@ -3004,7 +3080,7 @@ dependencies = [ "fig_os_shim", "fig_util", "hex", - "http 1.2.0", + "http 1.3.1", "http-body-util", "hyper 1.6.0", "hyper-util", @@ -3024,7 +3100,7 @@ dependencies = [ "cfg-if", "clap", "core-foundation 0.10.0", - "dirs", + "dirs 5.0.1", "fig_os_shim", "fig_test", "hex", @@ -3033,9 +3109,9 @@ dependencies = [ "libc", "macos-utils", "nix 0.29.0", - "objc2", - "objc2-app-kit", - "objc2-foundation", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", "paste", "rand 0.9.0", "regex", @@ -3163,6 +3239,12 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + [[package]] name = "flate2" version = "1.1.0" @@ -3202,9 +3284,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foldhash" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "foreign-types" @@ -3248,7 +3330,7 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8ef34245e0540c9a3ce7a28340b98d2c12b75da0d446da4e8224923fcaa0c16" dependencies = [ - "dirs", + "dirs 5.0.1", "once_cell", "rust-ini", "thiserror 1.0.69", @@ -3558,14 +3640,16 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" dependencies = [ "cfg-if", + "js-sys", "libc", - "wasi 0.13.3+wasi-0.2.2", - "windows-targets 0.52.6", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", + "wasm-bindgen", ] [[package]] @@ -3757,7 +3841,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.7.0", + "indexmap 2.8.0", "slab", "tokio", "tokio-util", @@ -3766,17 +3850,17 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" +checksum = "5017294ff4bb30944501348f6f8e42e6ad28f42c8bbef7a74029aff064a4e3c2" dependencies = [ "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "http 1.2.0", - "indexmap 2.7.0", + "http 1.3.1", + "indexmap 2.8.0", "slab", "tokio", "tokio-util", @@ -3785,9 +3869,9 @@ dependencies = [ [[package]] name = "half" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +checksum = "7db2ff139bba50379da6aa0766b52fdcb62cb5b263009b09ed58ba604e14bbd1" dependencies = [ "cfg-if", "crunchy", @@ -3866,6 +3950,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" +[[package]] +name = "hermit-abi" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbd780fe5cc30f81464441920d82ac8740e2e46b29a6fad543ddd075229ce37e" + [[package]] name = "hex" version = "0.4.3" @@ -3912,18 +4002,18 @@ checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", - "itoa 1.0.14", + "itoa 1.0.15", ] [[package]] name = "http" -version = "1.2.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" dependencies = [ "bytes", "fnv", - "itoa 1.0.14", + "itoa 1.0.15", ] [[package]] @@ -3944,7 +4034,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.2.0", + "http 1.3.1", ] [[package]] @@ -3955,16 +4045,16 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http 1.2.0", + "http 1.3.1", "http-body 1.0.1", "pin-project-lite", ] [[package]] name = "httparse" -version = "1.9.5" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "httpdate" @@ -3987,7 +4077,7 @@ dependencies = [ "http-body 0.4.6", "httparse", "httpdate", - "itoa 1.0.14", + "itoa 1.0.15", "pin-project-lite", "socket2", "tokio", @@ -4005,12 +4095,12 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.7", - "http 1.2.0", + "h2 0.4.8", + "http 1.3.1", "http-body 1.0.1", "httparse", "httpdate", - "itoa 1.0.14", + "itoa 1.0.15", "pin-project-lite", "smallvec", "tokio", @@ -4040,14 +4130,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" dependencies = [ "futures-util", - "http 1.2.0", + "http 1.3.1", "hyper 1.6.0", "hyper-util", - "rustls 0.23.23", + "rustls 0.23.25", "rustls-native-certs 0.8.1", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.1", + "tokio-rustls 0.26.2", "tower-service", "webpki-roots", ] @@ -4061,7 +4151,7 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.2.0", + "http 1.3.1", "http-body 1.0.1", "hyper 1.6.0", "pin-project-lite", @@ -4258,9 +4348,9 @@ dependencies = [ [[package]] name = "image-webp" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e031e8e3d94711a9ccb5d6ea357439ef3dcbed361798bd4071dc4d9793fbe22f" +checksum = "b77d01e822461baa8409e156015a1d91735549f0f2c17691bd2d996bef238f7f" dependencies = [ "byteorder-lite", "quick-error", @@ -4290,9 +4380,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" dependencies = [ "equivalent", "hashbrown 0.15.2", @@ -4373,9 +4463,9 @@ dependencies = [ [[package]] name = "inventory" -version = "0.3.17" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b31349d02fe60f80bbbab1a9402364cad7460626d6030494b08ac4a2075bf81" +checksum = "ab08d7cd2c5897f2c949e5383ea7c7db03fb19130ffcfbf7eda795137ae3cb83" dependencies = [ "rustversion", ] @@ -4391,19 +4481,19 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.10.1" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "is-terminal" -version = "0.4.13" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" dependencies = [ - "hermit-abi", + "hermit-abi 0.5.0", "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -4445,6 +4535,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "0.4.8" @@ -4453,9 +4552,9 @@ checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "itoa" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "javascriptcore-rs" @@ -4651,9 +4750,9 @@ dependencies = [ [[package]] name = "libmimalloc-sys" -version = "0.1.39" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23aa6811d3bd4deb8a84dde645f943476d13b248d818edcf8ce0b2f37f036b44" +checksum = "07d0e07885d6a754b9c7993f2625187ad694ee985d60f23355ff0e7077261502" dependencies = [ "cc", "libc", @@ -4709,15 +4808,15 @@ checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "linux-raw-sys" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9c683daf087dc577b7506e9695b3d556a9f3849903fa28186283afd6809e9" +checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" [[package]] name = "litemap" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" +checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" [[package]] name = "litrs" @@ -4738,9 +4837,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.22" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" [[package]] name = "loom" @@ -4804,7 +4903,7 @@ dependencies = [ "accessibility", "accessibility-sys", "appkit-nsworkspace-bindings", - "block2", + "block2 0.5.1", "cocoa", "core-foundation 0.10.0", "core-graphics", @@ -4814,9 +4913,9 @@ dependencies = [ "libc", "nix 0.29.0", "objc", - "objc2", - "objc2-app-kit", - "objc2-foundation", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", "tokio", "tracing", ] @@ -4875,6 +4974,20 @@ dependencies = [ "rayon", ] +[[package]] +name = "mcp_client" +version = "1.7.1" +dependencies = [ + "async-trait", + "nix 0.29.0", + "serde", + "serde_json", + "thiserror 2.0.12", + "tokio", + "tracing", + "uuid", +] + [[package]] name = "memchr" version = "2.7.4" @@ -4907,9 +5020,9 @@ dependencies = [ [[package]] name = "miette" -version = "7.4.0" +version = "7.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317f146e2eb7021892722af37cf1b971f0a70c8406f487e24952667616192c64" +checksum = "1a955165f87b37fd1862df2a59547ac542c77ef6d17c666f619d1ad22dd89484" dependencies = [ "cfg-if", "miette-derive", @@ -4925,9 +5038,9 @@ dependencies = [ [[package]] name = "miette-derive" -version = "7.4.0" +version = "7.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23c9b935fbe1d6cbd1dac857b54a688145e2d93f48db36010514d0f612d0ad67" +checksum = "bf45bf44ab49be92fd1227a3be6fc6f617f1a337c06af54981048574d8783147" dependencies = [ "proc-macro2", "quote", @@ -4936,9 +5049,9 @@ dependencies = [ [[package]] name = "mimalloc" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68914350ae34959d83f732418d51e2427a794055d0b9529f48259ac07af65633" +checksum = "99585191385958383e13f6b822e6b6d8d9cf928e7d286ceb092da92b43c87bc1" dependencies = [ "libmimalloc-sys", ] @@ -4996,7 +5109,7 @@ dependencies = [ "bytes", "colored", "futures-util", - "http 1.2.0", + "http 1.3.1", "http-body 1.0.1", "http-body-util", "hyper 1.6.0", @@ -5042,9 +5155,9 @@ dependencies = [ "dpi", "gtk", "keyboard-types", - "objc2", - "objc2-app-kit", - "objc2-foundation", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", "once_cell", "png", "thiserror 1.0.69", @@ -5239,7 +5352,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc7c92f190c97f79b4a332f5e81dcf68c8420af2045c936c9be0bc9de6f63b5" dependencies = [ - "proc-macro-crate 3.2.0", + "proc-macro-crate 3.3.0", "proc-macro2", "quote", "syn 1.0.109", @@ -5327,7 +5440,7 @@ version = "0.102.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b34402c223280f2a12b40562c92d5e39e66dbcf8e63d984b788758e67bfc1fa" dependencies = [ - "dirs", + "dirs 5.0.1", "omnipath", "pwd", "ref-cast", @@ -5342,11 +5455,11 @@ dependencies = [ "bytes", "chrono", "chrono-humanize", - "dirs", - "dirs-sys", + "dirs 5.0.1", + "dirs-sys 0.4.1", "fancy-regex", "heck 0.5.0", - "indexmap 2.7.0", + "indexmap 2.8.0", "log", "lru", "memchr", @@ -5438,7 +5551,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" dependencies = [ "arrayvec", - "itoa 1.0.14", + "itoa 1.0.15", ] [[package]] @@ -5485,7 +5598,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ - "proc-macro-crate 3.2.0", + "proc-macro-crate 3.3.0", "proc-macro2", "quote", "syn 2.0.100", @@ -5534,6 +5647,15 @@ dependencies = [ "objc2-encode", ] +[[package]] +name = "objc2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3531f65190d9cff863b77a99857e74c314dd16bf56c538c4b57c7cbc3f3a6e59" +dependencies = [ + "objc2-encode", +] + [[package]] name = "objc2-app-kit" version = "0.2.2" @@ -5541,15 +5663,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ "bitflags 2.9.0", - "block2", + "block2 0.5.1", "libc", - "objc2", + "objc2 0.5.2", "objc2-core-data", "objc2-core-image", - "objc2-foundation", + "objc2-foundation 0.2.2", "objc2-quartz-core", ] +[[package]] +name = "objc2-app-kit" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5906f93257178e2f7ae069efb89fbd6ee94f0592740b5f8a1512ca498814d0fb" +dependencies = [ + "bitflags 2.9.0", + "block2 0.6.0", + "objc2 0.6.0", + "objc2-core-foundation", + "objc2-foundation 0.3.0", +] + [[package]] name = "objc2-cloud-kit" version = "0.2.2" @@ -5557,10 +5692,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" dependencies = [ "bitflags 2.9.0", - "block2", - "objc2", + "block2 0.5.1", + "objc2 0.5.2", "objc2-core-location", - "objc2-foundation", + "objc2-foundation 0.2.2", ] [[package]] @@ -5569,9 +5704,9 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" dependencies = [ - "block2", - "objc2", - "objc2-foundation", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", ] [[package]] @@ -5581,9 +5716,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ "bitflags 2.9.0", - "block2", - "objc2", - "objc2-foundation", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daeaf60f25471d26948a1c2f840e3f7d86f4109e3af4e8e4b5cd70c39690d925" +dependencies = [ + "bitflags 2.9.0", + "objc2 0.6.0", +] + +[[package]] +name = "objc2-core-graphics" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dca602628b65356b6513290a21a6405b4d4027b8b250f0b98dddbb28b7de02" +dependencies = [ + "bitflags 2.9.0", + "objc2-core-foundation", ] [[package]] @@ -5592,9 +5747,9 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" dependencies = [ - "block2", - "objc2", - "objc2-foundation", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", "objc2-metal", ] @@ -5604,17 +5759,17 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" dependencies = [ - "block2", - "objc2", + "block2 0.5.1", + "objc2 0.5.2", "objc2-contacts", - "objc2-foundation", + "objc2-foundation 0.2.2", ] [[package]] name = "objc2-encode" -version = "4.0.3" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7891e71393cd1f227313c9379a26a584ff3d7e6e7159e988851f0934c993f0f8" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" [[package]] name = "objc2-foundation" @@ -5623,10 +5778,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ "bitflags 2.9.0", - "block2", - "dispatch", + "block2 0.5.1", "libc", - "objc2", + "objc2 0.5.2", +] + +[[package]] +name = "objc2-foundation" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a21c6c9014b82c39515db5b396f91645182611c97d24637cf56ac01e5f8d998" +dependencies = [ + "bitflags 2.9.0", + "block2 0.6.0", + "objc2 0.6.0", + "objc2-core-foundation", ] [[package]] @@ -5635,9 +5801,9 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12e306c83555cdab87755f31b45f8d9a657081edb15fc89c74a5bb4175ebd487" dependencies = [ - "objc2", - "objc2-app-kit", - "objc2-foundation", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", ] [[package]] @@ -5646,10 +5812,10 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" dependencies = [ - "block2", - "objc2", - "objc2-app-kit", - "objc2-foundation", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", ] [[package]] @@ -5659,9 +5825,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ "bitflags 2.9.0", - "block2", - "objc2", - "objc2-foundation", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", ] [[package]] @@ -5671,9 +5837,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ "bitflags 2.9.0", - "block2", - "objc2", - "objc2-foundation", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", "objc2-metal", ] @@ -5683,8 +5849,8 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc" dependencies = [ - "objc2", - "objc2-foundation", + "objc2 0.5.2", + "objc2-foundation 0.2.2", ] [[package]] @@ -5694,13 +5860,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" dependencies = [ "bitflags 2.9.0", - "block2", - "objc2", + "block2 0.5.1", + "objc2 0.5.2", "objc2-cloud-kit", "objc2-core-data", "objc2-core-image", "objc2-core-location", - "objc2-foundation", + "objc2-foundation 0.2.2", "objc2-link-presentation", "objc2-quartz-core", "objc2-symbols", @@ -5714,9 +5880,9 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" dependencies = [ - "block2", - "objc2", - "objc2-foundation", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", ] [[package]] @@ -5726,10 +5892,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" dependencies = [ "bitflags 2.9.0", - "block2", - "objc2", + "block2 0.5.1", + "objc2 0.5.2", "objc2-core-location", - "objc2-foundation", + "objc2-foundation 0.2.2", ] [[package]] @@ -5739,10 +5905,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68bc69301064cebefc6c4c90ce9cba69225239e4b8ff99d445a2b5563797da65" dependencies = [ "bitflags 2.9.0", - "block2", - "objc2", - "objc2-app-kit", - "objc2-foundation", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", ] [[package]] @@ -5762,9 +5928,9 @@ checksum = "80adb31078122c880307e9cdfd4e3361e6545c319f9b9dcafcb03acd3b51a575" [[package]] name = "once_cell" -version = "1.20.2" +version = "1.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc" [[package]] name = "onig" @@ -5790,15 +5956,15 @@ dependencies = [ [[package]] name = "oorandom" -version = "11.1.4" +version = "11.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" [[package]] name = "openssl-probe" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "option-ext" @@ -5847,9 +6013,9 @@ dependencies = [ [[package]] name = "outref" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4030760ffd992bef45b0ae3f10ce1aba99e33464c90d14dd7c039884963ddc7a" +checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" [[package]] name = "overload" @@ -5941,8 +6107,18 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ - "fixedbitset", - "indexmap 2.7.0", + "fixedbitset 0.4.2", + "indexmap 2.8.0", +] + +[[package]] +name = "petgraph" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" +dependencies = [ + "fixedbitset 0.5.7", + "indexmap 2.8.0", ] [[package]] @@ -6005,6 +6181,16 @@ dependencies = [ "rand 0.8.5", ] +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared 0.11.3", + "rand 0.8.5", +] + [[package]] name = "phf_macros" version = "0.8.0" @@ -6025,7 +6211,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" dependencies = [ - "siphasher", + "siphasher 0.3.11", ] [[package]] @@ -6034,7 +6220,16 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" dependencies = [ - "siphasher", + "siphasher 0.3.11", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher 1.0.1", ] [[package]] @@ -6082,9 +6277,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "plist" @@ -6093,7 +6288,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016" dependencies = [ "base64 0.22.1", - "indexmap 2.7.0", + "indexmap 2.8.0", "quick-xml 0.32.0", "serde", "time", @@ -6148,9 +6343,9 @@ checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" dependencies = [ "cfg-if", "concurrent-queue", - "hermit-abi", + "hermit-abi 0.4.0", "pin-project-lite", - "rustix 0.38.43", + "rustix 0.38.44", "tracing", "windows-sys 0.59.0", ] @@ -6163,9 +6358,9 @@ checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3" [[package]] name = "portable-atomic" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" +checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" [[package]] name = "portable-pty" @@ -6196,11 +6391,11 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy 0.7.35", + "zerocopy 0.8.24", ] [[package]] @@ -6251,9 +6446,9 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.30" +version = "0.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1ccf34da56fc294e7d4ccf69a85992b7dfb826b7cf57bac6a70bba3494cc08a" +checksum = "5316f57387668042f561aae71480de936257848f9c43ce528e311d89a07cadeb" dependencies = [ "proc-macro2", "syn 2.0.100", @@ -6280,11 +6475,11 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.2.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" dependencies = [ - "toml_edit 0.22.22", + "toml_edit 0.22.24", ] [[package]] @@ -6319,9 +6514,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.92" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" dependencies = [ "unicode-ident", ] @@ -6337,7 +6532,7 @@ dependencies = [ "flate2", "hex", "procfs-core", - "rustix 0.38.43", + "rustix 0.38.44", ] [[package]] @@ -6387,11 +6582,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" dependencies = [ "heck 0.5.0", - "itertools 0.13.0", + "itertools 0.14.0", "log", "multimap", "once_cell", - "petgraph", + "petgraph 0.7.1", "prettyplease", "prost", "prost-types", @@ -6407,7 +6602,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" dependencies = [ "anyhow", - "itertools 0.13.0", + "itertools 0.14.0", "proc-macro2", "quote", "syn 2.0.100", @@ -6543,11 +6738,12 @@ dependencies = [ "indoc", "insta", "macos-utils", + "mcp_client", "mimalloc", "nix 0.29.0", - "objc2", - "objc2-app-kit", - "objc2-foundation", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", "owo-colors 4.2.0", "parking_lot", "paste", @@ -6559,6 +6755,7 @@ dependencies = [ "serde", "serde_json", "shell-color", + "shellexpand", "shlex", "similar", "spinners", @@ -6580,7 +6777,7 @@ dependencies = [ "whoami", "winapi", "windows 0.58.0", - "winnow 0.6.22", + "winnow 0.6.26", ] [[package]] @@ -6619,43 +6816,45 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.36.2" +version = "0.37.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe" +checksum = "165859e9e55f79d67b96c5d96f4e88b6f2695a1972849c15a6a3f5c59fc2c003" dependencies = [ "memchr", ] [[package]] name = "quinn" -version = "0.11.6" +version = "0.11.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" +checksum = "c3bd15a6f2967aef83887dcb9fec0014580467e33720d073560cf015a5683012" dependencies = [ "bytes", + "cfg_aliases 0.2.1", "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash 2.1.0", - "rustls 0.23.23", + "rustc-hash 2.1.1", + "rustls 0.23.25", "socket2", "thiserror 2.0.12", "tokio", "tracing", + "web-time", ] [[package]] name = "quinn-proto" -version = "0.11.9" +version = "0.11.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" +checksum = "b820744eb4dc9b57a3398183639c511b5a26d2ed702cedd3febaa1393caa22cc" dependencies = [ "bytes", - "getrandom 0.2.15", - "rand 0.8.5", + "getrandom 0.3.2", + "rand 0.9.0", "ring", - "rustc-hash 2.1.0", - "rustls 0.23.23", + "rustc-hash 2.1.1", + "rustls 0.23.25", "rustls-pki-types", "slab", "thiserror 2.0.12", @@ -6666,9 +6865,9 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c40286217b4ba3a71d644d752e6a0b71f13f1b6a2c5311acfcbe0c2418ed904" +checksum = "e46f3055866785f6b92bc6164b76be02ca8f2eb4b002c0354b28cf4c119e5944" dependencies = [ "cfg_aliases 0.2.1", "libc", @@ -6687,6 +6886,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + [[package]] name = "r2d2" version = "0.8.10" @@ -6752,7 +6957,7 @@ checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.3", - "zerocopy 0.8.23", + "zerocopy 0.8.24", ] [[package]] @@ -6809,7 +7014,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.1", + "getrandom 0.3.2", ] [[package]] @@ -6908,9 +7113,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.8" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" +checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" dependencies = [ "bitflags 2.9.0", ] @@ -6926,6 +7131,17 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "redox_users" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" +dependencies = [ + "getrandom 0.2.15", + "libredox", + "thiserror 2.0.12", +] + [[package]] name = "ref-cast" version = "1.0.24" @@ -6998,9 +7214,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" -version = "0.12.14" +version = "0.12.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989e327e510263980e231de548a33e63d34962d29ae61b467389a1a09627a254" +checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" dependencies = [ "async-compression", "base64 0.22.1", @@ -7010,8 +7226,8 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2 0.4.7", - "http 1.2.0", + "h2 0.4.8", + "http 1.3.1", "http-body 1.0.1", "http-body-util", "hyper 1.6.0", @@ -7025,7 +7241,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.23", + "rustls 0.23.25", "rustls-native-certs 0.8.1", "rustls-pemfile 2.2.0", "rustls-pki-types", @@ -7034,7 +7250,7 @@ dependencies = [ "serde_urlencoded", "sync_wrapper", "tokio", - "tokio-rustls 0.26.1", + "tokio-rustls 0.26.2", "tokio-socks", "tokio-util", "tower", @@ -7061,19 +7277,19 @@ dependencies = [ [[package]] name = "rfd" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a24763657bff09769a8ccf12c8b8a50416fb035fe199263b4c5071e4e3f006f" +checksum = "80c844748fdc82aae252ee4594a89b6e7ebef1063de7951545564cbc4e57075d" dependencies = [ "ashpd", - "block2", - "core-foundation 0.10.0", - "core-foundation-sys", + "block2 0.6.0", + "dispatch2", "js-sys", "log", - "objc2", - "objc2-app-kit", - "objc2-foundation", + "objc2 0.6.0", + "objc2-app-kit 0.3.0", + "objc2-core-foundation", + "objc2-foundation 0.3.0", "pollster", "raw-window-handle", "urlencoding", @@ -7173,9 +7389,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc-hash" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] name = "rustc_version" @@ -7188,9 +7404,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.43" +version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ "bitflags 2.9.0", "errno", @@ -7201,14 +7417,14 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7178faa4b75a30e269c71e61c353ce2748cf3d76f0c44c393f4e60abf49b825" +checksum = "e56a18552996ac8d29ecc3b190b4fdbb2d91ca4ec396de7bbffaf43f3d637e96" dependencies = [ "bitflags 2.9.0", "errno", "libc", - "linux-raw-sys 0.9.2", + "linux-raw-sys 0.9.3", "windows-sys 0.59.0", ] @@ -7226,16 +7442,16 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.23" +version = "0.23.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47796c98c480fce5406ef69d1c76378375492c3b0a0de587be0c1d9feb12f395" +checksum = "822ee9188ac4ec04a2f0531e55d035fb2de73f18b41a63c70c2712503b6fb13c" dependencies = [ "aws-lc-rs", "log", "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.102.8", + "rustls-webpki 0.103.0", "subtle", "zeroize", ] @@ -7284,9 +7500,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" +checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" dependencies = [ "web-time", ] @@ -7303,9 +7519,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.102.8" +version = "0.103.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +checksum = "0aa4eeac2588ffff23e9d7a7e9b3f971c5fb5b7ebc9452745e0c232c64f83b2f" dependencies = [ "aws-lc-rs", "ring", @@ -7315,9 +7531,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" [[package]] name = "rustyline" @@ -7355,9 +7571,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "same-file" @@ -7515,8 +7731,8 @@ version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ - "indexmap 2.7.0", - "itoa 1.0.14", + "indexmap 2.8.0", + "itoa 1.0.15", "memchr", "ryu", "serde", @@ -7558,7 +7774,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", - "itoa 1.0.14", + "itoa 1.0.15", "ryu", "serde", ] @@ -7569,8 +7785,8 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.7.0", - "itoa 1.0.14", + "indexmap 2.8.0", + "itoa 1.0.15", "ryu", "serde", "unsafe-libyaml", @@ -7691,7 +7907,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da03fa3b94cc19e3ebfc88c4229c49d8f08cdbd1228870a45f0ffdf84988e14b" dependencies = [ - "dirs", + "dirs 5.0.1", ] [[package]] @@ -7757,6 +7973,12 @@ version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + [[package]] name = "slab" version = "0.4.9" @@ -7768,9 +7990,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.2" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" [[package]] name = "socket2" @@ -7842,37 +8064,36 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "string_cache" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +checksum = "938d512196766101d333398efde81bc1f37b00cb42c2f8350e5df639f040bbbe" dependencies = [ "new_debug_unreachable", - "once_cell", "parking_lot", - "phf_shared 0.10.0", + "phf_shared 0.11.3", "precomputed-hash", "serde", ] [[package]] name = "string_cache_codegen" -version = "0.5.2" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" +checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", + "phf_generator 0.11.3", + "phf_shared 0.11.3", "proc-macro2", "quote", ] [[package]] name = "strip-ansi-escapes" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55ff8ef943b384c414f54aefa961dd2bd853add74ec75e7ac74cf91dba62bcfa" +checksum = "2a8f8038e7e7969abb3f1b7c2a811225e9296da208539e0f79c5251d6cac0025" dependencies = [ - "vte 0.11.1", + "vte 0.14.1", ] [[package]] @@ -8162,15 +8383,14 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tempfile" -version = "3.18.0" +version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c317e0a526ee6120d8dabad239c8dadca62b24b6f168914bbbc8e2fb1f0e567" +checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" dependencies = [ - "cfg-if", "fastrand", - "getrandom 0.3.1", + "getrandom 0.3.2", "once_cell", - "rustix 1.0.2", + "rustix 1.0.3", "windows-sys 0.59.0", ] @@ -8187,11 +8407,11 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5352447f921fda68cf61b4101566c0bdb5104eff6804d0678e5227580ab6a4e9" +checksum = "45c6481c4829e4cc63825e62c49186a34538b7b2750b73b266581ffb612fb5ed" dependencies = [ - "rustix 0.38.43", + "rustix 1.0.3", "windows-sys 0.59.0", ] @@ -8222,9 +8442,9 @@ dependencies = [ [[package]] name = "test-log-macros" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5999e24eaa32083191ba4e425deb75cdf25efefabe5aaccb7446dd0d4122a3f5" +checksum = "888d0c3c6db53c0fdab160d2ed5e12ba745383d3e85813f2ea0f2b1475ab553f" dependencies = [ "proc-macro2", "quote", @@ -8233,12 +8453,12 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.16.1" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" +checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" dependencies = [ "unicode-linebreak", - "unicode-width 0.1.14", + "unicode-width 0.2.0", ] [[package]] @@ -8310,12 +8530,12 @@ dependencies = [ [[package]] name = "time" -version = "0.3.39" +version = "0.3.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dad298b01a40a23aac4580b67e3dbedb7cc8402f3592d7f49469de2ea4aecdd8" +checksum = "9d9c75b47bdff86fa3334a3db91356b8d7d86a9b839dab7d0bdc5c3d3a077618" dependencies = [ "deranged", - "itoa 1.0.14", + "itoa 1.0.15", "libc", "num-conv", "num_threads", @@ -8327,15 +8547,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "765c97a5b985b7c11d7bc27fa927dc4fe6af3a6dfb021d28deb60d3bf51e76ef" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" [[package]] name = "time-macros" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8093bc3e81c3bc5f7879de09619d06c9a5a5e45ca44dfeeb7225bae38005c5c" +checksum = "29aa485584182073ed57fd5004aa09c371f021325014694e432313345865fd04" dependencies = [ "num-conv", "time-core", @@ -8372,9 +8592,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" dependencies = [ "tinyvec_macros", ] @@ -8387,9 +8607,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.44.0" +version = "1.44.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9975ea0f48b5aa3972bf2d888c238182458437cc2a19374b81b25cdf1023fb3a" +checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a" dependencies = [ "backtrace", "bytes", @@ -8427,11 +8647,11 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.1" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" +checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" dependencies = [ - "rustls 0.23.23", + "rustls 0.23.25", "tokio", ] @@ -8461,9 +8681,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.13" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" +checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034" dependencies = [ "bytes", "futures-core", @@ -8488,14 +8708,14 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.22", + "toml_edit 0.22.24", ] [[package]] @@ -8513,7 +8733,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.7.0", + "indexmap 2.8.0", "toml_datetime", "winnow 0.5.40", ] @@ -8524,22 +8744,22 @@ version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" dependencies = [ - "indexmap 2.7.0", + "indexmap 2.8.0", "toml_datetime", "winnow 0.5.40", ] [[package]] name = "toml_edit" -version = "0.22.22" +version = "0.22.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" dependencies = [ - "indexmap 2.7.0", + "indexmap 2.8.0", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.22", + "winnow 0.7.4", ] [[package]] @@ -8691,21 +8911,22 @@ dependencies = [ [[package]] name = "tray-icon" -version = "0.19.2" +version = "0.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d48a05076dd272615d03033bf04f480199f7d1b66a8ac64d75c625fc4a70c06b" +checksum = "eadd75f5002e2513eaa19b2365f533090cc3e93abd38788452d9ea85cff7b48a" dependencies = [ - "core-graphics", "crossbeam-channel", - "dirs", + "dirs 6.0.0", "libappindicator", "muda", - "objc2", - "objc2-app-kit", - "objc2-foundation", + "objc2 0.6.0", + "objc2-app-kit 0.3.0", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation 0.3.0", "once_cell", "png", - "thiserror 1.0.69", + "thiserror 2.0.12", "windows-sys 0.59.0", ] @@ -8719,7 +8940,7 @@ dependencies = [ "memchr", "nom", "once_cell", - "petgraph", + "petgraph 0.6.5", ] [[package]] @@ -8736,7 +8957,7 @@ checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13" dependencies = [ "bytes", "data-encoding", - "http 1.2.0", + "http 1.3.1", "httparse", "log", "rand 0.9.0", @@ -8747,21 +8968,21 @@ dependencies = [ [[package]] name = "typeid" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e13db2e0ccd5e14a544e8a246ba2312cd25223f616442d7f2cb0e3db614236e" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" [[package]] name = "typenum" -version = "1.17.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] name = "typetag" -version = "0.2.19" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "044fc3365ddd307c297fe0fe7b2e70588cdab4d0f62dc52055ca0d11b174cf0e" +checksum = "73f22b40dd7bfe8c14230cf9702081366421890435b2d625fa92b4acc4c3de6f" dependencies = [ "erased-serde", "inventory", @@ -8772,9 +8993,9 @@ dependencies = [ [[package]] name = "typetag-impl" -version = "0.2.19" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9d30226ac9cbd2d1ff775f74e8febdab985dab14fb14aa2582c29a92d5555dc" +checksum = "35f5380909ffc31b4de4f4bdf96b877175a016aa2ca98cee39fcfd8c4d53d952" dependencies = [ "proc-macro2", "quote", @@ -8800,9 +9021,9 @@ checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" [[package]] name = "unicode-ident" -version = "1.0.14" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-linebreak" @@ -8884,11 +9105,11 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.15.1" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0f540e3240398cce6128b64ba83fdbdd86129c16a3aa1a3a252efd66eb3d587" +checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" dependencies = [ - "getrandom 0.3.1", + "getrandom 0.3.2", "rand 0.9.0", "serde", ] @@ -8906,9 +9127,9 @@ dependencies = [ [[package]] name = "valuable" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "vcpkg" @@ -8946,12 +9167,11 @@ dependencies = [ [[package]] name = "vte" -version = "0.11.1" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5022b5fbf9407086c180e9557be968742d839e68346af7792b8592489732197" +checksum = "231fdcd7ef3037e8330d8e17e61011a2c244126acc0a982f4040ac3f9f0bc077" dependencies = [ - "utf8parse", - "vte_generate_state_changes", + "memchr", ] [[package]] @@ -8964,21 +9184,11 @@ dependencies = [ "memchr", ] -[[package]] -name = "vte_generate_state_changes" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e369bee1b05d510a7b4ed645f5faa90619e05437111783ea5848f28d97d3c2e" -dependencies = [ - "proc-macro2", - "quote", -] - [[package]] name = "wait-timeout" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" dependencies = [ "libc", ] @@ -9016,9 +9226,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasi" -version = "0.13.3+wasi-0.2.2" +version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" dependencies = [ "wit-bindgen-rt", ] @@ -9102,26 +9312,25 @@ dependencies = [ [[package]] name = "wayland-backend" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "056535ced7a150d45159d3a8dc30f91a2e2d588ca0b23f70e56033622b8016f6" +checksum = "b7208998eaa3870dad37ec8836979581506e0c5c64c20c9e79e9d2a10d6f47bf" dependencies = [ "cc", "downcast-rs", - "rustix 0.38.43", - "scoped-tls", + "rustix 0.38.44", "smallvec", "wayland-sys", ] [[package]] name = "wayland-client" -version = "0.31.7" +version = "0.31.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66249d3fc69f76fd74c82cc319300faa554e9d865dab1f7cd66cc20db10b280" +checksum = "c2120de3d33638aaef5b9f4472bff75f07c56379cf76ea320bd3a3d65ecaf73f" dependencies = [ "bitflags 2.9.0", - "rustix 0.38.43", + "rustix 0.38.44", "wayland-backend", "wayland-scanner", ] @@ -9138,18 +9347,6 @@ dependencies = [ "wayland-scanner", ] -[[package]] -name = "wayland-protocols" -version = "0.32.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd0ade57c4e6e9a8952741325c30bf82f4246885dca8bf561898b86d0c1f58e" -dependencies = [ - "bitflags 2.9.0", - "wayland-backend", - "wayland-client", - "wayland-scanner", -] - [[package]] name = "wayland-protocols-wlr" version = "0.2.0" @@ -9159,29 +9356,27 @@ dependencies = [ "bitflags 2.9.0", "wayland-backend", "wayland-client", - "wayland-protocols 0.31.2", + "wayland-protocols", "wayland-scanner", ] [[package]] name = "wayland-scanner" -version = "0.31.5" +version = "0.31.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597f2001b2e5fc1121e3d5b9791d3e78f05ba6bfa4641053846248e3a13661c3" +checksum = "896fdafd5d28145fce7958917d69f2fd44469b1d4e861cb5961bcbeebc6d1484" dependencies = [ "proc-macro2", - "quick-xml 0.36.2", + "quick-xml 0.37.2", "quote", ] [[package]] name = "wayland-sys" -version = "0.31.5" +version = "0.31.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efa8ac0d8e8ed3e3b5c9fc92c7881406a268e11555abe36493efabe649a29e09" +checksum = "dbcebb399c77d5aa9fa5db874806ee7b4eba4e73650948e8f93963f128896615" dependencies = [ - "dlib", - "log", "pkg-config", ] @@ -9309,7 +9504,7 @@ dependencies = [ "either", "home", "once_cell", - "rustix 0.38.43", + "rustix 0.38.44", ] [[package]] @@ -9320,7 +9515,7 @@ checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f" dependencies = [ "either", "home", - "rustix 0.38.43", + "rustix 0.38.44", "winsafe", ] @@ -9510,9 +9705,9 @@ dependencies = [ [[package]] name = "windows-link" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" [[package]] name = "windows-registry" @@ -9520,7 +9715,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" dependencies = [ - "windows-result 0.3.1", + "windows-result 0.3.2", "windows-strings 0.3.1", "windows-targets 0.53.0", ] @@ -9545,9 +9740,9 @@ dependencies = [ [[package]] name = "windows-result" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06374efe858fab7e4f881500e6e86ec8bc28f9462c47e5a9941a0142ad86b189" +checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" dependencies = [ "windows-link", ] @@ -9671,11 +9866,11 @@ dependencies = [ [[package]] name = "windows-version" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c12476c23a74725c539b24eae8bfc0dac4029c39cdb561d9f23616accd4ae26d" +checksum = "e04a5c6627e310a23ad2358483286c7df260c964eb2d003d8efd6d0f4e79265c" dependencies = [ - "windows-targets 0.53.0", + "windows-link", ] [[package]] @@ -9869,9 +10064,18 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.22" +version = "0.6.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39281189af81c07ec09db316b302a3e67bf9bd7cbf6c820b50e35fee9c2fa980" +checksum = "1e90edd2ac1aa278a5c4599b1d89cf03074b610800f866d4026dc199d7929a28" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36" dependencies = [ "memchr", ] @@ -9903,9 +10107,9 @@ checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" [[package]] name = "wit-bindgen-rt" -version = "0.33.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ "bitflags 2.9.0", ] @@ -9926,7 +10130,7 @@ dependencies = [ "tree_magic_mini", "wayland-backend", "wayland-client", - "wayland-protocols 0.31.2", + "wayland-protocols", "wayland-protocols-wlr", ] @@ -9949,7 +10153,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2e33c08b174442ff80d5c791020696f9f8b4e4a87b8cfc7494aad6167ec44e1" dependencies = [ "base64 0.22.1", - "block2", + "block2 0.5.1", "cookie", "crossbeam-channel", "dpi", @@ -9957,15 +10161,15 @@ dependencies = [ "gdkx11", "gtk", "html5ever", - "http 1.2.0", + "http 1.3.1", "javascriptcore-rs", "jni", "kuchikiki", "libc", "ndk", - "objc2", - "objc2-app-kit", - "objc2-foundation", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", "objc2-ui-kit", "objc2-web-kit", "once_cell", @@ -10013,7 +10217,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12" dependencies = [ "gethostname", - "rustix 0.38.43", + "rustix 0.38.44", "x11rb-protocol", ] @@ -10025,13 +10229,12 @@ checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" [[package]] name = "xattr" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e105d177a3871454f754b33bb0ee637ecaaac997446375fd3e5d43a2ed00c909" +checksum = "0d65cbf2f12c15564212d48f4e3dfb87923d25d611f2aed18f4cb23f0413d89e" dependencies = [ "libc", - "linux-raw-sys 0.4.15", - "rustix 0.38.43", + "rustix 1.0.3", ] [[package]] @@ -10142,9 +10345,9 @@ dependencies = [ [[package]] name = "zbus" -version = "5.2.0" +version = "5.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb67eadba43784b6fb14857eba0d8fc518686d3ee537066eb6086dc318e2c8a1" +checksum = "59c333f648ea1b647bc95dc1d34807c8e25ed7a6feff3394034dc4776054b236" dependencies = [ "async-broadcast", "async-executor", @@ -10159,7 +10362,7 @@ dependencies = [ "enumflags2", "event-listener", "futures-core", - "futures-util", + "futures-lite", "hex", "nix 0.29.0", "ordered-stream", @@ -10169,11 +10372,11 @@ dependencies = [ "tracing", "uds_windows", "windows-sys 0.59.0", - "winnow 0.6.22", + "winnow 0.7.4", "xdg-home", - "zbus_macros 5.2.0", - "zbus_names 4.1.0", - "zvariant 5.1.0", + "zbus_macros 5.5.0", + "zbus_names 4.2.0", + "zvariant 5.4.0", ] [[package]] @@ -10182,7 +10385,7 @@ version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "267db9407081e90bbfa46d841d3cbc60f59c0351838c4bc65199ecd79ab1983e" dependencies = [ - "proc-macro-crate 3.2.0", + "proc-macro-crate 3.3.0", "proc-macro2", "quote", "syn 2.0.100", @@ -10191,17 +10394,17 @@ dependencies = [ [[package]] name = "zbus_macros" -version = "5.2.0" +version = "5.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d49ebc960ceb660f2abe40a5904da975de6986f2af0d7884b39eec6528c57" +checksum = "f325ad10eb0d0a3eb060203494c3b7ec3162a01a59db75d2deee100339709fc0" dependencies = [ - "proc-macro-crate 3.2.0", + "proc-macro-crate 3.3.0", "proc-macro2", "quote", "syn 2.0.100", - "zbus_names 4.1.0", - "zvariant 5.1.0", - "zvariant_utils 3.0.2", + "zbus_names 4.2.0", + "zvariant 5.4.0", + "zvariant_utils 3.2.0", ] [[package]] @@ -10226,14 +10429,14 @@ dependencies = [ [[package]] name = "zbus_names" -version = "4.1.0" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "856b7a38811f71846fd47856ceee8bccaec8399ff53fb370247e66081ace647b" +checksum = "7be68e64bf6ce8db94f63e72f0c7eb9a60d733f7e0499e628dfab0f84d6bcb97" dependencies = [ "serde", "static_assertions", - "winnow 0.6.22", - "zvariant 5.1.0", + "winnow 0.7.4", + "zvariant 5.4.0", ] [[package]] @@ -10255,17 +10458,16 @@ version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ - "byteorder", "zerocopy-derive 0.7.35", ] [[package]] name = "zerocopy" -version = "0.8.23" +version = "0.8.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6" +checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" dependencies = [ - "zerocopy-derive 0.8.23", + "zerocopy-derive 0.8.24", ] [[package]] @@ -10281,9 +10483,9 @@ dependencies = [ [[package]] name = "zerocopy-derive" -version = "0.8.23" +version = "0.8.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154" +checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" dependencies = [ "proc-macro2", "quote", @@ -10292,18 +10494,18 @@ dependencies = [ [[package]] name = "zerofrom" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", @@ -10350,18 +10552,18 @@ dependencies = [ [[package]] name = "zstd-safe" -version = "7.2.1" +version = "7.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" dependencies = [ "zstd-sys", ] [[package]] name = "zstd-sys" -version = "2.0.13+zstd.1.5.6" +version = "2.0.15+zstd.1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" +checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237" dependencies = [ "cc", "pkg-config", @@ -10411,18 +10613,18 @@ dependencies = [ [[package]] name = "zvariant" -version = "5.1.0" +version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1200ee6ac32f1e5a312e455a949a4794855515d34f9909f4a3e082d14e1a56f" +checksum = "b2df9ee044893fcffbdc25de30546edef3e32341466811ca18421e3cd6c5a3ac" dependencies = [ "endi", "enumflags2", "serde", "static_assertions", "url", - "winnow 0.6.22", - "zvariant_derive 5.1.0", - "zvariant_utils 3.0.2", + "winnow 0.7.4", + "zvariant_derive 5.4.0", + "zvariant_utils 3.2.0", ] [[package]] @@ -10431,7 +10633,7 @@ version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73e2ba546bda683a90652bac4a279bc146adad1386f25379cf73200d2002c449" dependencies = [ - "proc-macro-crate 3.2.0", + "proc-macro-crate 3.3.0", "proc-macro2", "quote", "syn 2.0.100", @@ -10440,15 +10642,15 @@ dependencies = [ [[package]] name = "zvariant_derive" -version = "5.1.0" +version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "687e3b97fae6c9104fbbd36c73d27d149abf04fb874e2efbd84838763daa8916" +checksum = "74170caa85b8b84cc4935f2d56a57c7a15ea6185ccdd7eadb57e6edd90f94b2f" dependencies = [ - "proc-macro-crate 3.2.0", + "proc-macro-crate 3.3.0", "proc-macro2", "quote", "syn 2.0.100", - "zvariant_utils 3.0.2", + "zvariant_utils 3.2.0", ] [[package]] @@ -10464,14 +10666,14 @@ dependencies = [ [[package]] name = "zvariant_utils" -version = "3.0.2" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20d1d011a38f12360e5fcccceeff5e2c42a8eb7f27f0dcba97a0862ede05c9c6" +checksum = "e16edfee43e5d7b553b77872d99bc36afdda75c223ca7ad5e3fbecd82ca5fc34" dependencies = [ "proc-macro2", "quote", "serde", "static_assertions", "syn 2.0.100", - "winnow 0.6.22", + "winnow 0.7.4", ] diff --git a/Cargo.toml b/Cargo.toml index 370751f83..6920b61be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -86,6 +86,7 @@ indicatif = "0.17.11" indoc = "2.0.6" insta = "1.42.2" libc = "0.2.171" +mcp_client = { path = "crates/mcp_client" } mimalloc = "0.1.43" nix = { version = "0.29.0", features = [ "feature", @@ -123,6 +124,7 @@ reqwest = { version = "0.12.14", default-features = false, features = [ ] } ring = "0.17.14" rusqlite = { version = "0.32.1", features = ["bundled", "serde_json"] } +shellexpand = "3.0.0" shell-color = { path = "crates/shell-color" } semver = { version = "1.0.26", features = ["serde"] } serde = { version = "1.0.219", features = ["derive", "rc"] } diff --git a/crates/fig_auth/src/builder_id.rs b/crates/fig_auth/src/builder_id.rs index 2266c56d2..a84f2c0ea 100644 --- a/crates/fig_auth/src/builder_id.rs +++ b/crates/fig_auth/src/builder_id.rs @@ -95,7 +95,7 @@ pub(crate) fn oidc_url(region: &Region) -> String { pub(crate) fn client(region: Region) -> Client { let retry_config = RetryConfig::standard().with_max_attempts(3); let sdk_config = aws_types::SdkConfig::builder() - .behavior_version(BehaviorVersion::v2024_03_28()) + .behavior_version(BehaviorVersion::v2025_01_17()) .endpoint_url(oidc_url(®ion)) .region(region) .retry_config(retry_config) diff --git a/crates/fig_aws_common/src/lib.rs b/crates/fig_aws_common/src/lib.rs index 3795f1cfc..0e3d67f2f 100644 --- a/crates/fig_aws_common/src/lib.rs +++ b/crates/fig_aws_common/src/lib.rs @@ -16,7 +16,7 @@ pub fn app_name() -> AppName { } pub fn behavior_version() -> BehaviorVersion { - BehaviorVersion::v2024_03_28() + BehaviorVersion::v2025_01_17() } #[cfg(test)] diff --git a/crates/fig_desktop/Cargo.toml b/crates/fig_desktop/Cargo.toml index e5f2a6d64..c2471b3db 100644 --- a/crates/fig_desktop/Cargo.toml +++ b/crates/fig_desktop/Cargo.toml @@ -75,7 +75,7 @@ rfd = "0.15.1" semver.workspace = true serde.workspace = true serde_json.workspace = true -shellexpand = "3.0.0" +shellexpand.workspace = true sysinfo.workspace = true tao = { version = "0.31.1", features = ["serde"] } tempfile.workspace = true diff --git a/crates/fig_desktop_api/Cargo.toml b/crates/fig_desktop_api/Cargo.toml index d414b0d3a..672cc8e75 100644 --- a/crates/fig_desktop_api/Cargo.toml +++ b/crates/fig_desktop_api/Cargo.toml @@ -30,7 +30,7 @@ fig_util.workspace = true fnv = "1.0.7" serde.workspace = true serde_json.workspace = true -shellexpand = "3.0.0" +shellexpand.workspace = true thiserror.workspace = true tokio.workspace = true tracing.workspace = true diff --git a/crates/fig_telemetry/src/cognito.rs b/crates/fig_telemetry/src/cognito.rs index 4c26c0de5..033936c47 100644 --- a/crates/fig_telemetry/src/cognito.rs +++ b/crates/fig_telemetry/src/cognito.rs @@ -28,7 +28,7 @@ pub(crate) async fn get_cognito_credentials_send( telemetry_stage: &TelemetryStage, ) -> Result { let conf = aws_sdk_cognitoidentity::Config::builder() - .behavior_version(BehaviorVersion::v2024_03_28()) + .behavior_version(BehaviorVersion::v2025_01_17()) .region(telemetry_stage.region.clone()) .app_name(app_name()) .build(); diff --git a/crates/fig_telemetry/src/lib.rs b/crates/fig_telemetry/src/lib.rs index d98e37887..eac4b78f3 100644 --- a/crates/fig_telemetry/src/lib.rs +++ b/crates/fig_telemetry/src/lib.rs @@ -205,7 +205,7 @@ impl Client { let client_id = util::get_client_id(); let toolkit_telemetry_client = Some(amzn_toolkit_telemetry::Client::from_conf( Config::builder() - .behavior_version(BehaviorVersion::v2024_03_28()) + .behavior_version(BehaviorVersion::v2025_01_17()) .endpoint_resolver(StaticEndpoint(telemetry_stage.endpoint)) .app_name(app_name()) .region(telemetry_stage.region.clone()) diff --git a/crates/figterm/Cargo.toml b/crates/figterm/Cargo.toml index 99b0794be..2bf739a9a 100644 --- a/crates/figterm/Cargo.toml +++ b/crates/figterm/Cargo.toml @@ -56,7 +56,7 @@ serde.workspace = true serde_json.workspace = true shell-color.workspace = true shell-words = "1.1" -shellexpand = "3.1.0" +shellexpand.workspace = true shlex.workspace = true sysinfo.workspace = true time.workspace = true diff --git a/crates/mcp_client/Cargo.toml b/crates/mcp_client/Cargo.toml new file mode 100644 index 000000000..a95692d10 --- /dev/null +++ b/crates/mcp_client/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "mcp_client" +authors.workspace = true +edition.workspace = true +homepage.workspace = true +publish.workspace = true +version.workspace = true +license.workspace = true + +[lints] +workspace = true + +[features] +default = [] + +[[bin]] +name = "test_mcp_server" +path = "test_mcp_server/test_server.rs" +test = true +doc = false + +[dependencies] +tokio.workspace = true +serde.workspace = true +serde_json.workspace = true +async-trait.workspace = true +tracing.workspace = true +thiserror.workspace = true +uuid.workspace = true +nix.workspace = true diff --git a/crates/mcp_client/src/client.rs b/crates/mcp_client/src/client.rs new file mode 100644 index 000000000..e247eb097 --- /dev/null +++ b/crates/mcp_client/src/client.rs @@ -0,0 +1,492 @@ +use std::process::Stdio; +use std::sync::Arc; +use std::sync::atomic::{ + AtomicU64, + Ordering, +}; +use std::time::Duration; + +use nix::sys::signal::Signal; +use nix::unistd::Pid; +use serde::Deserialize; +use thiserror::Error; +use tokio::time; + +use crate::transport::base_protocol::{ + JsonRpcMessage, + JsonRpcNotification, + JsonRpcRequest, + JsonRpcVersion, +}; +use crate::transport::stdio::JsonRpcStdioTransport; +use crate::transport::{ + self, + Transport, + TransportError, +}; +use crate::{ + PaginationSupportedOps, + PromptsListResult, + ResourceTemplatesListResult, + ResourcesListResult, + ToolsListResult, +}; + +pub type ServerCapabilities = serde_json::Value; +pub type StdioTransport = JsonRpcStdioTransport; + +#[derive(Debug, Deserialize)] +pub struct ClientConfig { + pub server_name: String, + pub bin_path: String, + pub args: Vec, + pub timeout: u64, + pub init_params: serde_json::Value, +} + +#[derive(Debug, Error)] +pub enum ClientError { + #[error(transparent)] + TransportError(#[from] TransportError), + #[error(transparent)] + Io(#[from] std::io::Error), + #[error(transparent)] + Serialization(#[from] serde_json::Error), + #[error(transparent)] + RuntimeError(#[from] tokio::time::error::Elapsed), + #[error("Unexpected msg type encountered")] + UnexpectedMsgType, + #[error("{0}")] + NegotiationError(String), + #[error("Failed to obtain process id")] + MissingProcessId, + #[error("Invalid path received")] + InvalidPath, + #[error("{0}")] + ProcessKillError(String), +} + +#[derive(Debug)] +pub struct Client { + server_name: String, + transport: Arc, + timeout: u64, + server_process_id: Pid, + init_params: serde_json::Value, + current_id: AtomicU64, +} + +impl Client { + pub fn from_config(config: ClientConfig) -> Result { + let ClientConfig { + server_name, + bin_path, + args, + timeout, + init_params, + } = config; + let child = tokio::process::Command::new(bin_path) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) + .args(args) + .spawn()?; + let server_process_id = child.id().ok_or(ClientError::MissingProcessId)?; + #[allow(clippy::map_err_ignore)] + let server_process_id = Pid::from_raw( + server_process_id + .try_into() + .map_err(|_| ClientError::MissingProcessId)?, + ); + let transport = Arc::new(transport::stdio::JsonRpcStdioTransport::client(child)?); + Ok(Self { + server_name, + transport, + timeout, + server_process_id, + init_params, + current_id: AtomicU64::new(0), + }) + } +} + +impl Drop for Client +where + T: Transport, +{ + fn drop(&mut self) { + let _ = nix::sys::signal::kill(self.server_process_id, Signal::SIGTERM); + } +} + +impl Client +where + T: Transport, +{ + /// Exchange of information specified as per https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/lifecycle/#initialization + /// + /// Also done is the spawn of a background task that constantly listens for incoming messages + /// from the server. + pub async fn init(&self) -> Result { + let transport_ref = self.transport.clone(); + let server_name = self.server_name.clone(); + + tokio::spawn(async move { + loop { + match transport_ref.monitor().await { + Ok(msg) => { + match msg { + JsonRpcMessage::Request(_req) => {}, + JsonRpcMessage::Notification(_notif) => {}, + JsonRpcMessage::Response(_resp) => { /* noop since direct response is handled inside the request api */ + }, + } + }, + Err(e) => { + tracing::error!("Background listening thread for client {}: {:?}", server_name, e); + }, + } + } + }); + + let server_capabilities = self.request("initialize", Some(self.init_params.clone())).await?; + if let Err(e) = examine_server_capabilities(&server_capabilities) { + let _ = nix::sys::signal::kill(self.server_process_id, Signal::SIGTERM); + return Err(ClientError::NegotiationError(format!( + "Client {} has failed to negotiate server capabilities with server: {:?}", + self.server_name, e + ))); + } + self.notify("initialized", None).await?; + + Ok(server_capabilities) + } + + /// Sends a request to the server associated. + /// This call will yield until a response is received. + pub async fn request( + &self, + method: &str, + params: Option, + ) -> Result { + let request = JsonRpcRequest { + jsonrpc: JsonRpcVersion::default(), + id: self.get_id(), + method: method.to_owned(), + params, + }; + let msg = JsonRpcMessage::Request(request); + time::timeout(Duration::from_secs(self.timeout), self.transport.send(&msg)).await??; + let resp = time::timeout(Duration::from_secs(self.timeout), self.transport.listen()).await??; + let JsonRpcMessage::Response(mut resp) = resp else { + return Err(ClientError::UnexpectedMsgType); + }; + // Pagination support: https://spec.modelcontextprotocol.io/specification/2024-11-05/server/utilities/pagination/#pagination-model + let mut next_cursor = resp.result.as_ref().and_then(|v| v.get("nextCursor")); + if next_cursor.is_some() { + let mut current_resp = resp.clone(); + let mut results = Vec::::new(); + let pagination_supported_ops = { + let maybe_pagination_supported_op: Result = method.try_into(); + maybe_pagination_supported_op.ok() + }; + if let Some(ops) = pagination_supported_ops { + loop { + let result = current_resp.result.as_ref().cloned().unwrap(); + let mut list: Vec = match ops { + PaginationSupportedOps::ResourcesList => { + let ResourcesListResult { resources: list, .. } = + serde_json::from_value::(result) + .map_err(ClientError::Serialization)?; + list + }, + PaginationSupportedOps::ResourceTemplatesList => { + let ResourceTemplatesListResult { + resource_templates: list, + .. + } = serde_json::from_value::(result) + .map_err(ClientError::Serialization)?; + list + }, + PaginationSupportedOps::PromptsList => { + let PromptsListResult { prompts: list, .. } = + serde_json::from_value::(result) + .map_err(ClientError::Serialization)?; + list + }, + PaginationSupportedOps::ToolsList => { + let ToolsListResult { tools: list, .. } = serde_json::from_value::(result) + .map_err(ClientError::Serialization)?; + list + }, + }; + results.append(&mut list); + if next_cursor.is_none() { + break; + } + let next_request = JsonRpcRequest { + jsonrpc: JsonRpcVersion::default(), + id: self.get_id(), + method: method.to_owned(), + params: Some(serde_json::json!({ + "cursor": next_cursor, + })), + }; + let msg = JsonRpcMessage::Request(next_request); + time::timeout(Duration::from_secs(self.timeout), self.transport.send(&msg)).await??; + let resp = time::timeout(Duration::from_secs(self.timeout), self.transport.listen()).await??; + let JsonRpcMessage::Response(resp) = resp else { + return Err(ClientError::UnexpectedMsgType); + }; + current_resp = resp; + next_cursor = current_resp.result.as_ref().and_then(|v| v.get("nextCursor")); + } + resp.result = Some({ + let mut map = serde_json::Map::new(); + map.insert(ops.as_key().to_owned(), serde_json::to_value(results)?); + serde_json::to_value(map)? + }); + } + } + Ok(serde_json::to_value(resp)?) + } + + /// Sends a notification to the server associated. + /// Notifications are requests that expect no responses. + pub async fn notify(&self, method: &str, params: Option) -> Result<(), ClientError> { + let notification = JsonRpcNotification { + jsonrpc: JsonRpcVersion::default(), + method: format!("notifications/{}", method), + params, + }; + let msg = JsonRpcMessage::Notification(notification); + Ok(time::timeout(Duration::from_secs(self.timeout), self.transport.send(&msg)).await??) + } + + fn get_id(&self) -> u64 { + self.current_id.fetch_add(1, Ordering::SeqCst) + } +} + +fn examine_server_capabilities(ser_cap: &serde_json::Value) -> Result<(), ClientError> { + // Check the jrpc version. + // Currently we are only proceeding if the versions are EXACTLY the same. + let jrpc_version = ser_cap + .get("jsonrpc") + .map(|v| { + v.to_string() + .trim_matches('"') + .replace("\\\"", "\"") + .split(".") + .map(|n| n.parse::()) + .collect::>>() + }) + .ok_or(ClientError::NegotiationError("Missing jsonrpc from server".to_owned()))?; + let client_jrpc_version = JsonRpcVersion::default().as_u32_vec(); + for (sv, cv) in jrpc_version.iter().zip(client_jrpc_version.iter()) { + let sv = sv + .as_ref() + .map_err(|e| ClientError::NegotiationError(format!("Failed to parse server jrpc version: {:?}", e)))?; + if sv != cv { + return Err(ClientError::NegotiationError( + "Incompatible jrpc version between server and client".to_owned(), + )); + } + } + Ok(()) +} + +#[cfg(test)] +mod tests { + use std::path::PathBuf; + + use serde_json::Value; + + use super::*; + const TEST_BIN_OUT_DIR: &str = "target/debug"; + const TEST_SERVER_NAME: &str = "test_mcp_server"; + + fn get_workspace_root() -> PathBuf { + let output = std::process::Command::new("cargo") + .args(["metadata", "--format-version=1", "--no-deps"]) + .output() + .expect("Failed to execute cargo metadata"); + + let metadata: serde_json::Value = + serde_json::from_slice(&output.stdout).expect("Failed to parse cargo metadata"); + + let workspace_root = metadata["workspace_root"] + .as_str() + .expect("Failed to find workspace_root in metadata"); + + PathBuf::from(workspace_root) + } + + #[tokio::test(flavor = "multi_thread")] + async fn test_client_stdio() { + std::process::Command::new("cargo") + .args(["build", "--bin", TEST_SERVER_NAME]) + .status() + .expect("Failed to build binary"); + let workspace_root = get_workspace_root(); + let bin_path = workspace_root.join(TEST_BIN_OUT_DIR).join(TEST_SERVER_NAME); + println!("bin path: {}", bin_path.to_str().unwrap_or("no path found")); + + // Testing 2 concurrent sessions to make sure transport layer does not overlap. + let init_params_one = serde_json::json!({ + "protocolVersion": "2024-11-05", + "capabilities": { + "roots": { + "listChanged": true + }, + "sampling": {} + }, + "clientInfo": { + "name": "TestClientOne", + "version": "1.0.0" + } + }); + let client_config_one = ClientConfig { + server_name: "test_tool".to_owned(), + bin_path: bin_path.to_str().unwrap().to_string(), + args: ["1".to_owned()].to_vec(), + timeout: 60, + init_params: init_params_one.clone(), + }; + let init_params_two = serde_json::json!({ + "protocolVersion": "2024-11-05", + "capabilities": { + "roots": { + "listChanged": false + }, + "sampling": {} + }, + "clientInfo": { + "name": "TestClientTwo", + "version": "1.0.0" + } + }); + let client_config_two = ClientConfig { + server_name: "test_tool".to_owned(), + bin_path: bin_path.to_str().unwrap().to_string(), + args: ["2".to_owned()].to_vec(), + timeout: 60, + init_params: init_params_two.clone(), + }; + let mut client_one = Client::::from_config(client_config_one).expect("Failed to create client"); + let mut client_two = Client::::from_config(client_config_two).expect("Failed to create client"); + + let (res_one, res_two) = tokio::join!( + time::timeout( + time::Duration::from_secs(5), + test_client_routine(&mut client_one, init_params_one) + ), + time::timeout( + time::Duration::from_secs(5), + test_client_routine(&mut client_two, init_params_two) + ) + ); + let res_one = res_one.expect("Client one timed out"); + let res_two = res_two.expect("Client two timed out"); + assert!(res_one.is_ok()); + assert!(res_two.is_ok()); + } + + async fn test_client_routine( + client: &mut Client, + cap_sent: serde_json::Value, + ) -> Result<(), Box> { + let _ = client.init().await.expect("Client init failed"); + tokio::time::sleep(time::Duration::from_millis(1500)).await; + let client_capabilities_sent = client + .request("verify_init_ack_sent", None) + .await + .expect("Verify init ack mock request failed"); + let has_server_recvd_init_ack = client_capabilities_sent + .get("result") + .expect("Failed to retrieve client capabilities sent."); + assert_eq!(has_server_recvd_init_ack.to_string(), "true"); + let cap_recvd = client + .request("verify_init_params_sent", None) + .await + .expect("Verify init params mock request failed"); + let cap_recvd = cap_recvd + .get("result") + .expect("Verify init params mock request does not contain required field (result)"); + assert!(are_json_values_equal(&cap_sent, cap_recvd)); + + let fake_server_names = ["get_weather_one", "get_weather_two", "get_weather_three"]; + let mock_result_spec = fake_server_names.map(create_fake_tool_spec); + let mock_tool_specs_for_verify = serde_json::json!(mock_result_spec.clone()); + let mock_tool_specs_prep_param = mock_result_spec + .iter() + .zip(fake_server_names.iter()) + .map(|(v, n)| { + serde_json::json!({ + "key": (*n).to_string(), + "value": v + }) + }) + .collect::>(); + let mock_tool_specs_prep_param = + serde_json::to_value(mock_tool_specs_prep_param).expect("Failed to create mock tool specs prep param"); + let _ = client + .request("store_mock_tool_spec", Some(mock_tool_specs_prep_param)) + .await + .expect("Mock tool spec prep failed"); + let tool_spec_recvd = client.request("tools/list", None).await.expect("List tools failed"); + assert!(are_json_values_equal( + tool_spec_recvd + .get("result") + .and_then(|v| v.get("tools")) + .expect("Failed to retrieve tool specs from result received"), + &mock_tool_specs_for_verify + )); + Ok(()) + } + + fn are_json_values_equal(a: &Value, b: &Value) -> bool { + match (a, b) { + (Value::Null, Value::Null) => true, + (Value::Bool(a_val), Value::Bool(b_val)) => a_val == b_val, + (Value::Number(a_val), Value::Number(b_val)) => a_val == b_val, + (Value::String(a_val), Value::String(b_val)) => a_val == b_val, + (Value::Array(a_arr), Value::Array(b_arr)) => { + if a_arr.len() != b_arr.len() { + return false; + } + a_arr + .iter() + .zip(b_arr.iter()) + .all(|(a_item, b_item)| are_json_values_equal(a_item, b_item)) + }, + (Value::Object(a_obj), Value::Object(b_obj)) => { + if a_obj.len() != b_obj.len() { + return false; + } + a_obj.iter().all(|(key, a_value)| match b_obj.get(key) { + Some(b_value) => are_json_values_equal(a_value, b_value), + None => false, + }) + }, + _ => false, + } + } + + fn create_fake_tool_spec(name_to_append: &str) -> serde_json::Value { + serde_json::json!({ + "name": name_to_append, + "description": "Get current weather information for a location", + "inputSchema": { + "type": "object", + "properties": { + "location": { + "type": "string", + "description": "City name or zip code" + } + }, + "required": ["location"] + } + }) + } +} diff --git a/crates/mcp_client/src/error.rs b/crates/mcp_client/src/error.rs new file mode 100644 index 000000000..d05e7efa4 --- /dev/null +++ b/crates/mcp_client/src/error.rs @@ -0,0 +1,66 @@ +/// Error codes as defined in the MCP protocol. +/// +/// These error codes are based on the JSON-RPC 2.0 specification with additional +/// MCP-specific error codes in the -32000 to -32099 range. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(i32)] +pub enum ErrorCode { + /// Invalid JSON was received by the server. + /// An error occurred on the server while parsing the JSON text. + ParseError = -32700, + + /// The JSON sent is not a valid Request object. + InvalidRequest = -32600, + + /// The method does not exist / is not available. + MethodNotFound = -32601, + + /// Invalid method parameter(s). + InvalidParams = -32602, + + /// Internal JSON-RPC error. + InternalError = -32603, + + /// Server has not been initialized. + /// This error is returned when a request is made before the server + /// has been properly initialized. + ServerNotInitialized = -32002, + + /// Unknown error code. + /// This error is returned when an error code is received that is not + /// recognized by the implementation. + UnknownErrorCode = -32001, + + /// Request failed. + /// This error is returned when a request fails for a reason not covered + /// by other error codes. + RequestFailed = -32000, +} + +impl From for ErrorCode { + fn from(code: i32) -> Self { + match code { + -32700 => ErrorCode::ParseError, + -32600 => ErrorCode::InvalidRequest, + -32601 => ErrorCode::MethodNotFound, + -32602 => ErrorCode::InvalidParams, + -32603 => ErrorCode::InternalError, + -32002 => ErrorCode::ServerNotInitialized, + -32001 => ErrorCode::UnknownErrorCode, + -32000 => ErrorCode::RequestFailed, + _ => ErrorCode::UnknownErrorCode, + } + } +} + +impl From for i32 { + fn from(code: ErrorCode) -> Self { + code as i32 + } +} + +impl std::fmt::Display for ErrorCode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} diff --git a/crates/mcp_client/src/lib.rs b/crates/mcp_client/src/lib.rs new file mode 100644 index 000000000..2a828d20c --- /dev/null +++ b/crates/mcp_client/src/lib.rs @@ -0,0 +1,85 @@ +use serde::{ + Deserialize, + Serialize, +}; +use thiserror::Error; + +pub mod client; +pub mod error; +pub mod server; +pub mod transport; + +pub use client::*; +pub use transport::*; + +/// https://spec.modelcontextprotocol.io/specification/2024-11-05/server/utilities/pagination/#operations-supporting-pagination +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum PaginationSupportedOps { + ResourcesList, + ResourceTemplatesList, + PromptsList, + ToolsList, +} + +impl PaginationSupportedOps { + fn as_key(&self) -> &str { + match self { + PaginationSupportedOps::ResourcesList => "resources", + PaginationSupportedOps::ResourceTemplatesList => "resourceTemplates", + PaginationSupportedOps::PromptsList => "prompts", + PaginationSupportedOps::ToolsList => "tools", + } + } +} + +impl TryFrom<&str> for PaginationSupportedOps { + type Error = OpsConversionError; + + fn try_from(value: &str) -> Result { + match value { + "resources/list" => Ok(PaginationSupportedOps::ResourcesList), + "resources/templates/list" => Ok(PaginationSupportedOps::ResourceTemplatesList), + "prompts/list" => Ok(PaginationSupportedOps::PromptsList), + "tools/list" => Ok(PaginationSupportedOps::ToolsList), + _ => Err(OpsConversionError::InvalidMethod), + } + } +} + +#[derive(Error, Debug)] +pub enum OpsConversionError { + #[error("Invalid method encountered")] + InvalidMethod, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ResourcesListResult { + resources: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + next_cursor: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ResourceTemplatesListResult { + resource_templates: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + next_cursor: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PromptsListResult { + prompts: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + next_cursor: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ToolsListResult { + tools: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + next_cursor: Option, +} diff --git a/crates/mcp_client/src/server.rs b/crates/mcp_client/src/server.rs new file mode 100644 index 000000000..30415ff13 --- /dev/null +++ b/crates/mcp_client/src/server.rs @@ -0,0 +1,291 @@ +use std::collections::HashMap; +use std::sync::atomic::{ + AtomicBool, + AtomicU64, + Ordering, +}; +use std::sync::{ + Arc, + Mutex, +}; + +use tokio::io::{ + Stdin, + Stdout, +}; +use tokio::task::JoinHandle; + +use crate::client::StdioTransport; +use crate::error::ErrorCode; +use crate::transport::base_protocol::{ + JsonRpcError, + JsonRpcMessage, + JsonRpcNotification, + JsonRpcRequest, + JsonRpcResponse, +}; +use crate::transport::stdio::JsonRpcStdioTransport; +use crate::transport::{ + JsonRpcVersion, + Transport, + TransportError, +}; + +pub type Request = serde_json::Value; +pub type Response = Option; +pub type InitializedServer = JoinHandle>; + +pub trait PreServerRequestHandler { + fn register_pending_request_callback(&mut self, cb: impl Fn(u64) -> Option + Send + Sync + 'static); + fn register_send_request_callback( + &mut self, + cb: impl Fn(&str, Option) -> Result<(), ServerError> + Send + Sync + 'static, + ); +} + +#[async_trait::async_trait] +pub trait ServerRequestHandler: PreServerRequestHandler + Send + Sync + 'static { + async fn handle_initialize(&self, params: Option) -> Result; + async fn handle_incoming(&self, method: &str, params: Option) -> Result; + async fn handle_response(&self, resp: JsonRpcResponse) -> Result<(), ServerError>; + async fn handle_shutdown(&self) -> Result<(), ServerError>; +} + +pub struct Server { + transport: Option>, + handler: Option, + #[allow(dead_code)] + pending_requests: Arc>>, + #[allow(dead_code)] + current_id: Arc, +} + +#[derive(Debug, thiserror::Error)] +pub enum ServerError { + #[error(transparent)] + TransportError(#[from] TransportError), + #[error(transparent)] + Io(#[from] std::io::Error), + #[error(transparent)] + Serialization(#[from] serde_json::Error), + #[error("Unexpected msg type encountered")] + UnexpectedMsgType, + #[error("{0}")] + NegotiationError(String), + #[error(transparent)] + TokioJoinError(#[from] tokio::task::JoinError), + #[error("Failed to obtain mutex lock")] + MutexError, + #[error("Failed to obtain request method")] + MissingMethod, + #[error("Failed to obtain request id")] + MissingId, + #[error("Failed to initialize server. Missing transport")] + MissingTransport, + #[error("Failed to initialize server. Missing handler")] + MissingHandler, +} + +impl Server +where + H: ServerRequestHandler, +{ + pub fn new(mut handler: H, stdin: Stdin, stdout: Stdout) -> Result { + let transport = Arc::new(JsonRpcStdioTransport::server(stdin, stdout)?); + let pending_requests = Arc::new(Mutex::new(HashMap::::new())); + let pending_requests_clone_one = pending_requests.clone(); + let current_id = Arc::new(AtomicU64::new(0)); + let pending_request_getter = move |id: u64| -> Option { + match pending_requests_clone_one.lock() { + Ok(mut p) => p.remove(&id), + Err(_) => None, + } + }; + handler.register_pending_request_callback(pending_request_getter); + let transport_clone = transport.clone(); + let pending_request_clone_two = pending_requests.clone(); + let current_id_clone = current_id.clone(); + let request_sender = move |method: &str, params: Option| -> Result<(), ServerError> { + let id = current_id_clone.fetch_add(1, Ordering::SeqCst); + let request = JsonRpcRequest { + jsonrpc: JsonRpcVersion::default(), + id, + method: method.to_owned(), + params, + }; + let msg = JsonRpcMessage::Request(request.clone()); + let transport = transport_clone.clone(); + tokio::task::spawn(async move { + let _ = transport.send(&msg).await; + }); + #[allow(clippy::map_err_ignore)] + let mut pending_request = pending_request_clone_two.lock().map_err(|_| ServerError::MutexError)?; + pending_request.insert(id, request); + Ok(()) + }; + handler.register_send_request_callback(request_sender); + let server = Self { + transport: Some(transport), + handler: Some(handler), + pending_requests, + current_id, + }; + Ok(server) + } +} + +impl Server +where + T: Transport, + H: ServerRequestHandler, +{ + pub fn init(mut self) -> Result { + let transport = self.transport.take().ok_or(ServerError::MissingTransport)?; + let handler = Arc::new(self.handler.take().ok_or(ServerError::MissingHandler)?); + let has_initialized = Arc::new(AtomicBool::new(false)); + let listener = tokio::spawn(async move { + loop { + let request = transport.monitor().await; + let transport_clone = transport.clone(); + let has_init_clone = has_initialized.clone(); + let handler_clone = handler.clone(); + tokio::task::spawn(async move { + process_request(has_init_clone, transport_clone, handler_clone, request).await; + }); + } + }); + Ok(listener) + } +} + +async fn process_request( + has_initialized: Arc, + transport: Arc, + handler: Arc, + request: Result, +) where + T: Transport, + H: ServerRequestHandler, +{ + match request { + Ok(msg) if msg.is_initialize() => { + let id = msg.id().unwrap_or_default(); + if has_initialized.load(Ordering::SeqCst) { + let resp = JsonRpcMessage::Response(JsonRpcResponse { + jsonrpc: JsonRpcVersion::default(), + id, + error: Some(JsonRpcError { + code: ErrorCode::InvalidRequest.into(), + message: "Server has already been initialized".to_owned(), + data: None, + }), + ..Default::default() + }); + let _ = transport.send(&resp).await; + return; + } + let JsonRpcMessage::Request(req) = msg else { + let resp = JsonRpcMessage::Response(JsonRpcResponse { + jsonrpc: JsonRpcVersion::default(), + id, + error: Some(JsonRpcError { + code: ErrorCode::InvalidRequest.into(), + message: "Invalid method for initialization (use request)".to_owned(), + data: None, + }), + ..Default::default() + }); + let _ = transport.send(&resp).await; + return; + }; + let JsonRpcRequest { params, .. } = req; + match handler.handle_initialize(params).await { + Ok(result) => { + let resp = JsonRpcMessage::Response(JsonRpcResponse { + id, + result, + ..Default::default() + }); + let _ = transport.send(&resp).await; + has_initialized.store(true, Ordering::SeqCst); + }, + Err(_e) => { + let resp = JsonRpcMessage::Response(JsonRpcResponse { + jsonrpc: JsonRpcVersion::default(), + id, + error: Some(JsonRpcError { + code: ErrorCode::InternalError.into(), + message: "Error producing initialization response".to_owned(), + data: None, + }), + ..Default::default() + }); + let _ = transport.send(&resp).await; + }, + } + }, + Ok(msg) if msg.is_shutdown() => { + // TODO: add shutdown routine + }, + Ok(msg) if has_initialized.load(Ordering::SeqCst) => match msg { + JsonRpcMessage::Request(req) => { + let JsonRpcRequest { + id, + jsonrpc, + params, + ref method, + } = req; + let resp = handler.handle_incoming(method, params).await.map_or_else( + |error| { + let err = JsonRpcError { + code: ErrorCode::InternalError.into(), + message: error.to_string(), + data: None, + }; + let resp = JsonRpcResponse { + jsonrpc: jsonrpc.clone(), + id, + result: None, + error: Some(err), + }; + JsonRpcMessage::Response(resp) + }, + |result| { + let resp = JsonRpcResponse { + jsonrpc: jsonrpc.clone(), + id, + result, + error: None, + }; + JsonRpcMessage::Response(resp) + }, + ); + let _ = transport.send(&resp).await; + }, + JsonRpcMessage::Notification(notif) => { + let JsonRpcNotification { ref method, params, .. } = notif; + let _ = handler.handle_incoming(method, params).await; + }, + JsonRpcMessage::Response(resp) => { + let _ = handler.handle_response(resp).await; + }, + }, + Ok(msg) => { + let id = msg.id().unwrap_or_default(); + let resp = JsonRpcMessage::Response(JsonRpcResponse { + jsonrpc: JsonRpcVersion::default(), + id, + error: Some(JsonRpcError { + code: ErrorCode::ServerNotInitialized.into(), + message: "Server has not been initialized".to_owned(), + data: None, + }), + ..Default::default() + }); + let _ = transport.send(&resp).await; + }, + Err(_e) => { + // TODO: error handling + }, + } +} diff --git a/crates/mcp_client/src/transport/base_protocol.rs b/crates/mcp_client/src/transport/base_protocol.rs new file mode 100644 index 000000000..33d76d1eb --- /dev/null +++ b/crates/mcp_client/src/transport/base_protocol.rs @@ -0,0 +1,107 @@ +//! Referencing https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/messages/ +//! Protocol Revision 2024-11-05 +use serde::{ + Deserialize, + Serialize, +}; + +pub type RequestId = u64; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub struct JsonRpcVersion(String); + +impl Default for JsonRpcVersion { + fn default() -> Self { + JsonRpcVersion("2.0".to_owned()) + } +} +impl JsonRpcVersion { + pub fn as_u32_vec(&self) -> Vec { + self.0 + .split(".") + .map(|n| n.parse::().unwrap()) + .collect::>() + } +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[serde(untagged)] +#[serde(deny_unknown_fields)] +// DO NOT change the order of these variants. This body of json is [untagged](https://serde.rs/enum-representations.html#untagged) +// The categorization of the deserialization depends on the order in which the variants are +// declared. +pub enum JsonRpcMessage { + Response(JsonRpcResponse), + Request(JsonRpcRequest), + Notification(JsonRpcNotification), +} + +impl JsonRpcMessage { + pub fn is_initialize(&self) -> bool { + match self { + JsonRpcMessage::Request(req) => req.method == "initialize", + _ => false, + } + } + + pub fn is_shutdown(&self) -> bool { + match self { + JsonRpcMessage::Notification(notif) => notif.method == "notification/shutdown", + _ => false, + } + } + + pub fn id(&self) -> Option { + match self { + JsonRpcMessage::Request(req) => Some(req.id), + JsonRpcMessage::Response(resp) => Some(resp.id), + JsonRpcMessage::Notification(_) => None, + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)] +#[serde(default, deny_unknown_fields)] +pub struct JsonRpcRequest { + pub jsonrpc: JsonRpcVersion, + pub id: RequestId, + pub method: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub params: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)] +#[serde(default, deny_unknown_fields)] +pub struct JsonRpcResponse { + pub jsonrpc: JsonRpcVersion, + pub id: RequestId, + #[serde(skip_serializing_if = "Option::is_none")] + pub result: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub error: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)] +#[serde(default, deny_unknown_fields)] +pub struct JsonRpcNotification { + pub jsonrpc: JsonRpcVersion, + pub method: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub params: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)] +#[serde(default, deny_unknown_fields)] +pub struct JsonRpcError { + pub code: i32, + pub message: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub data: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)] +pub enum TransportType { + #[default] + Stdio, + Websocket, +} diff --git a/crates/mcp_client/src/transport/mod.rs b/crates/mcp_client/src/transport/mod.rs new file mode 100644 index 000000000..b8a02c9d0 --- /dev/null +++ b/crates/mcp_client/src/transport/mod.rs @@ -0,0 +1,43 @@ +pub mod base_protocol; +pub mod stdio; + +use std::fmt::Debug; + +pub use base_protocol::*; +pub use stdio::*; +use thiserror::Error; + +#[derive(Clone, Debug, Error)] +pub enum TransportError { + #[error("Serialization error: {0}")] + Serialization(String), + #[error("IO error: {0}")] + Stdio(String), + #[error("{0}")] + Custom(String), + #[error(transparent)] + RecvError(#[from] tokio::sync::broadcast::error::RecvError), +} + +impl From for TransportError { + fn from(err: serde_json::Error) -> Self { + TransportError::Serialization(err.to_string()) + } +} + +impl From for TransportError { + fn from(err: std::io::Error) -> Self { + TransportError::Stdio(err.to_string()) + } +} + +#[async_trait::async_trait] +pub trait Transport: Send + Sync + Debug + 'static { + /// Sends a message over the transport layer. + async fn send(&self, msg: &JsonRpcMessage) -> Result<(), TransportError>; + /// Listens to awaits for a response. This is a call that should be used after `send` is called + /// to listen for a response from the message recipient. + async fn listen(&self) -> Result; + /// Monitors for a response. This is meant for use in the background loop. + async fn monitor(&self) -> Result; +} diff --git a/crates/mcp_client/src/transport/stdio.rs b/crates/mcp_client/src/transport/stdio.rs new file mode 100644 index 000000000..113901646 --- /dev/null +++ b/crates/mcp_client/src/transport/stdio.rs @@ -0,0 +1,170 @@ +use std::sync::Arc; + +use tokio::io::{ + AsyncBufReadExt as _, + AsyncWriteExt as _, + BufReader, + Stdin, + Stdout, +}; +use tokio::process::{ + Child, + ChildStdin, +}; +use tokio::sync::{ + Mutex, + broadcast, +}; + +use super::base_protocol::JsonRpcMessage; +use super::{ + Transport, + TransportError, +}; + +#[derive(Debug)] +pub enum JsonRpcStdioTransport { + Client { + stdin: Arc>, + exclusive_receiver: Arc>>>, + shared_receiver: broadcast::Receiver>, + }, + Server { + stdout: Arc>, + exclusive_receiver: Arc>>>, + shared_receiver: broadcast::Receiver>, + }, +} + +impl JsonRpcStdioTransport { + pub fn client(child_process: Child) -> Result { + let (tx, receiver) = broadcast::channel::>(100); + let exclusive_receiver = Arc::new(Mutex::new(receiver)); + let shared_receiver = tx.subscribe(); + let Some(stdout) = child_process.stdout else { + return Err(TransportError::Custom("No stdout found on child process".to_owned())); + }; + let Some(stdin) = child_process.stdin else { + return Err(TransportError::Custom("No stdin found on child process".to_owned())); + }; + let stdin = Arc::new(Mutex::new(stdin)); + tokio::spawn(async move { + let mut buffer = Vec::::new(); + let mut buf_reader = BufReader::new(stdout); + loop { + buffer.clear(); + // Messages are delimited by newlines and assumed to contain no embedded newlines + // See https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/transports/#stdio + match buf_reader.read_until(b'\n', &mut buffer).await { + Ok(0) => continue, + Ok(_) => match serde_json::from_slice::(buffer.as_slice()) { + Ok(msg) => { + let _ = tx.send(Ok(msg)); + }, + Err(e) => { + let _ = tx.send(Err(e.into())); + }, + }, + Err(e) => { + let _ = tx.send(Err(e.into())); + }, + } + } + }); + Ok(JsonRpcStdioTransport::Client { + stdin, + exclusive_receiver, + shared_receiver, + }) + } + + pub fn server(stdin: Stdin, stdout: Stdout) -> Result { + let (tx, receiver) = broadcast::channel::>(100); + let exclusive_receiver = Arc::new(Mutex::new(receiver)); + let shared_receiver = tx.subscribe(); + tokio::spawn(async move { + let mut buffer = Vec::::new(); + let mut buf_reader = BufReader::new(stdin); + loop { + buffer.clear(); + // Messages are delimited by newlines and assumed to contain no embedded newlines + // See https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/transports/#stdio + match buf_reader.read_until(b'\n', &mut buffer).await { + Ok(0) => continue, + Ok(_) => match serde_json::from_slice::(buffer.as_slice()) { + Ok(msg) => { + let _ = tx.send(Ok(msg)); + }, + Err(e) => { + let _ = tx.send(Err(e.into())); + }, + }, + Err(e) => { + let _ = tx.send(Err(e.into())); + }, + } + } + }); + let stdout = Arc::new(Mutex::new(stdout)); + Ok(JsonRpcStdioTransport::Server { + stdout, + exclusive_receiver, + shared_receiver, + }) + } +} + +#[async_trait::async_trait] +impl Transport for JsonRpcStdioTransport { + async fn send(&self, msg: &JsonRpcMessage) -> Result<(), TransportError> { + match self { + JsonRpcStdioTransport::Client { stdin, .. } => { + let mut serialized = serde_json::to_vec(msg)?; + serialized.push(b'\n'); + let mut stdin = stdin.lock().await; + stdin + .write_all(&serialized) + .await + .map_err(|e| TransportError::Custom(format!("Error writing to server: {:?}", e)))?; + stdin + .flush() + .await + .map_err(|e| TransportError::Custom(format!("Error writing to server: {:?}", e)))?; + Ok(()) + }, + JsonRpcStdioTransport::Server { stdout, .. } => { + let mut serialized = serde_json::to_vec(msg)?; + serialized.push(b'\n'); + let mut stdout = stdout.lock().await; + stdout + .write_all(&serialized) + .await + .map_err(|e| TransportError::Custom(format!("Error writing to client: {:?}", e)))?; + stdout + .flush() + .await + .map_err(|e| TransportError::Custom(format!("Error writing to client: {:?}", e)))?; + Ok(()) + }, + } + } + + async fn listen(&self) -> Result { + match self { + JsonRpcStdioTransport::Client { shared_receiver, .. } + | JsonRpcStdioTransport::Server { shared_receiver, .. } => { + let mut rx = shared_receiver.resubscribe(); + rx.recv().await? + }, + } + } + + async fn monitor(&self) -> Result { + match self { + JsonRpcStdioTransport::Client { exclusive_receiver, .. } + | JsonRpcStdioTransport::Server { exclusive_receiver, .. } => { + exclusive_receiver.lock().await.recv().await? + }, + } + } +} diff --git a/crates/mcp_client/src/transport/websocket.rs b/crates/mcp_client/src/transport/websocket.rs new file mode 100644 index 000000000..e69de29bb diff --git a/crates/mcp_client/test_mcp_server/test_server.rs b/crates/mcp_client/test_mcp_server/test_server.rs new file mode 100644 index 000000000..ffe6c197b --- /dev/null +++ b/crates/mcp_client/test_mcp_server/test_server.rs @@ -0,0 +1,245 @@ +//! This is a bin used solely for testing the client +use std::collections::HashMap; +use std::str::FromStr; + +use mcp_client::server::{ + self, + PreServerRequestHandler, + Response, + ServerError, + ServerRequestHandler, +}; +use mcp_client::transport::{ + JsonRpcRequest, + JsonRpcResponse, + JsonRpcStdioTransport, +}; +use tokio::sync::Mutex; + +#[derive(Default)] +struct Handler { + pending_request: Option Option + Send + Sync>>, + #[allow(clippy::type_complexity)] + send_request: Option) -> Result<(), ServerError> + Send + Sync>>, + storage: Mutex>, + tool_spec: Mutex>, + tool_spec_key_list: Mutex>, +} + +impl PreServerRequestHandler for Handler { + fn register_pending_request_callback( + &mut self, + cb: impl Fn(u64) -> Option + Send + Sync + 'static, + ) { + self.pending_request = Some(Box::new(cb)); + } + + fn register_send_request_callback( + &mut self, + cb: impl Fn(&str, Option) -> Result<(), ServerError> + Send + Sync + 'static, + ) { + self.send_request = Some(Box::new(cb)); + } +} + +#[async_trait::async_trait] +impl ServerRequestHandler for Handler { + async fn handle_initialize(&self, params: Option) -> Result { + let mut storage = self.storage.lock().await; + if let Some(params) = params { + storage.insert("client_cap".to_owned(), params); + } + let capabilities = serde_json::json!({ + "protocolVersion": "2024-11-05", + "capabilities": { + "logging": {}, + "prompts": { + "listChanged": true + }, + "resources": { + "subscribe": true, + "listChanged": true + }, + "tools": { + "listChanged": true + } + }, + "serverInfo": { + "name": "TestServer", + "version": "1.0.0" + } + }); + Ok(Some(capabilities)) + } + + async fn handle_incoming(&self, method: &str, params: Option) -> Result { + match method { + "notifications/initialized" => { + { + let mut storage = self.storage.lock().await; + storage.insert( + "init_ack_sent".to_owned(), + serde_json::Value::from_str("true").expect("Failed to convert string to value"), + ); + } + Ok(None) + }, + "verify_init_params_sent" => { + let client_capabilities = { + let storage = self.storage.lock().await; + storage.get("client_cap").cloned() + }; + Ok(client_capabilities) + }, + "verify_init_ack_sent" => { + let result = { + let storage = self.storage.lock().await; + storage.get("init_ack_sent").cloned() + }; + Ok(result) + }, + "store_mock_tool_spec" => { + let Some(params) = params else { + eprintln!("Params missing from store mock tool spec"); + return Ok(None); + }; + // expecting a mock_specs: { key: String, value: serde_json::Value }[]; + let Ok(mock_specs) = serde_json::from_value::>(params) else { + eprintln!("Failed to convert to mock specs from value"); + return Ok(None); + }; + let self_tool_specs = self.tool_spec.lock().await; + let mut self_tool_spec_key_list = self.tool_spec_key_list.lock().await; + let _ = mock_specs.iter().fold(self_tool_specs, |mut acc, spec| { + let Some(key) = spec.get("key").cloned() else { + return acc; + }; + let Ok(key) = serde_json::from_value::(key) else { + eprintln!("Failed to convert serde value to string for key"); + return acc; + }; + self_tool_spec_key_list.push(key.clone()); + acc.insert(key, spec.get("value").cloned()); + acc + }); + Ok(None) + }, + "tools/list" => { + if let Some(params) = params { + if let Some(cursor) = params.get("cursor").cloned() { + let Ok(cursor) = serde_json::from_value::(cursor) else { + eprintln!("Failed to convert cursor to string: {:#?}", params); + return Ok(None); + }; + let self_tool_spec_key_list = self.tool_spec_key_list.lock().await; + let self_tool_spec = self.tool_spec.lock().await; + let (next_cursor, spec) = { + 'blk: { + for (i, item) in self_tool_spec_key_list.iter().enumerate() { + if item == &cursor { + break 'blk ( + self_tool_spec_key_list.get(i + 1).cloned(), + self_tool_spec.get(&cursor).cloned().unwrap(), + ); + } + } + (None, None) + } + }; + if let Some(next_cursor) = next_cursor { + return Ok(Some(serde_json::json!({ + "tools": [spec.unwrap()], + "nextCursor": next_cursor, + }))); + } else { + return Ok(Some(serde_json::json!({ + "tools": [spec.unwrap()], + }))); + } + } else { + eprintln!("Params exist but cursor is missing"); + return Ok(None); + } + } else { + let first_key = self + .tool_spec_key_list + .lock() + .await + .first() + .expect("First key missing from tool specs") + .clone(); + let first_value = self + .tool_spec + .lock() + .await + .get(&first_key) + .expect("First value missing from tool specs") + .clone(); + let second_key = self + .tool_spec_key_list + .lock() + .await + .get(1) + .expect("Second key missing from tool specs") + .clone(); + return Ok(Some(serde_json::json!({ + "tools": [first_value], + "nextCursor": second_key + }))); + }; + }, + // This is a test path relevant only to sampling + "trigger_server_request" => { + let Some(ref send_request) = self.send_request else { + return Err(ServerError::MissingMethod); + }; + let params = Some(serde_json::json!({ + "messages": [ + { + "role": "user", + "content": { + "type": "text", + "text": "What is the capital of France?" + } + } + ], + "modelPreferences": { + "hints": [ + { + "name": "claude-3-sonnet" + } + ], + "intelligencePriority": 0.8, + "speedPriority": 0.5 + }, + "systemPrompt": "You are a helpful assistant.", + "maxTokens": 100 + })); + send_request("sampling/createMessage", params)?; + Ok(None) + }, + _ => Err(ServerError::MissingMethod), + } + } + + // This is a test path relevant only to sampling + async fn handle_response(&self, resp: JsonRpcResponse) -> Result<(), ServerError> { + let JsonRpcResponse { id, .. } = resp; + let _pending = self.pending_request.as_ref().and_then(|f| f(id)); + Ok(()) + } + + async fn handle_shutdown(&self) -> Result<(), ServerError> { + Ok(()) + } +} + +#[tokio::main] +async fn main() { + let handler = Handler::default(); + let stdin = tokio::io::stdin(); + let stdout = tokio::io::stdout(); + let test_server = + server::Server::::new(handler, stdin, stdout).expect("Failed to create server"); + let _ = test_server.init().expect("Test server failed to init").await; +} diff --git a/crates/q_cli/Cargo.toml b/crates/q_cli/Cargo.toml index 7ad77015c..d34e015ef 100644 --- a/crates/q_cli/Cargo.toml +++ b/crates/q_cli/Cargo.toml @@ -59,6 +59,7 @@ glob.workspace = true globset.workspace = true indicatif.workspace = true indoc.workspace = true +mcp_client.workspace = true mimalloc.workspace = true owo-colors = "4.2.0" parking_lot.workspace = true @@ -69,6 +70,7 @@ semver.workspace = true serde.workspace = true serde_json.workspace = true shlex.workspace = true +shellexpand.workspace = true similar.workspace = true spinners = "4.1.0" sysinfo.workspace = true diff --git a/crates/q_cli/src/cli/chat/conversation_state.rs b/crates/q_cli/src/cli/chat/conversation_state.rs index f22535743..9da7b1d97 100644 --- a/crates/q_cli/src/cli/chat/conversation_state.rs +++ b/crates/q_cli/src/cli/chat/conversation_state.rs @@ -525,7 +525,7 @@ mod tests { use super::*; use crate::cli::chat::context::AMAZONQ_FILENAME; - use crate::cli::chat::load_tools; + use crate::cli::chat::tool_manager::ToolManager; #[test] fn test_truncate_safe() { @@ -587,7 +587,9 @@ mod tests { #[tokio::test] async fn test_conversation_state_history_handling_truncation() { - let mut conversation_state = ConversationState::new(Context::new_fake(), load_tools().unwrap(), None).await; + let tool_manager = ToolManager::default(); + let mut conversation_state = + ConversationState::new(Context::new_fake(), tool_manager.load_tools().await.unwrap(), None).await; // First, build a large conversation history. We need to ensure that the order is always // User -> Assistant -> User -> Assistant ...and so on. @@ -607,7 +609,9 @@ mod tests { #[tokio::test] async fn test_conversation_state_history_handling_with_tool_results() { // Build a long conversation history of tool use results. - let mut conversation_state = ConversationState::new(Context::new_fake(), load_tools().unwrap(), None).await; + let tool_manager = ToolManager::default(); + let mut conversation_state = + ConversationState::new(Context::new_fake(), tool_manager.load_tools().await.unwrap(), None).await; conversation_state.append_new_user_message("start".to_string()).await; for i in 0..=(MAX_CONVERSATION_STATE_HISTORY_LEN + 100) { let s = conversation_state.as_sendable_conversation_state().await; @@ -629,7 +633,8 @@ mod tests { } // Build a long conversation history of user messages mixed in with tool results. - let mut conversation_state = ConversationState::new(Context::new_fake(), load_tools().unwrap(), None).await; + let mut conversation_state = + ConversationState::new(Context::new_fake(), tool_manager.load_tools().await.unwrap(), None).await; conversation_state.append_new_user_message("start".to_string()).await; for i in 0..=(MAX_CONVERSATION_STATE_HISTORY_LEN + 100) { let s = conversation_state.as_sendable_conversation_state().await; @@ -665,7 +670,8 @@ mod tests { let ctx = Context::builder().with_test_home().await.unwrap().build_fake(); ctx.fs().write(AMAZONQ_FILENAME, "test context").await.unwrap(); - let mut conversation_state = ConversationState::new(ctx, load_tools().unwrap(), None).await; + let tool_manager = ToolManager::default(); + let mut conversation_state = ConversationState::new(ctx, tool_manager.load_tools().await.unwrap(), None).await; // First, build a large conversation history. We need to ensure that the order is always // User -> Assistant -> User -> Assistant ...and so on. diff --git a/crates/q_cli/src/cli/chat/mod.rs b/crates/q_cli/src/cli/chat/mod.rs index 26d60073e..7f1fa168d 100644 --- a/crates/q_cli/src/cli/chat/mod.rs +++ b/crates/q_cli/src/cli/chat/mod.rs @@ -5,6 +5,7 @@ mod input_source; mod parse; mod parser; mod prompt; +mod tool_manager; mod tools; use std::borrow::Cow; use std::collections::HashMap; @@ -65,10 +66,11 @@ use tokio::signal::unix::{ SignalKind, signal, }; -use tools::{ - Tool, - ToolSpec, +use tool_manager::{ + McpServerConfig, + ToolManager, }; +use tools::Tool; use tracing::{ debug, error, @@ -158,6 +160,11 @@ pub async fn chat(input: Option, accept_all: bool, profile: Option StreamingClient::new().await?, }; + let mcp_server_configs = McpServerConfig::load_config().await.unwrap_or_else(|e| { + tracing::warn!("No mcp server config loaded: {}", e); + McpServerConfig::default() + }); + // If profile is specified, verify it exists before starting the chat if let Some(ref profile_name) = profile { // Create a temporary context manager to check if the profile exists @@ -188,6 +195,7 @@ pub async fn chat(input: Option, accept_all: bool, profile: Option { tool_use_telemetry_events: HashMap, /// State used to keep track of tool use relation tool_use_status: ToolUseStatus, + /// Abstraction that consolidates custom tools with native ones + tool_manager: ToolManager, accept_all: bool, } @@ -259,10 +269,14 @@ impl ChatContext { interactive: bool, client: StreamingClient, terminal_width_provider: fn() -> Option, + mcp_server_config: Option, accept_all: bool, profile: Option, ) -> Result { + let mcp_server_config = mcp_server_config.unwrap_or_default(); + let tool_manager = ToolManager::from_configs(mcp_server_config).await; let ctx_clone = Arc::clone(&ctx); + let conversation_state = ConversationState::new(ctx_clone, tool_manager.load_tools().await?, profile).await; Ok(Self { ctx, settings, @@ -273,9 +287,10 @@ impl ChatContext { client, terminal_width_provider, spinner: None, - conversation_state: ConversationState::new(ctx_clone, load_tools()?, profile).await, + conversation_state, tool_use_telemetry_events: HashMap::new(), tool_use_status: ToolUseStatus::Idle, + tool_manager, accept_all, }) } @@ -1260,7 +1275,7 @@ where .set_tool_use_id(tool_use_id.clone()) .set_tool_name(tool_use.name.clone()) .utterance_id(self.conversation_state.message_id().map(|s| s.to_string())); - match Tool::try_from(tool_use) { + match self.tool_manager.get_tool_from_tool_use(tool_use) { Ok(mut tool) => { match tool.validate(&self.ctx).await { Ok(()) => { @@ -1514,11 +1529,6 @@ fn create_stream(model_responses: serde_json::Value) -> StreamingClient { StreamingClient::mock(mock) } -/// Returns all tools supported by Q chat. -fn load_tools() -> Result> { - Ok(serde_json::from_str(include_str!("tools/tool_index.json"))?) -} - #[cfg(test)] mod tests { use super::*; @@ -1558,6 +1568,7 @@ mod tests { true, test_client, || Some(80), + None, false, None, ) diff --git a/crates/q_cli/src/cli/chat/parse.rs b/crates/q_cli/src/cli/chat/parse.rs index 12330f65c..98b455b26 100644 --- a/crates/q_cli/src/cli/chat/parse.rs +++ b/crates/q_cli/src/cli/chat/parse.rs @@ -1,3 +1,4 @@ +#![allow(deprecated)] use std::io::Write; use crossterm::style::{ diff --git a/crates/q_cli/src/cli/chat/tool_manager.rs b/crates/q_cli/src/cli/chat/tool_manager.rs new file mode 100644 index 000000000..77806f694 --- /dev/null +++ b/crates/q_cli/src/cli/chat/tool_manager.rs @@ -0,0 +1,163 @@ +use std::collections::HashMap; +use std::path::PathBuf; +use std::sync::Arc; + +use convert_case::Casing; +use eyre::OptionExt; +use fig_api_client::model::{ + ToolResult, + ToolResultContentBlock, + ToolResultStatus, +}; +use futures::{ + StreamExt, + stream, +}; +use serde::{ + Deserialize, + Serialize, +}; + +use super::parser::ToolUse; +use super::tools::Tool; +use super::tools::custom_tool::{ + CustomToolClient, + CustomToolConfig, +}; +use super::tools::execute_bash::ExecuteBash; +use super::tools::fs_read::FsRead; +use super::tools::fs_write::FsWrite; +use super::tools::use_aws::UseAws; +use crate::cli::chat::tools::ToolSpec; +use crate::cli::chat::tools::custom_tool::CustomTool; + +const NAMESPACE_DELIMITER: &str = "___"; + +// This is to mirror claude's config set up +#[derive(Clone, Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct McpServerConfig { + mcp_servers: HashMap, +} + +impl McpServerConfig { + pub async fn load_config() -> eyre::Result { + let config_path = fig_settings::settings::get_value("mcp.config")? + .ok_or_eyre("No mcp config path specified")? + .as_str() + .ok_or_eyre("No valid path provided for mcp config") + .map(|path| shellexpand::tilde(path))? + .parse::()?; + let buf = tokio::fs::read(config_path).await?; + Ok(serde_json::from_slice::(&buf)?) + } +} + +#[derive(Default)] +pub struct ToolManager { + clients: HashMap>, +} + +impl ToolManager { + pub async fn from_configs(config: McpServerConfig) -> Self { + let McpServerConfig { mcp_servers } = config; + let pre_initialized = mcp_servers + .into_iter() + .map(|(server_name, server_config)| { + let server_name = server_name.to_case(convert_case::Case::Snake); + let custom_tool_client = CustomToolClient::from_config(server_name.clone(), server_config); + (server_name, custom_tool_client) + }) + .collect::>(); + let init_results = stream::iter(pre_initialized) + .map(|(name, uninit_client)| async move { (name, uninit_client.await) }) + .buffer_unordered(10) + .collect::>() + .await; + let mut clients = HashMap::>::new(); + for (name, init_res) in init_results { + match init_res { + Ok(client) => { + clients.insert(name, Arc::new(client)); + }, + Err(_e) => { + // TODO: log this + }, + } + } + Self { clients } + } + + pub async fn load_tools(&self) -> eyre::Result> { + let mut tool_specs = serde_json::from_str::>(include_str!("tools/tool_index.json"))?; + for client in self.clients.values() { + match client.get_tool_spec().await { + Ok((name, specs)) => { + // Each mcp server might have multiple tools. + // To avoid naming conflicts we are going to namespace it. + // This would also help us locate which mcp server to call the tool from. + for mut spec in specs { + spec.name = format!("{}{}{}", name, NAMESPACE_DELIMITER, spec.name); + tool_specs.insert(spec.name.clone(), spec); + } + }, + Err(_e) => { + // TODO: log this. Perhaps also delete it from the list of tools we have? + }, + } + } + Ok(tool_specs) + } + + pub fn get_tool_from_tool_use(&self, value: ToolUse) -> Result { + let map_err = |parse_error| ToolResult { + tool_use_id: value.id.clone(), + content: vec![ToolResultContentBlock::Text(format!( + "Failed to validate tool parameters: {parse_error}. The model has either suggested tool parameters which are incompatible with the existing tools, or has suggested one or more tool that does not exist in the list of known tools." + ))], + status: ToolResultStatus::Error, + }; + + Ok(match value.name.as_str() { + "fs_read" => Tool::FsRead(serde_json::from_value::(value.args).map_err(map_err)?), + "fs_write" => Tool::FsWrite(serde_json::from_value::(value.args).map_err(map_err)?), + "execute_bash" => Tool::ExecuteBash(serde_json::from_value::(value.args).map_err(map_err)?), + "use_aws" => Tool::UseAws(serde_json::from_value::(value.args).map_err(map_err)?), + // Note that this name is namespaced with server_name{DELIMITER}tool_name + name => { + let (server_name, tool_name) = name.split_once(NAMESPACE_DELIMITER).ok_or(ToolResult { + tool_use_id: value.id.clone(), + content: vec![ToolResultContentBlock::Text(format!( + "The tool, \"{name}\" is supplied with incorrect name" + ))], + status: ToolResultStatus::Error, + })?; + let Some(client) = self.clients.get(server_name) else { + return Err(ToolResult { + tool_use_id: value.id, + content: vec![ToolResultContentBlock::Text(format!( + "The tool, \"{server_name}\" is not supported by the client" + ))], + status: ToolResultStatus::Error, + }); + }; + // The tool input schema has the shape of { type, properties }. + // The field "params" expected by MCP is { name, arguments }, where name is the + // name of the tool being invoked, + // https://spec.modelcontextprotocol.io/specification/2024-11-05/server/tools/#calling-tools. + // The field "arguments" is where ToolUse::args belong. + let mut params = serde_json::Map::::new(); + params.insert("name".to_owned(), serde_json::Value::String(tool_name.to_owned())); + params.insert("arguments".to_owned(), value.args); + let params = serde_json::Value::Object(params); + let custom_tool = CustomTool { + name: tool_name.to_owned(), + client: client.clone(), + method: "tools/call".to_owned(), + params: Some(params), + }; + Tool::Custom(custom_tool) + }, + }) + } +} diff --git a/crates/q_cli/src/cli/chat/tools/custom_tool.rs b/crates/q_cli/src/cli/chat/tools/custom_tool.rs new file mode 100644 index 000000000..f42b3068c --- /dev/null +++ b/crates/q_cli/src/cli/chat/tools/custom_tool.rs @@ -0,0 +1,141 @@ +use std::collections::HashMap; +use std::io::Write; +use std::sync::Arc; + +use crossterm::{ + queue, + style, +}; +use eyre::Result; +use fig_os_shim::Context; +use mcp_client::{ + Client as McpClient, + ClientConfig as McpClientConfig, + JsonRpcStdioTransport, + ServerCapabilities, + StdioTransport, +}; +use serde::{ + Deserialize, + Serialize, +}; + +use super::{ + InvokeOutput, + ToolSpec, +}; + +// TODO: support http transport type +#[derive(Clone, Serialize, Deserialize, Debug)] +pub struct CustomToolConfig { + pub command: String, + pub args: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + pub env: Option>, +} + +#[derive(Debug)] +pub enum CustomToolClient { + Stdio { + server_name: String, + client: McpClient, + #[allow(dead_code)] + server_capabilities: Option, + }, +} + +impl CustomToolClient { + // TODO: add support for http transport + pub async fn from_config(server_name: String, config: CustomToolConfig) -> Result { + // TODO: accommodate for envs specified + let CustomToolConfig { command, args, env: _ } = config; + let mcp_client_config = McpClientConfig { + server_name: server_name.clone(), + bin_path: command.clone(), + args, + timeout: 120, + init_params: serde_json::json!({ + "protocolVersion": "2024-11-05", + "capabilities": {}, + "clientInfo": { + "name": "Q CLI Chat", + "version": "1.0.0" + } + }), + }; + let client = McpClient::::from_config(mcp_client_config)?; + let server_capabilities = Some(client.init().await?); + Ok(CustomToolClient::Stdio { + server_name, + client, + server_capabilities, + }) + } + + pub async fn get_tool_spec(&self) -> Result<(String, Vec)> { + match self { + CustomToolClient::Stdio { + client, server_name, .. + } => { + let resp = client.request("tools/list", None).await?; + // Assuming a shape of return as per https://spec.modelcontextprotocol.io/specification/2024-11-05/server/tools/#listing-tools + let result = resp + .get("result") + .ok_or(eyre::eyre!("Failed to retrieve result for custom tool {}", server_name))?; + let tools = result.get("tools").ok_or(eyre::eyre!( + "Failed to retrieve tools from result for custom tool {}", + server_name + ))?; + let tools = serde_json::from_value::>(tools.clone())?; + Ok((server_name.clone(), tools)) + }, + } + } + + pub async fn request(&self, method: &str, params: Option) -> Result { + match self { + CustomToolClient::Stdio { client, .. } => Ok(client.request(method, params).await?), + } + } + + #[allow(dead_code)] + pub async fn notify(&self, method: &str, params: Option) -> Result<()> { + match self { + CustomToolClient::Stdio { client, .. } => Ok(client.notify(method, params).await?), + } + } +} + +#[derive(Clone, Debug)] +pub struct CustomTool { + pub name: String, + pub client: Arc, + pub method: String, + pub params: Option, +} + +impl CustomTool { + pub async fn invoke(&self, _ctx: &Context, _updates: &mut impl Write) -> Result { + // Assuming a response shape as per https://spec.modelcontextprotocol.io/specification/2024-11-05/server/tools/#calling-tools + let resp = self.client.request(self.method.as_str(), self.params.clone()).await?; + let result = resp + .get("result") + .ok_or(eyre::eyre!("{} invocation failed to produce a result", self.name))?; + Ok(InvokeOutput { + output: super::OutputKind::Json(result.clone()), + }) + } + + pub fn queue_description(&self, updates: &mut impl Write) -> Result<()> { + queue!(updates, style::Print(format!("Running {}", self.name)),)?; + if let Some(params) = &self.params { + queue!(updates, style::Print(format!(" with the param:\n{}", params)),)?; + } + queue!(updates, style::Print("\n"),)?; + Ok(()) + } + + pub async fn validate(&mut self, _ctx: &Context) -> Result<()> { + Ok(()) + } +} diff --git a/crates/q_cli/src/cli/chat/tools/mod.rs b/crates/q_cli/src/cli/chat/tools/mod.rs index 7e6215f1e..13c67ea99 100644 --- a/crates/q_cli/src/cli/chat/tools/mod.rs +++ b/crates/q_cli/src/cli/chat/tools/mod.rs @@ -1,3 +1,4 @@ +pub mod custom_tool; pub mod execute_bash; pub mod fs_read; pub mod fs_write; @@ -13,6 +14,7 @@ use aws_smithy_types::{ Document, Number as SmithyNumber, }; +use custom_tool::CustomTool; use execute_bash::ExecuteBash; use eyre::Result; use fig_api_client::model::{ @@ -37,17 +39,20 @@ pub enum Tool { FsWrite(FsWrite), ExecuteBash(ExecuteBash), UseAws(UseAws), + Custom(CustomTool), } impl Tool { /// The display name of a tool - pub fn display_name(&self) -> &'static str { + pub fn display_name(&self) -> String { match self { Tool::FsRead(_) => "Read from filesystem", Tool::FsWrite(_) => "Write to filesystem", Tool::ExecuteBash(_) => "Execute shell command", Tool::UseAws(_) => "Use AWS CLI", + Tool::Custom(custom_tool) => &custom_tool.name, } + .to_owned() } // TODO: Remove, just roll with it for now ya? @@ -57,6 +62,7 @@ impl Tool { Tool::FsWrite(_) => "Writing to filesystem", Tool::ExecuteBash(execute_bash) => return format!("Executing `{}`", execute_bash.command), Tool::UseAws(_) => "Using AWS CLI", + Tool::Custom(custom_tool) => &custom_tool.name, } .to_owned() } @@ -68,6 +74,7 @@ impl Tool { Tool::FsWrite(_) => true, Tool::ExecuteBash(execute_bash) => execute_bash.requires_acceptance(), Tool::UseAws(use_aws) => use_aws.requires_acceptance(), + Tool::Custom(_) => false, } } @@ -78,6 +85,7 @@ impl Tool { Tool::FsWrite(fs_write) => fs_write.invoke(context, updates).await, Tool::ExecuteBash(execute_bash) => execute_bash.invoke(updates).await, Tool::UseAws(use_aws) => use_aws.invoke(context, updates).await, + Tool::Custom(custom_tool) => custom_tool.invoke(context, updates).await, } } @@ -88,6 +96,7 @@ impl Tool { Tool::FsWrite(fs_write) => fs_write.queue_description(ctx, updates), Tool::ExecuteBash(execute_bash) => execute_bash.queue_description(updates), Tool::UseAws(use_aws) => use_aws.queue_description(updates), + Tool::Custom(custom_tool) => custom_tool.queue_description(updates), } } @@ -98,6 +107,7 @@ impl Tool { Tool::FsWrite(fs_write) => fs_write.validate(ctx).await, Tool::ExecuteBash(execute_bash) => execute_bash.validate(ctx).await, Tool::UseAws(use_aws) => use_aws.validate(ctx).await, + Tool::Custom(custom_tool) => custom_tool.validate(ctx).await, } } } @@ -138,6 +148,7 @@ impl TryFrom for Tool { pub struct ToolSpec { pub name: String, pub description: String, + #[serde(alias = "inputSchema")] pub input_schema: InputSchema, }