Radish alpha
h
rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5
Radicle Heartwood Protocol & Stack
Radicle
Git
cli/node/status: Also print link direction
Merged lorenz opened 11 months ago

On nodes with only outgoing connections, this won’t be very interesting. But on seed nodes it sometimes is of interest in which direction the connections are going.

Also, I hope that in the future we will enable more and more nodes to connect directly to each other.

The table header “Dir.” is an abbreviation for “Link Direction”.

I took the liberty to also shorten NIDs.

14 files changed +1058 -54 ee12f76c 5a2f26ea
modified Cargo.lock
@@ -3,6 +3,21 @@
version = 4

[[package]]
+
name = "addr2line"
+
version = "0.22.0"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678"
+
dependencies = [
+
 "gimli",
+
]
+

+
[[package]]
+
name = "adler"
+
version = "1.0.2"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
+

+
[[package]]
name = "adler2"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -44,6 +59,20 @@ dependencies = [
]

[[package]]
+
name = "ahash"
+
version = "0.8.11"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
+
dependencies = [
+
 "cfg-if",
+
 "getrandom",
+
 "once_cell",
+
 "serde",
+
 "version_check",
+
 "zerocopy",
+
]
+

+
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -184,6 +213,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"

[[package]]
+
name = "backtrace"
+
version = "0.3.73"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a"
+
dependencies = [
+
 "addr2line",
+
 "cc",
+
 "cfg-if",
+
 "libc",
+
 "miniz_oxide 0.7.4",
+
 "object",
+
 "rustc-demangle",
+
]
+

+
[[package]]
name = "base-x"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -237,6 +281,21 @@ dependencies = [
]

[[package]]
+
name = "bit-set"
+
version = "0.8.0"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
+
dependencies = [
+
 "bit-vec",
+
]
+

+
[[package]]
+
name = "bit-vec"
+
version = "0.8.0"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
+

+
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -286,6 +345,12 @@ dependencies = [
]

[[package]]
+
name = "borrow-or-share"
+
version = "0.2.2"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "3eeab4423108c5d7c744f4d234de88d18d636100093ae04caf4825134b9c3a32"
+

+
[[package]]
name = "bstr"
version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -303,12 +368,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"

[[package]]
+
name = "bytecount"
+
version = "0.6.8"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce"
+

+
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"

[[package]]
+
name = "bytes"
+
version = "1.10.1"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
+

+
[[package]]
name = "bytesize"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -656,6 +733,15 @@ dependencies = [
]

[[package]]
+
name = "email_address"
+
version = "0.2.9"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "e079f19b08ca6239f47f8ba8509c11cf3ea30095831f7fed61441475edd8c449"
+
dependencies = [
+
 "serde",
+
]
+

+
[[package]]
name = "emojis"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -693,6 +779,17 @@ dependencies = [
]

[[package]]
+
name = "fancy-regex"
+
version = "0.14.0"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "6e24cb5a94bcae1e5408b0effca5cd7172ea3c5755049c5f3af4cd283a165298"
+
dependencies = [
+
 "bit-set",
+
 "regex-automata",
+
 "regex-syntax",
+
]
+

+
[[package]]
name = "faster-hex"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -736,10 +833,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
dependencies = [
 "crc32fast",
-
 "miniz_oxide",
+
 "miniz_oxide 0.8.8",
]

[[package]]
+
name = "fluent-uri"
+
version = "0.3.2"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "1918b65d96df47d3591bed19c5cca17e3fa5d0707318e4b5ef2eae01764df7e5"
+
dependencies = [
+
 "borrow-or-share",
+
 "ref-cast",
+
 "serde",
+
]
+

+
[[package]]
+
name = "fnv"
+
version = "1.0.7"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+

+
[[package]]
name = "form_urlencoded"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -749,6 +863,66 @@ dependencies = [
]

[[package]]
+
name = "fraction"
+
version = "0.15.3"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "0f158e3ff0a1b334408dc9fb811cd99b446986f4d8b741bb08f9df1604085ae7"
+
dependencies = [
+
 "lazy_static",
+
 "num",
+
]
+

+
[[package]]
+
name = "futures-channel"
+
version = "0.3.31"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
+
dependencies = [
+
 "futures-core",
+
 "futures-sink",
+
]
+

+
[[package]]
+
name = "futures-core"
+
version = "0.3.31"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
+

+
[[package]]
+
name = "futures-io"
+
version = "0.3.31"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
+

+
[[package]]
+
name = "futures-sink"
+
version = "0.3.31"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
+

+
[[package]]
+
name = "futures-task"
+
version = "0.3.31"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
+

+
[[package]]
+
name = "futures-util"
+
version = "0.3.31"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
+
dependencies = [
+
 "futures-core",
+
 "futures-io",
+
 "futures-sink",
+
 "futures-task",
+
 "memchr",
+
 "pin-project-lite",
+
 "pin-utils",
+
 "slab",
+
]
+

+
[[package]]
name = "fxhash"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -790,6 +964,12 @@ dependencies = [
]

[[package]]
+
name = "gimli"
+
version = "0.29.0"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
+

+
[[package]]
name = "git-ref-format"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1346,6 +1526,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"

[[package]]
+
name = "hermit-abi"
+
version = "0.3.9"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
+

+
[[package]]
name = "hmac"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1364,6 +1550,84 @@ dependencies = [
]

[[package]]
+
name = "http"
+
version = "1.3.1"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565"
+
dependencies = [
+
 "bytes",
+
 "fnv",
+
 "itoa",
+
]
+

