chore: seed v0.8.60 branch from main after v0.8.59
# Conflicts: # README.md # crates/cli/src/lib.rs # crates/config/src/lib.rs # crates/config/src/provider.rs # crates/tui/src/commands/mod.rs # crates/tui/src/localization.rs # crates/tui/src/prompts.rs # crates/tui/src/tui/ui.rs # crates/tui/src/tui/ui/tests.rs # crates/tui/src/tui/widgets/tool_card.rs # scripts/benchmarks/cli-compare.py
This commit is contained in:
Generated
+129
-56
@@ -280,7 +280,7 @@ dependencies = [
|
||||
"futures-lite",
|
||||
"parking",
|
||||
"polling",
|
||||
"rustix 1.1.3",
|
||||
"rustix 1.1.4",
|
||||
"slab",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
@@ -311,7 +311,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"event-listener",
|
||||
"futures-lite",
|
||||
"rustix 1.1.3",
|
||||
"rustix 1.1.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -337,7 +337,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"rustix 1.1.3",
|
||||
"rustix 1.1.4",
|
||||
"signal-hook-registry",
|
||||
"slab",
|
||||
"windows-sys 0.61.2",
|
||||
@@ -656,6 +656,12 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
|
||||
|
||||
[[package]]
|
||||
name = "cff-parser"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31f5b6e9141c036f3ff4ce7b2f7e432b0f00dee416ddcd4f17741d189ddc2e9d"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.4"
|
||||
@@ -1243,7 +1249,7 @@ dependencies = [
|
||||
"document-features",
|
||||
"mio",
|
||||
"parking_lot",
|
||||
"rustix 1.1.3",
|
||||
"rustix 1.1.4",
|
||||
"signal-hook",
|
||||
"signal-hook-mio",
|
||||
"winapi",
|
||||
@@ -1676,6 +1682,15 @@ version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
|
||||
|
||||
[[package]]
|
||||
name = "ecb"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a8bfa975b1aec2145850fcaa1c6fe269a16578c44705a532ae3edc92b8881c7"
|
||||
dependencies = [
|
||||
"cipher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.15.0"
|
||||
@@ -1884,7 +1899,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"rustix 1.1.3",
|
||||
"rustix 1.1.4",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
@@ -1939,9 +1954,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.5"
|
||||
version = "1.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb"
|
||||
checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
@@ -2115,7 +2130,7 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8"
|
||||
dependencies = [
|
||||
"rustix 1.1.3",
|
||||
"rustix 1.1.4",
|
||||
"windows-link 0.2.1",
|
||||
]
|
||||
|
||||
@@ -2563,9 +2578,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "image"
|
||||
version = "0.25.9"
|
||||
version = "0.25.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6506c6c10786659413faa717ceebcb8f70731c0a60cbae39795fdf114519c1a"
|
||||
checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"byteorder-lite",
|
||||
@@ -2926,9 +2941,9 @@ checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.11.0"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
|
||||
checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
|
||||
|
||||
[[package]]
|
||||
name = "litemap"
|
||||
@@ -2982,19 +2997,29 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lopdf"
|
||||
version = "0.34.0"
|
||||
version = "0.38.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c5c8ecfc6c72051981c0459f75ccc585e7ff67c70829560cda8e647882a9abff"
|
||||
checksum = "c7184fdea2bc3cd272a1acec4030c321a8f9875e877b3f92a53f2f6033fdc289"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"bitflags 2.12.1",
|
||||
"cbc",
|
||||
"ecb",
|
||||
"encoding_rs",
|
||||
"flate2",
|
||||
"getrandom 0.3.4",
|
||||
"indexmap",
|
||||
"itoa",
|
||||
"log",
|
||||
"md-5",
|
||||
"nom 7.1.3",
|
||||
"nom 8.0.0",
|
||||
"nom_locate",
|
||||
"rand 0.9.4",
|
||||
"rangemap",
|
||||
"time",
|
||||
"sha2 0.10.9",
|
||||
"stringprep",
|
||||
"thiserror 2.0.18",
|
||||
"ttf-parser",
|
||||
"weezl",
|
||||
]
|
||||
|
||||
@@ -3143,9 +3168,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "moxcms"
|
||||
version = "0.7.11"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac9557c559cd6fc9867e122e20d2cbefc9ca29d80d027a8e39310920ed2f0a97"
|
||||
checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"pxfm",
|
||||
@@ -3356,9 +3381,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objc2"
|
||||
version = "0.6.3"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05"
|
||||
checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f"
|
||||
dependencies = [
|
||||
"objc2-encode",
|
||||
]
|
||||
@@ -3513,13 +3538,15 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "pdf-extract"
|
||||
version = "0.7.12"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cbb3a5387b94b9053c1e69d8abfd4dd6dae7afda65a5c5279bc1f42ab39df575"
|
||||
checksum = "1e28ba1758a3d3f361459645780e09570b573fc3c82637449e9963174c813a98"
|
||||
dependencies = [
|
||||
"adobe-cmap-parser",
|
||||
"cff-parser",
|
||||
"encoding_rs",
|
||||
"euclid 0.20.14",
|
||||
"log",
|
||||
"lopdf",
|
||||
"postscript",
|
||||
"type1-encoding-parser",
|
||||
@@ -3639,7 +3666,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
|
||||
dependencies = [
|
||||
"phf_shared",
|
||||
"rand",
|
||||
"rand 0.8.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3736,7 +3763,7 @@ dependencies = [
|
||||
"concurrent-queue",
|
||||
"hermit-abi",
|
||||
"pin-project-lite",
|
||||
"rustix 1.1.3",
|
||||
"rustix 1.1.4",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
@@ -3890,8 +3917,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_chacha 0.3.1",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea"
|
||||
dependencies = [
|
||||
"rand_chacha 0.9.0",
|
||||
"rand_core 0.9.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3901,7 +3938,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.9.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3913,6 +3960,15 @@ dependencies = [
|
||||
"getrandom 0.2.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
|
||||
dependencies = [
|
||||
"getrandom 0.3.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rangemap"
|
||||
version = "1.7.1"
|
||||
@@ -4211,14 +4267,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.1.3"
|
||||
version = "1.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34"
|
||||
checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
|
||||
dependencies = [
|
||||
"bitflags 2.12.1",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.11.0",
|
||||
"linux-raw-sys 0.12.1",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
@@ -4467,7 +4523,7 @@ dependencies = [
|
||||
"hkdf",
|
||||
"num",
|
||||
"once_cell",
|
||||
"rand",
|
||||
"rand 0.8.6",
|
||||
"serde",
|
||||
"sha2 0.10.9",
|
||||
"zbus",
|
||||
@@ -4899,6 +4955,17 @@ dependencies = [
|
||||
"precomputed-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stringprep"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1"
|
||||
dependencies = [
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
"unicode-properties",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
@@ -5026,14 +5093,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.24.0"
|
||||
version = "3.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c"
|
||||
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"getrandom 0.3.4",
|
||||
"once_cell",
|
||||
"rustix 1.1.3",
|
||||
"rustix 1.1.4",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
@@ -5054,7 +5121,7 @@ version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874"
|
||||
dependencies = [
|
||||
"rustix 1.1.3",
|
||||
"rustix 1.1.4",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
@@ -5192,9 +5259,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tiff"
|
||||
version = "0.10.3"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af9605de7fee8d9551863fd692cce7637f548dbd9db9180fcc07ccc6d26c336f"
|
||||
checksum = "b63feaf3343d35b6ca4d50483f94843803b0f51634937cc2ec519fc32232bc52"
|
||||
dependencies = [
|
||||
"fax",
|
||||
"flate2",
|
||||
@@ -5211,14 +5278,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"itoa",
|
||||
"libc",
|
||||
"num-conv",
|
||||
"num_threads",
|
||||
"powerfmt",
|
||||
"serde_core",
|
||||
"time-core",
|
||||
"time-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5227,16 +5292,6 @@ version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215"
|
||||
dependencies = [
|
||||
"num-conv",
|
||||
"time-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiny-keccak"
|
||||
version = "2.0.2"
|
||||
@@ -5528,6 +5583,12 @@ version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
||||
|
||||
[[package]]
|
||||
name = "ttf-parser"
|
||||
version = "0.25.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31"
|
||||
|
||||
[[package]]
|
||||
name = "type1-encoding-parser"
|
||||
version = "0.1.0"
|
||||
@@ -5586,6 +5647,12 @@ version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-general-category"
|
||||
version = "1.1.0"
|
||||
@@ -5613,6 +5680,12 @@ dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-properties"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.12.0"
|
||||
@@ -6452,7 +6525,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9993aa5be5a26815fe2c3eacfc1fde061fc1a1f094bf1ad2a18bf9c495dd7414"
|
||||
dependencies = [
|
||||
"gethostname",
|
||||
"rustix 1.1.3",
|
||||
"rustix 1.1.4",
|
||||
"x11rb-protocol",
|
||||
]
|
||||
|
||||
@@ -6469,7 +6542,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rustix 1.1.3",
|
||||
"rustix 1.1.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6529,7 +6602,7 @@ dependencies = [
|
||||
"hex",
|
||||
"nix 0.29.0",
|
||||
"ordered-stream",
|
||||
"rand",
|
||||
"rand 0.8.6",
|
||||
"serde",
|
||||
"serde_repr",
|
||||
"sha1",
|
||||
@@ -6669,15 +6742,15 @@ checksum = "2fc5a66a20078bf1251bde995aa2fdcc4b800c70b5d92dd2c62abc5c60f679f8"
|
||||
|
||||
[[package]]
|
||||
name = "zune-core"
|
||||
version = "0.4.12"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a"
|
||||
checksum = "cb8a0807f7c01457d0379ba880ba6322660448ddebc890ce29bb64da71fb40f9"
|
||||
|
||||
[[package]]
|
||||
name = "zune-jpeg"
|
||||
version = "0.4.21"
|
||||
version = "0.5.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29ce2c8a9384ad323cf564b67da86e21d3cfdff87908bc1223ed5c99bc792713"
|
||||
checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296"
|
||||
dependencies = [
|
||||
"zune-core",
|
||||
]
|
||||
|
||||
@@ -28,5 +28,5 @@ tracing.workspace = true
|
||||
uuid.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.16"
|
||||
tempfile = "3.27"
|
||||
tower = "0.5"
|
||||
|
||||
@@ -36,7 +36,7 @@ rustls.workspace = true
|
||||
semver.workspace = true
|
||||
tokio.workspace = true
|
||||
sha2.workspace = true
|
||||
tempfile = "3.16"
|
||||
tempfile = "3.27"
|
||||
tracing.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -23,4 +23,4 @@ keyring = { version = "3", features = ["windows-native"] }
|
||||
keyring = { version = "3", features = ["linux-native-sync-persistent", "crypto-rust"] }
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.16"
|
||||
tempfile = "3.27"
|
||||
|
||||
@@ -55,7 +55,7 @@ unicode-width = "0.2"
|
||||
unicode-segmentation = "1.12"
|
||||
uuid = { version = "1.11", features = ["v4"] }
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
tempfile = "3.16"
|
||||
tempfile = "3.27"
|
||||
thiserror = "2.0"
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { workspace = true }
|
||||
@@ -68,7 +68,7 @@ ignore = "0.4"
|
||||
image = { version = "0.25", default-features = false, features = ["png"] }
|
||||
lru = "0.16"
|
||||
parking_lot = "0.12"
|
||||
pdf-extract = "0.7"
|
||||
pdf-extract = "0.10"
|
||||
tar = "0.4"
|
||||
flate2 = "1.1"
|
||||
sha2 = "0.10"
|
||||
|
||||
@@ -22,6 +22,7 @@ impl CommandGroup for UtilityCommands {
|
||||
Box::new(FunctionCommand::new(&JOBS_INFO, run_jobs)),
|
||||
Box::new(FunctionCommand::new(&MCP_INFO, run_mcp)),
|
||||
Box::new(FunctionCommand::new(&NETWORK_INFO, run_network)),
|
||||
Box::new(FunctionCommand::new(&PLUGINS_INFO, run_plugins)),
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -56,6 +57,12 @@ static NETWORK_INFO: CommandInfo = CommandInfo {
|
||||
usage: "/network [list|allow <host>|deny <host>|remove <host>|default <allow|deny|prompt>]",
|
||||
description_id: MessageId::CmdNetworkDescription,
|
||||
};
|
||||
static PLUGINS_INFO: CommandInfo = CommandInfo {
|
||||
name: "plugins",
|
||||
aliases: &["plugin"],
|
||||
usage: "/plugins [name]",
|
||||
description_id: MessageId::CmdPluginDescription,
|
||||
};
|
||||
|
||||
fn run_registered(app: &mut App, name: &str, arg: Option<&str>) -> CommandResult {
|
||||
dispatch(app, name, arg).expect("registered utility command should dispatch")
|
||||
@@ -76,6 +83,9 @@ fn run_mcp(app: &mut App, arg: Option<&str>) -> CommandResult {
|
||||
fn run_network(app: &mut App, arg: Option<&str>) -> CommandResult {
|
||||
run_registered(app, "network", arg)
|
||||
}
|
||||
fn run_plugins(app: &mut App, arg: Option<&str>) -> CommandResult {
|
||||
run_registered(app, "plugins", arg)
|
||||
}
|
||||
|
||||
pub(in crate::commands) fn dispatch(
|
||||
app: &mut App,
|
||||
@@ -88,6 +98,7 @@ pub(in crate::commands) fn dispatch(
|
||||
"jobs" | "job" | "zuoye" => jobs::jobs(app, arg),
|
||||
"mcp" => mcp::mcp(app, arg),
|
||||
"network" => network::network(app, arg),
|
||||
"plugins" | "plugin" => crate::commands::plugins::plugins(app, arg),
|
||||
_ => return None,
|
||||
};
|
||||
Some(result)
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
//! fall-through behaviour.
|
||||
|
||||
mod groups;
|
||||
mod plugins;
|
||||
pub mod traits;
|
||||
pub mod user_commands;
|
||||
|
||||
|
||||
@@ -0,0 +1,256 @@
|
||||
//! `/plugins` slash command — list and inspect script plugin tools.
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::commands::CommandResult;
|
||||
use crate::config::Config;
|
||||
use crate::localization::{MessageId, tr};
|
||||
use crate::tools::plugin::scan_plugin_dir;
|
||||
use crate::tui::app::App;
|
||||
|
||||
/// List discovered plugins, or show details for a named plugin.
|
||||
pub fn plugins(app: &mut App, arg: Option<&str>) -> CommandResult {
|
||||
let Some(plugin_dir) = plugin_dir_for(app) else {
|
||||
return CommandResult::error(
|
||||
"Could not resolve plugin directory. Set [tools].plugin_dir in config.toml or ensure ~/.codewhale/tools exists.".to_string(),
|
||||
);
|
||||
};
|
||||
|
||||
if !plugin_dir.exists() {
|
||||
return CommandResult::message(format!(
|
||||
"No plugin directory found at {}",
|
||||
plugin_dir.display()
|
||||
));
|
||||
}
|
||||
|
||||
let discovered = scan_plugin_dir(&plugin_dir);
|
||||
|
||||
if let Some(name) = arg.map(str::trim).filter(|s| !s.is_empty()) {
|
||||
show_plugin_detail(app, name, &discovered)
|
||||
} else {
|
||||
list_plugins(app, &plugin_dir, &discovered)
|
||||
}
|
||||
}
|
||||
|
||||
fn list_plugins(
|
||||
app: &App,
|
||||
plugin_dir: &std::path::Path,
|
||||
discovered: &[(PathBuf, crate::tools::plugin::PluginMetadata)],
|
||||
) -> CommandResult {
|
||||
if discovered.is_empty() {
|
||||
return CommandResult::message(
|
||||
tr(app.ui_locale, MessageId::CmdPluginNoneFound)
|
||||
.replace("{dir}", &plugin_dir.display().to_string()),
|
||||
);
|
||||
}
|
||||
|
||||
let mut out = String::new();
|
||||
out.push_str(
|
||||
&tr(app.ui_locale, MessageId::CmdPluginListHeader)
|
||||
.replace("{count}", &discovered.len().to_string()),
|
||||
);
|
||||
out.push('\n');
|
||||
|
||||
for (path, meta) in discovered {
|
||||
out.push_str(&format!(
|
||||
"• {} — {}\n {}",
|
||||
meta.name,
|
||||
meta.description,
|
||||
path.display()
|
||||
));
|
||||
out.push('\n');
|
||||
}
|
||||
|
||||
CommandResult::message(out)
|
||||
}
|
||||
|
||||
fn show_plugin_detail(
|
||||
app: &App,
|
||||
name: &str,
|
||||
discovered: &[(PathBuf, crate::tools::plugin::PluginMetadata)],
|
||||
) -> CommandResult {
|
||||
let Some((path, meta)) = discovered.iter().find(|(_, m)| m.name == name) else {
|
||||
return CommandResult::error(
|
||||
tr(app.ui_locale, MessageId::CmdPluginNotFound).replace("{name}", name),
|
||||
);
|
||||
};
|
||||
|
||||
let schema = serde_json::to_string_pretty(&meta.input_schema).unwrap_or_default();
|
||||
let approval = approval_label(meta.approval);
|
||||
|
||||
let mut out = String::new();
|
||||
out.push_str(&format!("{}\n", meta.name));
|
||||
out.push_str(&format!("{:=<40}\n", ""));
|
||||
out.push_str(&format!(
|
||||
"{}\n",
|
||||
tr(app.ui_locale, MessageId::CmdPluginDetailDescription)
|
||||
.replace("{description}", &meta.description)
|
||||
));
|
||||
out.push_str(&format!(
|
||||
"{}\n",
|
||||
tr(app.ui_locale, MessageId::CmdPluginDetailSchema).replace("{schema}", &schema)
|
||||
));
|
||||
out.push_str(&format!(
|
||||
"{}\n",
|
||||
tr(app.ui_locale, MessageId::CmdPluginDetailApproval).replace("{approval}", approval)
|
||||
));
|
||||
out.push_str(&format!(
|
||||
"{}\n",
|
||||
tr(app.ui_locale, MessageId::CmdPluginDetailPath)
|
||||
.replace("{path}", &path.display().to_string())
|
||||
));
|
||||
|
||||
CommandResult::message(out)
|
||||
}
|
||||
|
||||
fn approval_label(approval: crate::tools::spec::ApprovalRequirement) -> &'static str {
|
||||
match approval {
|
||||
crate::tools::spec::ApprovalRequirement::Auto => "auto",
|
||||
crate::tools::spec::ApprovalRequirement::Suggest => "suggest",
|
||||
crate::tools::spec::ApprovalRequirement::Required => "required",
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolve the configured plugin directory, defaulting to `~/.codewhale/tools`.
|
||||
fn plugin_dir_for(app: &App) -> Option<PathBuf> {
|
||||
let config = match &app.config_path {
|
||||
Some(path) => {
|
||||
Config::load(Some(path.clone()), app.config_profile.as_deref()).unwrap_or_default()
|
||||
}
|
||||
None => Config::default(),
|
||||
};
|
||||
|
||||
config
|
||||
.tools
|
||||
.as_ref()
|
||||
.and_then(|tools| tools.plugin_dir.as_ref())
|
||||
.map(PathBuf::from)
|
||||
.or_else(default_codewhale_tools_dir)
|
||||
}
|
||||
|
||||
fn default_codewhale_tools_dir() -> Option<PathBuf> {
|
||||
dirs::home_dir().map(|home| home.join(".codewhale").join("tools"))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::config::Config;
|
||||
use crate::tui::app::{App, TuiOptions};
|
||||
use tempfile::TempDir;
|
||||
|
||||
fn create_test_app_with_plugin_dir(plugin_dir: &std::path::Path) -> (App, TempDir) {
|
||||
let tmp = TempDir::new().expect("tempdir");
|
||||
let config_path = tmp.path().join("config.toml");
|
||||
let tools_dir = plugin_dir
|
||||
.canonicalize()
|
||||
.unwrap_or_else(|_| plugin_dir.to_path_buf());
|
||||
std::fs::write(
|
||||
&config_path,
|
||||
format!(
|
||||
"[tools]\nplugin_dir = {}\n",
|
||||
toml::Value::String(tools_dir.to_string_lossy().to_string())
|
||||
),
|
||||
)
|
||||
.expect("write config");
|
||||
|
||||
let options = TuiOptions {
|
||||
model: "deepseek-v4-pro".to_string(),
|
||||
workspace: tmp.path().to_path_buf(),
|
||||
config_path: Some(config_path),
|
||||
config_profile: None,
|
||||
allow_shell: false,
|
||||
use_alt_screen: true,
|
||||
use_mouse_capture: false,
|
||||
use_bracketed_paste: true,
|
||||
max_subagents: 1,
|
||||
skills_dir: tmp.path().join("skills"),
|
||||
memory_path: tmp.path().join("memory.md"),
|
||||
notes_path: tmp.path().join("notes.txt"),
|
||||
mcp_config_path: tmp.path().join("mcp.json"),
|
||||
use_memory: false,
|
||||
start_in_agent_mode: false,
|
||||
skip_onboarding: true,
|
||||
yolo: false,
|
||||
resume_session_id: None,
|
||||
initial_input: None,
|
||||
};
|
||||
let app = App::new(options, &Config::default());
|
||||
(app, tmp)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_plugins_lists_discovered_tools() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
std::fs::write(
|
||||
dir.path().join("greet.sh"),
|
||||
"# name: greet\n# description: Say hello\n# schema: {\"type\":\"object\"}\n# approval: auto\n",
|
||||
)
|
||||
.unwrap();
|
||||
std::fs::write(
|
||||
dir.path().join("audit.sh"),
|
||||
"# name: audit\n# description: Audit wrapper\n# approval: required\n",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let (mut app, _tmp) = create_test_app_with_plugin_dir(dir.path());
|
||||
let result = plugins(&mut app, None);
|
||||
let msg = result.message.expect("should return list");
|
||||
assert!(msg.contains("Plugin tools (2):"));
|
||||
assert!(msg.contains("greet"));
|
||||
assert!(msg.contains("Say hello"));
|
||||
assert!(msg.contains("audit"));
|
||||
assert!(msg.contains("Audit wrapper"));
|
||||
assert!(msg.contains("greet.sh"));
|
||||
assert!(!result.is_error);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_plugins_empty_directory() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let (mut app, _tmp) = create_test_app_with_plugin_dir(dir.path());
|
||||
let result = plugins(&mut app, None);
|
||||
let msg = result.message.expect("should return message");
|
||||
assert!(msg.contains("No plugin tools discovered"));
|
||||
assert!(msg.contains(&dir.path().canonicalize().unwrap().display().to_string()));
|
||||
assert!(!result.is_error);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_plugins_detail_shows_metadata() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
std::fs::write(
|
||||
dir.path().join("tool.sh"),
|
||||
"# name: my-tool\n# description: Does a thing\n# schema: {\"type\":\"object\",\"properties\":{\"x\":{\"type\":\"string\"}}}\n# approval: required\n",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let (mut app, _tmp) = create_test_app_with_plugin_dir(dir.path());
|
||||
let result = plugins(&mut app, Some("my-tool"));
|
||||
let msg = result.message.expect("should return detail");
|
||||
assert!(msg.contains("my-tool"));
|
||||
assert!(msg.contains("Does a thing"));
|
||||
assert!(msg.contains("\"type\": \"object\""));
|
||||
assert!(msg.contains("\"x\""));
|
||||
assert!(msg.contains("required"));
|
||||
assert!(msg.contains("tool.sh"));
|
||||
assert!(!result.is_error);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_plugins_detail_not_found() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
std::fs::write(
|
||||
dir.path().join("existing.sh"),
|
||||
"# name: existing\n# description: exists\n",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let (mut app, _tmp) = create_test_app_with_plugin_dir(dir.path());
|
||||
let result = plugins(&mut app, Some("missing"));
|
||||
assert!(result.is_error);
|
||||
let msg = result.message.expect("should return error");
|
||||
assert!(msg.contains("missing"));
|
||||
assert!(msg.contains("not found"));
|
||||
}
|
||||
}
|
||||
@@ -312,6 +312,14 @@ pub enum MessageId {
|
||||
CmdLogoutDescription,
|
||||
CmdMcpDescription,
|
||||
CmdMemoryDescription,
|
||||
CmdPluginDescription,
|
||||
CmdPluginNoneFound,
|
||||
CmdPluginNotFound,
|
||||
CmdPluginListHeader,
|
||||
CmdPluginDetailDescription,
|
||||
CmdPluginDetailSchema,
|
||||
CmdPluginDetailApproval,
|
||||
CmdPluginDetailPath,
|
||||
CmdModeDescription,
|
||||
CmdModelDescription,
|
||||
CmdModelsDescription,
|
||||
@@ -741,6 +749,14 @@ pub const ALL_MESSAGE_IDS: &[MessageId] = &[
|
||||
MessageId::CmdLoadDescription,
|
||||
MessageId::CmdLogoutDescription,
|
||||
MessageId::CmdMcpDescription,
|
||||
MessageId::CmdPluginDescription,
|
||||
MessageId::CmdPluginNoneFound,
|
||||
MessageId::CmdPluginNotFound,
|
||||
MessageId::CmdPluginListHeader,
|
||||
MessageId::CmdPluginDetailDescription,
|
||||
MessageId::CmdPluginDetailSchema,
|
||||
MessageId::CmdPluginDetailApproval,
|
||||
MessageId::CmdPluginDetailPath,
|
||||
MessageId::CmdMemoryDescription,
|
||||
MessageId::CmdModeDescription,
|
||||
MessageId::CmdModelDescription,
|
||||
@@ -1375,6 +1391,14 @@ fn english(id: MessageId) -> &'static str {
|
||||
MessageId::CmdLoadDescription => "Load session from file",
|
||||
MessageId::CmdLogoutDescription => "Clear API key and return to setup",
|
||||
MessageId::CmdMcpDescription => "Open or manage MCP servers",
|
||||
MessageId::CmdPluginDescription => "List discovered plugin tools or show details for one",
|
||||
MessageId::CmdPluginNoneFound => "No plugin tools discovered in {dir}",
|
||||
MessageId::CmdPluginNotFound => "Plugin '{name}' not found",
|
||||
MessageId::CmdPluginListHeader => "Plugin tools ({count}):",
|
||||
MessageId::CmdPluginDetailDescription => "Description: {description}",
|
||||
MessageId::CmdPluginDetailSchema => "Schema:\n{schema}",
|
||||
MessageId::CmdPluginDetailApproval => "Approval: {approval}",
|
||||
MessageId::CmdPluginDetailPath => "Path: {path}",
|
||||
MessageId::CmdMemoryDescription => "Inspect or manage the persistent user-memory file",
|
||||
MessageId::CmdModeDescription => {
|
||||
"Switch mode or open picker: /mode [agent|plan|yolo|1|2|3]"
|
||||
@@ -1973,6 +1997,14 @@ fn vietnamese(id: MessageId) -> Option<&'static str> {
|
||||
MessageId::CmdLoadDescription => "Tải phiên làm việc từ tệp",
|
||||
MessageId::CmdLogoutDescription => "Xóa khóa API và quay lại bước thiết lập",
|
||||
MessageId::CmdMcpDescription => "Mở hoặc quản lý các máy chủ MCP",
|
||||
MessageId::CmdPluginDescription => "List discovered plugin tools or show details for one",
|
||||
MessageId::CmdPluginNoneFound => "No plugin tools discovered in {dir}",
|
||||
MessageId::CmdPluginNotFound => "Plugin '{name}' not found",
|
||||
MessageId::CmdPluginListHeader => "Plugin tools ({count}):",
|
||||
MessageId::CmdPluginDetailDescription => "Description: {description}",
|
||||
MessageId::CmdPluginDetailSchema => "Schema:\n{schema}",
|
||||
MessageId::CmdPluginDetailApproval => "Approval: {approval}",
|
||||
MessageId::CmdPluginDetailPath => "Path: {path}",
|
||||
MessageId::CmdMemoryDescription => "Kiểm tra hoặc quản lý tệp bộ nhớ người dùng liên tục",
|
||||
MessageId::CmdModeDescription => {
|
||||
"Chuyển đổi chế độ hoặc mở bảng chọn: /mode [agent|plan|yolo|1|2|3]"
|
||||
@@ -2468,6 +2500,14 @@ fn vietnamese(id: MessageId) -> Option<&'static str> {
|
||||
fn traditional_chinese(id: MessageId) -> Option<&'static str> {
|
||||
Some(match id {
|
||||
MessageId::CmdRelayDescription => "為新執行緒建立會話接力摘要",
|
||||
MessageId::CmdPluginDescription => "List discovered plugin tools or show details for one",
|
||||
MessageId::CmdPluginNoneFound => "No plugin tools discovered in {dir}",
|
||||
MessageId::CmdPluginNotFound => "Plugin '{name}' not found",
|
||||
MessageId::CmdPluginListHeader => "Plugin tools ({count}):",
|
||||
MessageId::CmdPluginDetailDescription => "Description: {description}",
|
||||
MessageId::CmdPluginDetailSchema => "Schema:\n{schema}",
|
||||
MessageId::CmdPluginDetailApproval => "Approval: {approval}",
|
||||
MessageId::CmdPluginDetailPath => "Path: {path}",
|
||||
MessageId::CmdTranslateDescription => "切換輸出翻譯為目前系統語言的開關狀態",
|
||||
MessageId::CmdTranslateOff => "輸出翻譯已關閉(顯示原始模型輸出)",
|
||||
MessageId::CmdTranslateOn => "輸出翻譯已開啟:模型回覆將以繁體中文顯示",
|
||||
@@ -2762,6 +2802,14 @@ fn japanese(id: MessageId) -> Option<&'static str> {
|
||||
MessageId::CmdLoadDescription => "ファイルからセッションを読み込み",
|
||||
MessageId::CmdLogoutDescription => "API キーを消去してセットアップに戻る",
|
||||
MessageId::CmdMcpDescription => "MCP サーバを開く・管理する",
|
||||
MessageId::CmdPluginDescription => "List discovered plugin tools or show details for one",
|
||||
MessageId::CmdPluginNoneFound => "No plugin tools discovered in {dir}",
|
||||
MessageId::CmdPluginNotFound => "Plugin '{name}' not found",
|
||||
MessageId::CmdPluginListHeader => "Plugin tools ({count}):",
|
||||
MessageId::CmdPluginDetailDescription => "Description: {description}",
|
||||
MessageId::CmdPluginDetailSchema => "Schema:\n{schema}",
|
||||
MessageId::CmdPluginDetailApproval => "Approval: {approval}",
|
||||
MessageId::CmdPluginDetailPath => "Path: {path}",
|
||||
MessageId::CmdMemoryDescription => "永続ユーザーメモリファイルを確認・管理",
|
||||
MessageId::CmdModeDescription => {
|
||||
"動作モードを切り替え、または選択画面を開く: /mode [agent|plan|yolo|1|2|3]"
|
||||
@@ -3333,6 +3381,14 @@ fn chinese_simplified(id: MessageId) -> Option<&'static str> {
|
||||
MessageId::CmdLoadDescription => "从文件加载会话",
|
||||
MessageId::CmdLogoutDescription => "清除 API 密钥并返回设置",
|
||||
MessageId::CmdMcpDescription => "打开或管理 MCP 服务器",
|
||||
MessageId::CmdPluginDescription => "List discovered plugin tools or show details for one",
|
||||
MessageId::CmdPluginNoneFound => "No plugin tools discovered in {dir}",
|
||||
MessageId::CmdPluginNotFound => "Plugin '{name}' not found",
|
||||
MessageId::CmdPluginListHeader => "Plugin tools ({count}):",
|
||||
MessageId::CmdPluginDetailDescription => "Description: {description}",
|
||||
MessageId::CmdPluginDetailSchema => "Schema:\n{schema}",
|
||||
MessageId::CmdPluginDetailApproval => "Approval: {approval}",
|
||||
MessageId::CmdPluginDetailPath => "Path: {path}",
|
||||
MessageId::CmdMemoryDescription => "查看或管理持久用户记忆文件",
|
||||
MessageId::CmdModeDescription => "切换运行模式或打开选择器:/mode [agent|plan|yolo|1|2|3]",
|
||||
MessageId::CmdModelDescription => "切换或查看当前模型",
|
||||
@@ -3866,6 +3922,14 @@ fn portuguese_brazil(id: MessageId) -> Option<&'static str> {
|
||||
MessageId::CmdLoadDescription => "Carregar a sessão de um arquivo",
|
||||
MessageId::CmdLogoutDescription => "Limpar a chave de API e voltar à configuração",
|
||||
MessageId::CmdMcpDescription => "Abrir ou gerenciar servidores MCP",
|
||||
MessageId::CmdPluginDescription => "List discovered plugin tools or show details for one",
|
||||
MessageId::CmdPluginNoneFound => "No plugin tools discovered in {dir}",
|
||||
MessageId::CmdPluginNotFound => "Plugin '{name}' not found",
|
||||
MessageId::CmdPluginListHeader => "Plugin tools ({count}):",
|
||||
MessageId::CmdPluginDetailDescription => "Description: {description}",
|
||||
MessageId::CmdPluginDetailSchema => "Schema:\n{schema}",
|
||||
MessageId::CmdPluginDetailApproval => "Approval: {approval}",
|
||||
MessageId::CmdPluginDetailPath => "Path: {path}",
|
||||
MessageId::CmdMemoryDescription => {
|
||||
"Inspecionar ou gerenciar o arquivo persistente de memória do usuário"
|
||||
}
|
||||
@@ -4481,6 +4545,14 @@ fn spanish_latin_america(id: MessageId) -> Option<&'static str> {
|
||||
MessageId::CmdLoadDescription => "Cargar la sesión desde un archivo",
|
||||
MessageId::CmdLogoutDescription => "Limpiar la clave de API y volver a la configuración",
|
||||
MessageId::CmdMcpDescription => "Abrir o gestionar servidores MCP",
|
||||
MessageId::CmdPluginDescription => "List discovered plugin tools or show details for one",
|
||||
MessageId::CmdPluginNoneFound => "No plugin tools discovered in {dir}",
|
||||
MessageId::CmdPluginNotFound => "Plugin '{name}' not found",
|
||||
MessageId::CmdPluginListHeader => "Plugin tools ({count}):",
|
||||
MessageId::CmdPluginDetailDescription => "Description: {description}",
|
||||
MessageId::CmdPluginDetailSchema => "Schema:\n{schema}",
|
||||
MessageId::CmdPluginDetailApproval => "Approval: {approval}",
|
||||
MessageId::CmdPluginDetailPath => "Path: {path}",
|
||||
MessageId::CmdMemoryDescription => {
|
||||
"Inspeccionar o gestionar el archivo persistente de memoria del usuario"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user