+
[[package]]
+
name = "http-body"
+
version = "1.0.1"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
+
dependencies = [
+
 "bytes",
+
 "http",
+
]
+

+
[[package]]
+
name = "http-body-util"
+
version = "0.1.3"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
+
dependencies = [
+
 "bytes",
+
 "futures-core",
+
 "http",
+
 "http-body",
+
 "pin-project-lite",
+
]
+

+
[[package]]
+
name = "httparse"
+
version = "1.10.1"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
+

+
[[package]]
+
name = "hyper"
+
version = "1.6.0"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80"
+
dependencies = [
+
 "bytes",
+
 "futures-channel",
+
 "futures-util",
+
 "http",
+
 "http-body",
+
 "httparse",
+
 "itoa",
+
 "pin-project-lite",
+
 "smallvec",
+
 "tokio",
+
 "want",
+
]
+

+
[[package]]
+
name = "hyper-util"
+
version = "0.1.10"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4"
+
dependencies = [
+
 "bytes",
+
 "futures-channel",
+
 "futures-util",
+
 "http",
+
 "http-body",
+
 "hyper",
+
 "pin-project-lite",
+
 "socket2",
+
 "tokio",
+
 "tower-service",
+
 "tracing",
+
]
+

+
[[package]]
name = "iana-time-zone"
version = "0.1.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1575,6 +1839,12 @@ dependencies = [
]

[[package]]
+
name = "ipnet"
+
version = "2.11.0"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
+

+
[[package]]
name = "itoa"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1620,14 +1890,42 @@ dependencies = [

[[package]]
name = "js-sys"
-
version = "0.3.69"
+
version = "0.3.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
-
checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
+
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
dependencies = [
+
 "once_cell",
 "wasm-bindgen",
]

[[package]]
+
name = "jsonschema"
+
version = "0.30.0"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "f1b46a0365a611fbf1d2143104dcf910aada96fafd295bab16c60b802bf6fa1d"
+
dependencies = [
+
 "ahash",
+
 "base64 0.22.1",
+
 "bytecount",
+
 "email_address",
+
 "fancy-regex",
+
 "fraction",
+
 "idna",
+
 "itoa",
+
 "num-cmp",
+
 "num-traits",
+
 "once_cell",
+
 "percent-encoding",
+
 "referencing",
+
 "regex",
+
 "regex-syntax",
+
 "reqwest",
+
 "serde",
+
 "serde_json",
+
 "uuid-simd",
+
]
+

+
[[package]]
name = "keccak"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1762,6 +2060,21 @@ dependencies = [
]

[[package]]
+
name = "mime"
+
version = "0.3.17"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
+

+
[[package]]
+
name = "miniz_oxide"
+
version = "0.7.4"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
+
dependencies = [
+
 "adler",
+
]
+

+
[[package]]
name = "miniz_oxide"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1771,6 +2084,18 @@ dependencies = [
]

[[package]]
+
name = "mio"
+
version = "1.0.2"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
+
dependencies = [
+
 "hermit-abi",
+
 "libc",
+
 "wasi",
+
 "windows-sys 0.52.0",
+
]
+

+
[[package]]
name = "multibase"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1837,6 +2162,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be"

[[package]]
+
name = "num"
+
version = "0.4.3"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23"
+
dependencies = [
+
 "num-bigint",
+
 "num-complex",
+
 "num-integer",
+
 "num-iter",
+
 "num-rational",
+
 "num-traits",
+
]
+

+
[[package]]
+
name = "num-bigint"
+
version = "0.4.6"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
+
dependencies = [
+
 "num-integer",
+
 "num-traits",
+
]
+

+
[[package]]
name = "num-bigint-dig"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1854,6 +2203,21 @@ dependencies = [
]

[[package]]
+
name = "num-cmp"
+
version = "0.1.0"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "63335b2e2c34fae2fb0aa2cecfd9f0832a1e24b3b32ecec612c3426d46dc8aaa"
+

+
[[package]]
+
name = "num-complex"
+
version = "0.4.6"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
+
dependencies = [
+
 "num-traits",
+
]
+

+
[[package]]
name = "num-integer"
version = "0.1.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1864,9 +2228,9 @@ dependencies = [

[[package]]
name = "num-iter"
-
version = "0.1.44"
+
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
-
checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9"
+
checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
dependencies = [
 "autocfg",
 "num-integer",
@@ -1874,10 +2238,21 @@ dependencies = [
]

[[package]]
+
name = "num-rational"
+
version = "0.4.2"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
+
dependencies = [
+
 "num-bigint",
+
 "num-integer",
+
 "num-traits",
+
]
+

+
[[package]]
name = "num-traits"
-
version = "0.2.18"
+
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-
checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
+
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
 "autocfg",
 "libm",
@@ -1890,10 +2265,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"

[[package]]
+
name = "object"
+
version = "0.36.7"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
+
dependencies = [
+
 "memchr",
+
]
+

+
[[package]]
name = "once_cell"
-
version = "1.19.0"
+
version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
+
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"

[[package]]
name = "opaque-debug"
@@ -1902,6 +2286,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"

[[package]]
+
name = "outref"
+
version = "0.5.2"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e"
+

+
[[package]]
name = "p256"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1941,9 +2331,9 @@ dependencies = [

[[package]]
name = "parking_lot"
-
version = "0.12.1"
+
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
+
checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
dependencies = [
 "lock_api",
 "parking_lot_core",
@@ -2006,6 +2396,18 @@ dependencies = [
]

[[package]]
+
name = "pin-project-lite"
+
version = "0.2.16"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
+

+
[[package]]
+
name = "pin-utils"
+
version = "0.1.0"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+

+
[[package]]
name = "pkcs1"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2190,6 +2592,7 @@ dependencies = [
 "emojis",
 "fastrand",
 "git2",
+
 "jsonschema",
 "libc",
 "localtime",
 "log",
@@ -2203,6 +2606,7 @@ dependencies = [
 "radicle-crypto",
 "radicle-git-ext",
 "radicle-ssh",
+
 "schemars",
 "serde",
 "serde_json",
 "siphasher 1.0.1",
@@ -2232,6 +2636,7 @@ dependencies = [
 "radicle-node",
 "radicle-surf",
 "radicle-term",
+
 "schemars",
 "serde",
 "serde_json",
 "shlex",
@@ -2541,6 +2946,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20145670ba436b55d91fc92d25e71160fbfbdd57831631c8d7d36377a476f1cb"

[[package]]
+
name = "ref-cast"
+
version = "1.0.24"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf"
+
dependencies = [
+
 "ref-cast-impl",
+
]
+

+
[[package]]
+
name = "ref-cast-impl"
+
version = "1.0.24"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7"
+
dependencies = [
+
 "proc-macro2",
+
 "quote",
+
 "syn 2.0.89",
+
]
+

+
[[package]]
+
name = "referencing"
+
version = "0.30.0"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "c8eff4fa778b5c2a57e85c5f2fe3a709c52f0e60d23146e2151cbef5893f420e"
+
dependencies = [
+
 "ahash",
+
 "fluent-uri",
+
 "once_cell",
+
 "parking_lot",
+
 "percent-encoding",
+
 "serde_json",
+
]
+

+
[[package]]
name = "regex"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2570,6 +3009,43 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"

[[package]]
+
name = "reqwest"
+
version = "0.12.15"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb"
+
dependencies = [
+
 "base64 0.22.1",
+
 "bytes",
+
 "futures-channel",
+
 "futures-core",
+
 "futures-util",
+
 "http",
+
 "http-body",
+
 "http-body-util",
+
 "hyper",
+
 "hyper-util",
+
 "ipnet",
+
 "js-sys",
+
 "log",
+
 "mime",
+
 "once_cell",
+
 "percent-encoding",
+
 "pin-project-lite",
+
 "serde",
+
 "serde_json",
+
 "serde_urlencoded",
+
 "sync_wrapper",
+
 "tokio",
+
 "tower",
+
 "tower-service",
+
 "url",
+
 "wasm-bindgen",
+
 "wasm-bindgen-futures",
+
 "web-sys",
+
 "windows-registry",
+
]
+

+
[[package]]
name = "rfc6979"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2601,6 +3077,12 @@ dependencies = [
]

[[package]]
+
name = "rustc-demangle"
+
version = "0.1.24"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
+

+
[[package]]
name = "rustix"
version = "0.38.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2614,6 +3096,12 @@ dependencies = [
]

[[package]]
+
name = "rustversion"
+
version = "1.0.20"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
+

+
[[package]]
name = "ryu"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2638,6 +3126,31 @@ dependencies = [
]

[[package]]
+
name = "schemars"
+
version = "1.0.0-alpha.17"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "88ef2a6523400a2228db974a8ddc9e1d3deaa04f51bddd7832ef8d7e531bafcc"
+
dependencies = [
+
 "dyn-clone",
+
 "ref-cast",
+
 "schemars_derive",
+
 "serde",
+
 "serde_json",
+
]
+

+
[[package]]
+
name = "schemars_derive"
+
version = "1.0.0-alpha.17"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "c6d4e1945a3c9e58edaa708449b026519f7f4197185e1b5dbc689615c1ad724d"
+
dependencies = [
+
 "proc-macro2",
+
 "quote",
+
 "serde_derive_internals",
+
 "syn 2.0.89",
+
]
+

+
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2701,13 +3214,37 @@ dependencies = [
]

[[package]]
+
name = "serde_derive_internals"
+
version = "0.29.1"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
+
dependencies = [
+
 "proc-macro2",
+
 "quote",
+
 "syn 2.0.89",
+
]
+

+
[[package]]
name = "serde_json"
-
version = "1.0.116"
+
version = "1.0.140"
source = "registry+https://github.com/rust-lang/crates.io-index"
-
checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813"
+
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
dependencies = [
 "indexmap",
 "itoa",
+
 "memchr",
+
 "ryu",
+
 "serde",
+
]
+

+
[[package]]
+
name = "serde_urlencoded"
+
version = "0.7.1"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
+
dependencies = [
+
 "form_urlencoded",
+
 "itoa",
 "ryu",
 "serde",
]
@@ -2798,6 +3335,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"

[[package]]
+
name = "slab"
+
version = "0.4.9"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
+
dependencies = [
+
 "autocfg",
+
]
+

+
[[package]]
name = "smallvec"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2981,6 +3527,15 @@ dependencies = [
]

[[package]]
+
name = "sync_wrapper"
+
version = "1.0.2"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
+
dependencies = [
+
 "futures-core",
+
]
+

+
[[package]]
name = "synstructure"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3110,6 +3665,66 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"

[[package]]
+
name = "tokio"
+
version = "1.42.1"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "2209a14885b74764cce87ffa777ffa1b8ce81a3f3166c6f886b83337fe7e077f"
+
dependencies = [
+
 "backtrace",
+
 "libc",
+
 "mio",
+
 "pin-project-lite",
+
 "socket2",
+
 "windows-sys 0.52.0",
+
]
+

+
[[package]]
+
name = "tower"
+
version = "0.5.2"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
+
dependencies = [
+
 "futures-core",
+
 "futures-util",
+
 "pin-project-lite",
+
 "sync_wrapper",
+
 "tokio",
+
 "tower-layer",
+
 "tower-service",
+
]
+

+
[[package]]
+
name = "tower-layer"
+
version = "0.3.3"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
+

+
[[package]]
+
name = "tower-service"
+
version = "0.3.3"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
+

+
[[package]]
+
name = "tracing"
+
version = "0.1.41"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
+
dependencies = [
+
 "pin-project-lite",
+
 "tracing-core",
+
]
+

+
[[package]]
+
name = "tracing-core"
+
version = "0.1.33"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
+
dependencies = [
+
 "once_cell",
+
]
+

+
[[package]]
name = "tree-sitter"
version = "0.24.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3262,6 +3877,12 @@ dependencies = [
]

[[package]]
+
name = "try-lock"
+
version = "0.2.5"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
+

+
[[package]]
name = "typenum"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3343,6 +3964,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"

[[package]]
+
name = "uuid"
+
version = "1.16.0"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9"
+

+
[[package]]
+
name = "uuid-simd"
+
version = "0.8.0"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "23b082222b4f6619906941c17eb2297fff4c2fb96cb60164170522942a200bd8"
+
dependencies = [
+
 "outref",
+
 "uuid",
+
 "vsimd",
+
]
+

+
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3355,6 +3993,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"

[[package]]
+
name = "vsimd"
+
version = "0.8.0"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64"
+

+
[[package]]
name = "walkdir"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3365,6 +4009,15 @@ dependencies = [
]

[[package]]
+
name = "want"
+
version = "0.3.1"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
+
dependencies = [
+
 "try-lock",
+
]
+

+
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3372,23 +4025,24 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"

[[package]]
name = "wasm-bindgen"
-
version = "0.2.92"
+
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
-
checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
+
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
dependencies = [
 "cfg-if",
+
 "once_cell",
+
 "rustversion",
 "wasm-bindgen-macro",
]

[[package]]
name = "wasm-bindgen-backend"
-
version = "0.2.92"
+
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
-
checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
+
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
dependencies = [
 "bumpalo",
 "log",
-
 "once_cell",
 "proc-macro2",
 "quote",
 "syn 2.0.89",
@@ -3396,10 +4050,23 @@ dependencies = [
]

[[package]]
+
name = "wasm-bindgen-futures"
+
version = "0.4.50"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61"
+
dependencies = [
+
 "cfg-if",
+
 "js-sys",
+
 "once_cell",
+
 "wasm-bindgen",
+
 "web-sys",
+
]
+

+
[[package]]
name = "wasm-bindgen-macro"
-
version = "0.2.92"
+
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
-
checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
+
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
dependencies = [
 "quote",
 "wasm-bindgen-macro-support",
@@ -3407,9 +4074,9 @@ dependencies = [

[[package]]
name = "wasm-bindgen-macro-support"
-
version = "0.2.92"
+
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
-
checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
+
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
dependencies = [
 "proc-macro2",
 "quote",
@@ -3420,9 +4087,22 @@ dependencies = [

[[package]]
name = "wasm-bindgen-shared"
-
version = "0.2.92"
+
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
-
checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
+
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
+
dependencies = [
+
 "unicode-ident",
+
]
+

+
[[package]]
+
name = "web-sys"
+
version = "0.3.77"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2"
+
dependencies = [
+
 "js-sys",
+
 "wasm-bindgen",
+
]

[[package]]
name = "winapi-util"
@@ -3443,6 +4123,41 @@ dependencies = [
]

[[package]]
+
name = "windows-link"
+
version = "0.1.1"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
+

+
[[package]]
+
name = "windows-registry"
+
version = "0.4.0"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3"
+
dependencies = [
+
 "windows-result",
+
 "windows-strings",
+
 "windows-targets 0.53.0",
+
]
+

+
[[package]]
+
name = "windows-result"
+
version = "0.3.2"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
+
dependencies = [
+
 "windows-link",
+
]
+

+
[[package]]
+
name = "windows-strings"
+
version = "0.3.1"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319"
+
dependencies = [
+
 "windows-link",
+
]
+

+
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3484,7 +4199,7 @@ dependencies = [
 "windows_aarch64_gnullvm 0.52.5",
 "windows_aarch64_msvc 0.52.5",
 "windows_i686_gnu 0.52.5",
-
 "windows_i686_gnullvm",
+
 "windows_i686_gnullvm 0.52.5",
 "windows_i686_msvc 0.52.5",
 "windows_x86_64_gnu 0.52.5",
 "windows_x86_64_gnullvm 0.52.5",
@@ -3492,6 +4207,22 @@ dependencies = [
]

[[package]]
+
name = "windows-targets"
+
version = "0.53.0"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b"
+
dependencies = [
+
 "windows_aarch64_gnullvm 0.53.0",
+
 "windows_aarch64_msvc 0.53.0",
+
 "windows_i686_gnu 0.53.0",
+
 "windows_i686_gnullvm 0.53.0",
+
 "windows_i686_msvc 0.53.0",
+
 "windows_x86_64_gnu 0.53.0",
+
 "windows_x86_64_gnullvm 0.53.0",
+
 "windows_x86_64_msvc 0.53.0",
+
]
+

+
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3504,6 +4235,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"

[[package]]
+
name = "windows_aarch64_gnullvm"
+
version = "0.53.0"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
+

+
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3516,6 +4253,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"

[[package]]
+
name = "windows_aarch64_msvc"
+
version = "0.53.0"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
+

+
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3528,12 +4271,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"

[[package]]
+
name = "windows_i686_gnu"
+
version = "0.53.0"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3"
+

+
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"

[[package]]
+
name = "windows_i686_gnullvm"
+
version = "0.53.0"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
+

+
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3546,6 +4301,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"

[[package]]
+
name = "windows_i686_msvc"
+
version = "0.53.0"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
+

+
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3558,6 +4319,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"

[[package]]
+
name = "windows_x86_64_gnu"
+
version = "0.53.0"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
+

+
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3570,6 +4337,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"

[[package]]
+
name = "windows_x86_64_gnullvm"
+
version = "0.53.0"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
+

+
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3582,6 +4355,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"

[[package]]
+
name = "windows_x86_64_msvc"
+
version = "0.53.0"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
+

+
[[package]]
name = "winnow"
version = "0.6.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3644,6 +4423,26 @@ dependencies = [
]

[[package]]
+
name = "zerocopy"
+
version = "0.7.35"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
+
dependencies = [
+
 "zerocopy-derive",
+
]
+

+
[[package]]
+
name = "zerocopy-derive"
+
version = "0.7.35"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
+
dependencies = [
+
 "proc-macro2",
+
 "quote",
+
 "syn 2.0.89",
+
]
+

+
[[package]]
name = "zerofrom"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
modified radicle-cli/Cargo.toml
@@ -46,11 +46,12 @@ tree-sitter-bash = { version = "0.23.3" }
tree-sitter-go = { version = "0.23.4" }
tree-sitter-md = { version = "0.3.2" }
zeroize = { version = "1.1" }
+
schemars = { version = "1.0.0-alpha.17" }

[dependencies.radicle]
version = "0"
path = "../radicle"
-
features = ["logger"]
+
features = ["logger", "schemars"]

[dependencies.radicle-cli-test]
version = "0"
modified radicle-cli/src/commands/config.rs
@@ -23,6 +23,7 @@ Usage
    rad config init --alias <alias> [<option>...]
    rad config edit [<option>...]
    rad config get <key> [<option>...]
+
    rad config schema [<option>...]
    rad config set <key> <value> [<option>...]
    rad config unset <key> [<option>...]
    rad config push <key> <value> [<option>...]
@@ -43,6 +44,7 @@ enum Operation {
    #[default]
    Show,
    Get(String),
+
    Schema,
    Set(String, String),
    Push(String, String),
    Remove(String, String),
@@ -79,6 +81,7 @@ impl Args for Options {
                }
                Value(val) if op.is_none() => match val.to_string_lossy().as_ref() {
                    "show" => op = Some(Operation::Show),
+
                    "schema" => op = Some(Operation::Schema),
                    "edit" => op = Some(Operation::Edit),
                    "init" => op = Some(Operation::Init),
                    "get" => {
@@ -140,6 +143,9 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
            let profile = ctx.profile()?;
            term::json::to_pretty(&profile.config, path.as_path())?.print();
        }
+
        Operation::Schema => {
+
            term::json::to_pretty(&schemars::schema_for!(Config), path.as_path())?.print();
+
        }
        Operation::Get(key) => {
            let mut temp_config = RawConfig::from_file(&path)?;
            let key: ConfigPath = key.into();
modified radicle/Cargo.toml
@@ -35,6 +35,7 @@ sqlite = { version = "0.32.0", features = ["bundled"] }
tempfile = { version = "3.3.0" }
thiserror = { version = "1" }
unicode-normalization = { version = "0.1" }
+
schemars = { version = "1.0.0-alpha.17", optional = true}

[dependencies.chrono]
version = "0.4.0"
@@ -75,6 +76,7 @@ emojis = { version = "0.6" }
pretty_assertions = { version = "1.3.0" }
qcheck-macros = { version = "1", default-features = false }
qcheck = { version = "1", default-features = false }
+
jsonschema = { version = "0.30" }

[dev-dependencies.radicle-crypto]
path = "../radicle-crypto"
modified radicle/src/cli.rs
@@ -1,6 +1,11 @@
/// CLI configuration.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
+
#[cfg_attr(
+
    feature = "schemars",
+
    derive(schemars::JsonSchema),
+
    schemars(rename = "CliConfig")
+
)]
pub struct Config {
    /// Whether to show hints or not in the CLI.
    #[serde(default)]
modified radicle/src/explorer.rs
@@ -81,8 +81,9 @@ impl std::fmt::Display for ExplorerUrl {
}

/// A public explorer, eg. `https://app.radicle.xyz`.
-
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
+
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(transparent)]
+
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct Explorer(String);

impl Default for Explorer {
modified radicle/src/identity/doc/id.rs
@@ -20,7 +20,17 @@ pub enum IdError {

/// A repository identifier.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-
pub struct RepoId(git::Oid);
+
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
+
pub struct RepoId(
+
    #[cfg_attr(feature = "schemars", schemars(
+
        with = "String",
+
        description = "A repository identifier. Starts with \"rad:\", followed by a multibase Base58 encoded Git object identifier.",
+
        regex(pattern = r"rad:z[1-9a-km-zA-HJ-NP-Z]+"),
+
        length(min = 5),
+
        example = &"rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5",
+
    ))]
+
    git::Oid,
+
);

impl fmt::Display for RepoId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
modified radicle/src/lib.rs
@@ -23,6 +23,8 @@ pub mod logger;
pub mod node;
pub mod profile;
pub mod rad;
+
#[cfg(feature = "schemars")]
+
pub(crate) mod schemars_ext;
pub mod serde_ext;
pub mod sql;
pub mod storage;
modified radicle/src/node.rs
@@ -180,7 +180,7 @@ impl Penalty {
}

/// Repository sync status for our own refs.
-
#[derive(Debug, PartialEq, Eq, Clone, serde::Serialize, serde::Deserialize)]
+
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
#[serde(tag = "status")]
#[serde(rename_all = "camelCase")]
pub enum SyncStatus {
@@ -220,7 +220,7 @@ impl PartialOrd for SyncStatus {
}

/// Node user agent.
-
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, serde::Serialize, serde::Deserialize)]
+
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Serialize, Deserialize)]
pub struct UserAgent(String);

impl UserAgent {
@@ -290,10 +290,25 @@ impl AsRef<str> for UserAgent {
    }
}

-
/// Node alias.
-
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, serde::Serialize, serde::Deserialize)]
+
/// Node alias, i.e. a short and memorable name for it.
+
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Serialize, Deserialize)]
#[serde(try_from = "String", into = "String")]
-
pub struct Alias(String);
+
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
+
pub struct Alias(
+
    // To exclude control characters, one might be inclined to use the character
+
    // class `[[:cntrl:]]` which is understood by the `regex` crate.
+
    // However, the patterns in JSON schema must conform to ECMA-262, which does
+
    // not specify the character class.
+
    // Thus, we unfold its definition from <https://www.unicode.org/reports/tr18/#cntrl>,
+
    // which refers to the "general category" named "Cc",
+
    // see <https://unicode.org/reports/tr44/#General_Category_Values>.
+
    // We obtain the two ranges below from <https://www.unicode.org/notes/tn36/Categories.txt>.
+
    #[cfg_attr(
+
        feature = "schemars",
+
        schemars(regex(pattern = r"^[^\x00-\x1F\x7F-\x9F\s]{0,32}$"), length(max = 32))
+
    )]
+
    String,
+
);

impl Alias {
    /// Create a new alias from a string. Panics if the string is not a valid alias.
@@ -410,7 +425,7 @@ impl TryFrom<&sqlite::Value> for Alias {
}

/// Options passed to the "connect" node command.
-
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
+
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConnectOptions {
    /// Establish a persistent connection.
    pub persistent: bool,
@@ -499,10 +514,29 @@ impl<T: Serialize> CommandResult<T> {
}

/// Peer public protocol address.
-
#[derive(Wrapper, WrapperMut, Clone, Eq, PartialEq, Debug, Hash, From, Serialize, Deserialize)]
+
#[derive(Clone, Eq, PartialEq, Debug, Hash, From, Wrapper, WrapperMut, Serialize, Deserialize)]
#[wrapper(Deref, Display, FromStr)]
#[wrapper_mut(DerefMut)]
-
pub struct Address(#[serde(with = "crate::serde_ext::string")] NetAddr<HostName>);
+
#[cfg_attr(
+
    feature = "schemars",
+
    derive(schemars::JsonSchema),
+
    schemars(description = "\
+
        An IP address, or a DNS name, or a Tor onion name, followed by the symbol ':', \
+
        followed by a TCP port number.")
+
)]
+
pub struct Address(
+
    #[serde(with = "crate::serde_ext::string")]
+
    #[cfg_attr(feature = "schemars", schemars(
+
        with = "String",
+
        regex(pattern = r"^.+:((6553[0-5])|(655[0-2][0-9])|(65[0-4][0-9]{2})|(6[0-4][0-9]{3})|([1-5][0-9]{4})|([0-5]{0,5})|([0-9]{1,4}))$"),
+
        extend("examples" = [
+
            "xmrhfasfg5suueegrnc4gsgyi2tyclcy5oz7f5drnrodmdtob6t2ioyd.onion:8776",
+
            "seed.example.com:8776",
+
            "192.0.2.0:31337",
+
        ]),
+
    ))]
+
    NetAddr<HostName>,
+
);

impl Address {
    /// Check whether this address is from the local network.
@@ -666,7 +700,7 @@ impl Session {
}

/// A seed for some repository, with metadata about its status.
-
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
+
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Seed {
    /// The Node ID.
@@ -707,7 +741,7 @@ impl Seed {
    }
}

-
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
+
#[derive(Clone, Debug, Serialize, Deserialize)]
/// Represents a set of seeds with associated metadata. Uses an RNG
/// underneath, so every iteration returns a different ordering.
#[serde(into = "Vec<Seed>", from = "Vec<Seed>")]
modified radicle/src/node/config.rs
@@ -5,6 +5,7 @@ use std::{fmt, net};

use cyphernet::addr::PeerAddr;
use localtime::LocalDuration;
+
use serde::{Deserialize, Serialize};
use serde_json as json;

use crate::node;
@@ -57,8 +58,9 @@ pub mod seeds {
}

/// Peer-to-peer network.
-
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
+
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
+
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum Network {
    #[default]
    Main,
@@ -94,16 +96,25 @@ impl Network {
}

/// Configuration parameters defining attributes of minima and maxima.
-
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
+
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
+
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct Limits {
    /// Number of routing table entries before we start pruning.
    pub routing_max_size: usize,
    /// How long to keep a routing table entry before being pruned.
    #[serde(with = "crate::serde_ext::localtime::duration")]
+
    #[cfg_attr(
+
        feature = "schemars",
+
        schemars(with = "crate::schemars_ext::localtime::LocalDuration")
+
    )]
    pub routing_max_age: LocalDuration,
    /// How long to keep a gossip message entry before pruning it.
    #[serde(with = "crate::serde_ext::localtime::duration")]
+
    #[cfg_attr(
+
        feature = "schemars",
+
        schemars(with = "crate::schemars_ext::localtime::LocalDuration")
+
    )]
    pub gossip_max_age: LocalDuration,
    /// Maximum number of concurrent fetches per peer connection.
    pub fetch_concurrency: usize,
@@ -138,10 +149,19 @@ impl Default for Limits {
/// Limiter for byte streams.
///
/// Default: 500MiB
-
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
+
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[serde(into = "String", try_from = "String")]
+
#[cfg_attr(
+
    feature = "schemars",
+
    derive(schemars::JsonSchema),
+
    schemars(transparent)
+
)]
pub struct FetchPackSizeLimit {
+
    #[cfg_attr(
+
        feature = "schemars",
+
        schemars(with = "crate::schemars_ext::bytesize::ByteSize")
+
    )]
    limit: bytesize::ByteSize,
}

@@ -213,8 +233,9 @@ impl Default for FetchPackSizeLimit {
}

/// Connection limits.
-
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
+
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
+
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct ConnectionLimits {
    /// Max inbound connections.
    pub inbound: usize,
@@ -232,16 +253,18 @@ impl Default for ConnectionLimits {
}

/// Rate limts for a single connection.
-
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
+
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
+
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct RateLimit {
    pub fill_rate: f64,
    pub capacity: usize,
}

/// Rate limits for inbound and outbound connections.
-
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
+
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
+
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct RateLimits {
    pub inbound: RateLimit,
    pub outbound: RateLimit,
@@ -263,9 +286,30 @@ impl Default for RateLimits {
}

/// Full address used to connect to a remote node.
-
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, Hash)]
-
#[serde(transparent)]
-
pub struct ConnectAddress(#[serde(with = "crate::serde_ext::string")] PeerAddr<NodeId, Address>);
+
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+
#[cfg_attr(
+
    feature = "schemars",
+
    derive(schemars::JsonSchema),
+
    schemars(description = "\
+
        A node address to connect to. Format: An Ed25519 public key in \
+
        multibase encoding, followed by the symbol '@', followed by an IP \
+
        address, or a DNS name, or a Tor onion name, followed by the symbol \
+
        ':', followed by a TCP port number.")
+
)]
+
pub struct ConnectAddress(
+
    #[serde(with = "crate::serde_ext::string")]
+
    #[schemars(
+
        with = "String",
+
        regex(pattern = r"^.+@.+:((6553[0-5])|(655[0-2][0-9])|(65[0-4][0-9]{2})|(6[0-4][0-9]{3})|([1-5][0-9]{4})|([0-5]{0,5})|([0-9]{1,4}))$"),
+
        extend("examples" = [
+
            "z6MkrLMMsiPWUcNPHcRajuMi9mDfYckSoJyPwwnknocNYPm7@seed.radicle.garden:8776",
+
            "z6MkvUJtYD9dHDJfpevWRT98mzDDpdAtmUjwyDSkyqksUr7C@xmrhfasfg5suueegrnc4gsgyi2tyclcy5oz7f5drnrodmdtob6t2ioyd.onion:8776",
+
            "z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi@seed.example.com:8776",
+
            "z6MkkfM3tPXNPrPevKr3uSiQtHPuwnNhu2yUVjgd2jXVsVz5@192.0.2.0:31337",
+
        ]),
+
    )]
+
    PeerAddr<NodeId, Address>,
+
);

impl From<PeerAddr<NodeId, Address>> for ConnectAddress {
    fn from(value: PeerAddr<NodeId, Address>) -> Self {
@@ -300,8 +344,9 @@ impl Deref for ConnectAddress {
}

/// Peer configuration.
-
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
+
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", tag = "type")]
+
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum PeerConfig {
    /// Static peer set. Connect to the configured peers and maintain the connections.
    Static,
@@ -316,8 +361,9 @@ impl Default for PeerConfig {
}

/// Relay configuration.
-
#[derive(Debug, Copy, Clone, Default, serde::Serialize, serde::Deserialize)]
+
#[derive(Debug, Copy, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
+
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum Relay {
    /// Always relay messages.
    Always,
@@ -329,8 +375,9 @@ pub enum Relay {
}

/// Proxy configuration.
-
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
+
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", tag = "mode")]
+
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum AddressConfig {
    /// Proxy connections to this address type.
    Proxy {
@@ -343,8 +390,9 @@ pub enum AddressConfig {
}

/// Default seeding policy. Applies when no repository policies for the given repo are found.
-
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
+
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", tag = "default")]
+
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum DefaultSeedingPolicy {
    /// Allow seeding.
    Allow {
@@ -379,13 +427,19 @@ impl From<DefaultSeedingPolicy> for SeedingPolicy {
}

/// Service configuration.
-
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
+
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
+
#[cfg_attr(
+
    feature = "schemars",
+
    derive(schemars::JsonSchema),
+
    schemars(rename = "NodeConfig")
+
)]
pub struct Config {
    /// Node alias.
    pub alias: Alias,
-
    /// Address to listen on.
+
    /// Socket address (a combination of IPv4 or IPv6 address and TCP port) to listen on.
    #[serde(default)]
+
    #[cfg_attr(feature = "schemars", schemars(example = &"127.0.0.1:8776"))]
    pub listen: Vec<net::SocketAddr>,
    /// Peer configuration.
    #[serde(default)]
@@ -409,6 +463,10 @@ pub struct Config {
    /// Log level.
    #[serde(default = "defaults::log")]
    #[serde(with = "crate::serde_ext::string")]
+
    #[cfg_attr(
+
        feature = "schemars",
+
        schemars(with = "crate::schemars_ext::log::Level")
+
    )]
    pub log: log::Level,
    /// Whether or not our node should relay messages.
    #[serde(default, deserialize_with = "crate::serde_ext::ok_or_default")]
modified radicle/src/node/policy.rs
@@ -35,7 +35,7 @@ pub struct FollowPolicy {
}

/// Seeding policy of a node or repo.
-
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
+
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", tag = "policy")]
pub enum SeedingPolicy {
    /// Allow seeding.
@@ -159,6 +159,7 @@ impl TryFrom<&sqlite::Value> for Policy {
/// Follow scope of a seeded repository.
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
+
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum Scope {
    /// Seed remotes that are explicitly followed.
    Followed,
modified radicle/src/profile/config.rs
@@ -25,6 +25,7 @@ pub enum ConfigError {
/// Local radicle configuration.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
+
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct Config {
    /// Public explorer. This is used for generating links.
    #[serde(default)]
@@ -360,3 +361,19 @@ impl From<String> for ConfigPath {
        ConfigPath(parts)
    }
}
+

+
#[cfg(test)]
+
#[allow(clippy::unwrap_used)]
+
mod test {
+
    #[test]
+
    fn schema() {
+
        use super::Config;
+
        use crate::prelude::Alias;
+
        use serde_json::to_value;
+

+
        let schema = to_value(schemars::schema_for!(Config)).unwrap();
+
        let config = to_value(Config::new(Alias::new("schema"))).unwrap();
+
        jsonschema::validate(&schema, &config)
+
            .expect("generated configuration should validate under generated JSON Schema");
+
    }
+
}
added radicle/src/schemars_ext.rs
@@ -0,0 +1,59 @@
+
//! This module contains auxiliary definitions for generating JSONSchemas.
+
//! See <https://graham.cool/schemars/examples/5-remote_derive/>.
+
#![allow(dead_code)]
+

+
use schemars::JsonSchema;
+

+
pub(crate) mod log {
+
    use super::*;
+

+
    /// See [`::log::Level`]
+
    #[derive(JsonSchema)]
+
    #[schemars(
+
        remote = "log::Level",
+
        description = "A log level.",
+
        rename_all = "UPPERCASE"
+
    )]
+
    pub(crate) enum Level {
+
        /// Designates very serious errors.
+
        Error,
+
        /// Designates hazardous situations.
+
        Warn,
+
        /// Designates useful information.
+
        Info,
+
        /// Designates lower priority information.
+
        Debug,
+
        /// Designates very low priority, often extremely verbose, information.
+
        Trace,
+
    }
+
}
+

+
pub(crate) mod bytesize {
+
    use super::*;
+

+
    /// See [`::bytesize::ByteSize`] as well as [`::bytesize::parse`].
+
    /// Note that the pattern here is a little more restrictive than
+
    /// the actual parsing logic, as it enforces particular casing and whitespace.
+
    /// However, the regular expression is easier to read.
+
    #[derive(JsonSchema)]
+
    #[schemars(
+
        remote = "bytesize::ByteSize",
+
        description = "Byte quantities using unit prefixes according to SI or ISO/IEC 80000-13.",
+
        extend("examples" = ["7 G", "50.3 TiB", "200 B", "4 Ki", "10 MB"]),
+
    )]
+
    pub(crate) struct ByteSize(
+
        #[schemars(regex(pattern = r"^\d+(\.\d+)? ((K|M|G|T|P)i?B?|B)$"))] String,
+
    );
+
}
+

+
pub(crate) mod localtime {
+
    use super::*;
+

+
    /// See [`::localtime::LocalDuration`]
+
    #[derive(JsonSchema)]
+
    #[schemars(
+
        remote = "localtime::LocalDuration",
+
        description = "A time duration measured locally in milliseconds."
+
    )]
+
    pub(crate) struct LocalDuration(u64);
+
}
modified radicle/src/web.rs
@@ -7,17 +7,25 @@ use crate::prelude::RepoId;
/// Web configuration.
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
+
#[cfg_attr(
+
    feature = "schemars",
+
    derive(schemars::JsonSchema),
+
    schemars(rename = "WebConfig")
+
)]
pub struct Config {
    /// Pinned content.
    pub pinned: Pinned,
    /// URL pointing to an image used in the header of a node page.
    #[serde(default, skip_serializing_if = "Option::is_none")]
+
    #[cfg_attr(feature = "schemars", schemars(url))]
    pub banner_url: Option<String>,
    /// URL pointing to an image used as the node avatar.
    #[serde(default, skip_serializing_if = "Option::is_none")]
+
    #[cfg_attr(feature = "schemars", schemars(url))]
    pub avatar_url: Option<String>,
    /// Node description.
    #[serde(default, skip_serializing_if = "Option::is_none")]
+
    #[cfg_attr(feature = "schemars", schemars(url))]
    pub description: Option<String>,
}

@@ -25,6 +33,7 @@ pub struct Config {
/// listing, e.g. pin repositories on a web client.
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
+
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct Pinned {
    /// Pinned repositories.
    pub repositories: HashSet<RepoId>,