diff --git a/.codex/skills/code-review-context/SKILL.md b/.codex/skills/code-review-context/SKILL.md index 3d33192ec5..7faf3d7cd2 100644 --- a/.codex/skills/code-review-context/SKILL.md +++ b/.codex/skills/code-review-context/SKILL.md @@ -10,3 +10,4 @@ Codex maintains a context (history of messages) that is sent to the model in inf 3. No unbounded items - everything injected in the model context must have a bounded size and a hard cap. 4. No items larger than 10K tokens. 5. Highlight new individual items that can cross >1k tokens as P0. These need an additional manual review. +6. All injected fragments must be defined as structs in `core/context` and implement ContextualUserFragment trait \ No newline at end of file diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index b085bb68b4..1dbc873796 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -732,6 +732,7 @@ "clap_lex_1.0.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"automod\",\"req\":\"^1.0.14\"}],\"features\":{}}", "clap_lex_1.1.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"automod\",\"req\":\"^1.0.16\"}],\"features\":{}}", "clipboard-win_5.4.1": "{\"dependencies\":[{\"name\":\"error-code\",\"req\":\"^3\",\"target\":\"cfg(windows)\"},{\"name\":\"windows-win\",\"optional\":true,\"req\":\"^3\",\"target\":\"cfg(windows)\"}],\"features\":{\"monitor\":[\"windows-win\"],\"std\":[\"error-code/std\"]}}", + "clru_0.6.3": "{\"dependencies\":[{\"name\":\"hashbrown\",\"req\":\"^0.16\"}],\"features\":{}}", "cmake_0.1.57": "{\"dependencies\":[{\"name\":\"cc\",\"req\":\"^1.2.46\"}],\"features\":{}}", "cmp_any_0.8.1": "{\"dependencies\":[],\"features\":{}}", "codespan-reporting_0.13.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"insta\",\"req\":\"^1.6.3\"},{\"kind\":\"dev\",\"name\":\"peg\",\"req\":\"^0.7\"},{\"kind\":\"dev\",\"name\":\"pico-args\",\"req\":\"^0.5.0\"},{\"kind\":\"dev\",\"name\":\"rustyline\",\"req\":\"^6\"},{\"default_features\":false,\"features\":[\"derive\",\"alloc\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"termcolor\",\"optional\":true,\"req\":\"^1.0.4\"},{\"name\":\"unicode-width\",\"req\":\">=0.1, <0.3\"},{\"kind\":\"dev\",\"name\":\"unindent\",\"req\":\"^0.1\"}],\"features\":{\"ascii-only\":[],\"default\":[\"std\",\"termcolor\"],\"serialization\":[\"serde\"],\"std\":[\"serde?/std\"],\"termcolor\":[\"std\",\"dep:termcolor\"]}}", @@ -797,6 +798,7 @@ "darling_macro_0.20.11": "{\"dependencies\":[{\"name\":\"darling_core\",\"req\":\"=0.20.11\"},{\"name\":\"quote\",\"req\":\"^1.0.18\"},{\"name\":\"syn\",\"req\":\"^2.0.15\"}],\"features\":{}}", "darling_macro_0.21.3": "{\"dependencies\":[{\"name\":\"darling_core\",\"req\":\"=0.21.3\"},{\"name\":\"quote\",\"req\":\"^1.0.18\"},{\"name\":\"syn\",\"req\":\"^2.0.15\"}],\"features\":{}}", "darling_macro_0.23.0": "{\"dependencies\":[{\"name\":\"darling_core\",\"req\":\"=0.23.0\"},{\"name\":\"quote\",\"req\":\"^1.0.18\"},{\"name\":\"syn\",\"req\":\"^2.0.15\"}],\"features\":{}}", + "dashmap_6.1.0": "{\"dependencies\":[{\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1.3.0\"},{\"name\":\"cfg-if\",\"req\":\"^1.0.0\"},{\"name\":\"crossbeam-utils\",\"req\":\"^0.8\"},{\"default_features\":false,\"features\":[\"raw\"],\"name\":\"hashbrown\",\"req\":\"^0.14.0\"},{\"name\":\"lock_api\",\"req\":\"^0.4.10\"},{\"name\":\"once_cell\",\"req\":\"^1.18.0\"},{\"name\":\"parking_lot_core\",\"req\":\"^0.9.8\"},{\"name\":\"rayon\",\"optional\":true,\"req\":\"^1.7.0\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.188\"},{\"default_features\":false,\"name\":\"typesize\",\"optional\":true,\"req\":\"^0.1.8\"}],\"features\":{\"inline\":[\"hashbrown/inline-more\"],\"raw-api\":[],\"typesize\":[\"dep:typesize\"]}}", "dasp_sample_0.11.0": "{\"dependencies\":[],\"features\":{\"default\":[\"std\"],\"std\":[]}}", "data-encoding_2.10.0": "{\"dependencies\":[],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"std\":[\"alloc\"]}}", "dbus-secret-service_4.1.0": "{\"dependencies\":[{\"name\":\"aes\",\"optional\":true,\"req\":\"^0.8\"},{\"features\":[\"std\"],\"name\":\"block-padding\",\"optional\":true,\"req\":\"^0.3\"},{\"features\":[\"block-padding\",\"alloc\"],\"name\":\"cbc\",\"optional\":true,\"req\":\"^0.1\"},{\"name\":\"dbus\",\"req\":\"^0.9\"},{\"name\":\"fastrand\",\"optional\":true,\"req\":\"^2.3\"},{\"name\":\"hkdf\",\"optional\":true,\"req\":\"^0.12\"},{\"name\":\"num\",\"optional\":true,\"req\":\"^0.4\"},{\"name\":\"once_cell\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"openssl\",\"optional\":true,\"req\":\"^0.10.55\"},{\"name\":\"sha2\",\"optional\":true,\"req\":\"^0.10\"},{\"features\":[\"derive\"],\"name\":\"zeroize\",\"req\":\"^1.8\"}],\"features\":{\"crypto-openssl\":[\"dep:fastrand\",\"dep:num\",\"dep:once_cell\",\"dep:openssl\"],\"crypto-rust\":[\"dep:aes\",\"dep:block-padding\",\"dep:cbc\",\"dep:fastrand\",\"dep:hkdf\",\"dep:num\",\"dep:once_cell\",\"dep:sha2\"],\"vendored\":[\"dbus/vendored\",\"openssl?/vendored\"]}}", @@ -871,6 +873,7 @@ "event-listener_5.4.1": "{\"dependencies\":[{\"default_features\":false,\"name\":\"concurrent-queue\",\"req\":\"^2.4.0\"},{\"default_features\":false,\"features\":[\"cargo_bench_support\"],\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.7\"},{\"default_features\":false,\"name\":\"critical-section\",\"optional\":true,\"req\":\"^1.2.0\"},{\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"critical-section\",\"req\":\"^1.2.0\"},{\"kind\":\"dev\",\"name\":\"futures-lite\",\"req\":\"^2.0.0\"},{\"name\":\"loom\",\"optional\":true,\"req\":\"^0.7\",\"target\":\"cfg(loom)\"},{\"name\":\"parking\",\"optional\":true,\"req\":\"^2.0.0\",\"target\":\"cfg(not(target_family = \\\"wasm\\\"))\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2.12\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"portable-atomic-util\",\"optional\":true,\"req\":\"^0.2.0\"},{\"default_features\":false,\"name\":\"portable_atomic_crate\",\"optional\":true,\"package\":\"portable-atomic\",\"req\":\"^1.2.0\"},{\"kind\":\"dev\",\"name\":\"try-lock\",\"req\":\"^0.2.5\"},{\"kind\":\"dev\",\"name\":\"waker-fn\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3\",\"target\":\"cfg(target_family = \\\"wasm\\\")\"}],\"features\":{\"default\":[\"std\"],\"loom\":[\"concurrent-queue/loom\",\"parking?/loom\",\"dep:loom\"],\"portable-atomic\":[\"portable-atomic-util\",\"portable_atomic_crate\",\"concurrent-queue/portable-atomic\"],\"std\":[\"concurrent-queue/std\",\"parking\"]}}", "eventsource-stream_0.2.3": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"futures-core\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"http\",\"req\":\"^0.2\"},{\"default_features\":false,\"name\":\"nom\",\"req\":\"^7.1\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2.8\"},{\"features\":[\"stream\"],\"kind\":\"dev\",\"name\":\"reqwest\",\"req\":\"^0.11\"},{\"features\":[\"macros\",\"rt\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"url\",\"req\":\"^2.2\"}],\"features\":{\"default\":[\"std\"],\"std\":[\"futures-core/std\",\"nom/std\"]}}", "eyre_0.6.12": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0.28\"},{\"kind\":\"dev\",\"name\":\"backtrace\",\"req\":\"^0.3.46\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3\"},{\"name\":\"indenter\",\"req\":\"^0.3.0\"},{\"name\":\"once_cell\",\"req\":\"^1.18.0\"},{\"default_features\":false,\"name\":\"pyo3\",\"optional\":true,\"req\":\"^0.20\"},{\"default_features\":false,\"features\":[\"auto-initialize\"],\"kind\":\"dev\",\"name\":\"pyo3\",\"req\":\"^0.20\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0\"},{\"features\":[\"full\"],\"kind\":\"dev\",\"name\":\"syn\",\"req\":\"^2.0\"},{\"kind\":\"dev\",\"name\":\"thiserror\",\"req\":\"^1.0\"},{\"features\":[\"diff\"],\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.19\"}],\"features\":{\"auto-install\":[],\"default\":[\"auto-install\",\"track-caller\"],\"track-caller\":[]}}", + "faster-hex_0.10.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bytes\",\"req\":\"^1.4.0\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5\"},{\"name\":\"heapless\",\"req\":\"^0.8\",\"target\":\"cfg(not(feature = \\\"alloc\\\"))\"},{\"kind\":\"dev\",\"name\":\"hex\",\"req\":\"^0.3.2\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"rustc-hex\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"}],\"features\":{\"alloc\":[],\"default\":[\"std\",\"serde\"],\"serde\":[\"dep:serde\",\"alloc\"],\"std\":[\"alloc\",\"serde?/std\"]}}", "fastrand_2.3.0": "{\"dependencies\":[{\"features\":[\"js\"],\"name\":\"getrandom\",\"optional\":true,\"req\":\"^0.2\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"},{\"kind\":\"dev\",\"name\":\"getrandom\",\"req\":\"^0.2\"},{\"features\":[\"js\"],\"kind\":\"dev\",\"name\":\"getrandom\",\"req\":\"^0.2\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"},{\"kind\":\"dev\",\"name\":\"wyhash\",\"req\":\"^0.5\"}],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"js\":[\"std\",\"getrandom\"],\"std\":[\"alloc\"]}}", "fax_0.2.6": "{\"dependencies\":[{\"name\":\"fax_derive\",\"req\":\"^0.2.0\"},{\"kind\":\"dev\",\"name\":\"tiff\",\"req\":\"^0.9\"}],\"features\":{\"debug\":[]}}", "fax_derive_0.2.0": "{\"dependencies\":[{\"name\":\"proc-macro2\",\"req\":\"^1.0\"},{\"name\":\"quote\",\"req\":\"^1.0\"},{\"name\":\"syn\",\"req\":\"^2.0\"}],\"features\":{}}", @@ -944,6 +947,59 @@ "git+https://github.com/openai-oss-forks/tungstenite-rs?rev=9200079d3b54a1ff51072e24d81fd354f085156f#9200079d3b54a1ff51072e24d81fd354f085156f_tungstenite": "{\"dependencies\":[{\"name\":\"bytes\"},{\"default_features\":true,\"features\":[],\"name\":\"data-encoding\",\"optional\":true},{\"default_features\":false,\"features\":[\"zlib\"],\"name\":\"flate2\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"headers\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"http\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"httparse\",\"optional\":true},{\"name\":\"log\"},{\"default_features\":true,\"features\":[],\"name\":\"native-tls-crate\",\"optional\":true,\"package\":\"native-tls\"},{\"name\":\"rand\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"rustls\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"rustls-native-certs\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"rustls-pki-types\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"sha1\",\"optional\":true},{\"name\":\"thiserror\"},{\"default_features\":true,\"features\":[],\"name\":\"url\",\"optional\":true},{\"name\":\"utf-8\"},{\"default_features\":true,\"features\":[],\"name\":\"webpki-roots\",\"optional\":true}],\"features\":{\"__rustls-tls\":[\"rustls\",\"rustls-pki-types\"],\"default\":[\"handshake\"],\"deflate\":[\"headers\",\"flate2\"],\"handshake\":[\"data-encoding\",\"headers\",\"httparse\",\"sha1\"],\"headers\":[\"http\",\"dep:headers\"],\"native-tls\":[\"native-tls-crate\"],\"native-tls-vendored\":[\"native-tls\",\"native-tls-crate/vendored\"],\"proxy\":[\"handshake\"],\"rustls-tls-native-roots\":[\"__rustls-tls\",\"rustls-native-certs\"],\"rustls-tls-webpki-roots\":[\"__rustls-tls\",\"webpki-roots\"],\"url\":[\"dep:url\"]},\"strip_prefix\":\"\"}", "git+https://github.com/rust-lang/rust-clippy?rev=20ce69b9a63bcd2756cd906fe0964d1e901e042a#20ce69b9a63bcd2756cd906fe0964d1e901e042a_clippy_utils": "{\"dependencies\":[{\"default_features\":false,\"features\":[],\"name\":\"arrayvec\",\"optional\":false},{\"name\":\"itertools\"},{\"name\":\"rustc_apfloat\"},{\"default_features\":true,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":false}],\"features\":{},\"strip_prefix\":\"clippy_utils\"}", "git2_0.20.4": "{\"dependencies\":[{\"name\":\"bitflags\",\"req\":\"^2.1.0\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"clap\",\"req\":\"^4.4.13\"},{\"name\":\"libc\",\"req\":\"^0.2\"},{\"name\":\"libgit2-sys\",\"req\":\"^0.18.3\"},{\"name\":\"log\",\"req\":\"^0.4.8\"},{\"name\":\"openssl-probe\",\"optional\":true,\"req\":\"^0.1\",\"target\":\"cfg(all(unix, not(target_os = \\\"macos\\\")))\"},{\"name\":\"openssl-sys\",\"optional\":true,\"req\":\"^0.9.45\",\"target\":\"cfg(all(unix, not(target_os = \\\"macos\\\")))\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.1.0\"},{\"features\":[\"formatting\"],\"kind\":\"dev\",\"name\":\"time\",\"req\":\"^0.3.37\"},{\"name\":\"url\",\"req\":\"^2.5.4\"}],\"features\":{\"default\":[\"ssh\",\"https\"],\"https\":[\"libgit2-sys/https\",\"openssl-sys\",\"openssl-probe\"],\"ssh\":[\"libgit2-sys/ssh\"],\"unstable\":[],\"vendored-libgit2\":[\"libgit2-sys/vendored\"],\"vendored-openssl\":[\"openssl-sys/vendored\",\"libgit2-sys/vendored-openssl\"],\"zlib-ng-compat\":[\"libgit2-sys/zlib-ng-compat\"]}}", + "gix-actor_0.40.0": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"std\",\"unicode\"],\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2.0\"},{\"name\":\"gix-date\",\"req\":\"^0.15.0\"},{\"name\":\"gix-error\",\"req\":\"^0.2.0\"},{\"kind\":\"dev\",\"name\":\"pretty_assertions\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.114\"},{\"features\":[\"simd\"],\"name\":\"winnow\",\"req\":\"^0.7.14\"}],\"features\":{\"serde\":[\"dep:serde\",\"bstr/serde\",\"gix-date/serde\"]}}", + "gix-archive_0.30.0": "{\"dependencies\":[{\"default_features\":false,\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2.0\"},{\"default_features\":false,\"features\":[\"zlib-rs\"],\"name\":\"flate2\",\"optional\":true,\"req\":\"^1.1.9\"},{\"name\":\"gix-date\",\"req\":\"^0.15.1\"},{\"name\":\"gix-error\",\"req\":\"^0.2.1\"},{\"name\":\"gix-object\",\"req\":\"^0.58.0\"},{\"name\":\"gix-path\",\"optional\":true,\"req\":\"^0.11.2\"},{\"name\":\"gix-worktree-stream\",\"req\":\"^0.30.0\"},{\"name\":\"rawzip\",\"optional\":true,\"req\":\"^0.4.3\"},{\"name\":\"tar\",\"optional\":true,\"req\":\"^0.4.38\"}],\"features\":{\"default\":[\"tar\",\"tar_gz\",\"zip\"],\"sha1\":[\"gix-worktree-stream/sha1\",\"gix-object/sha1\"],\"tar\":[\"dep:tar\",\"dep:gix-path\"],\"tar_gz\":[\"tar\",\"dep:flate2\"],\"zip\":[\"dep:rawzip\",\"dep:flate2\"]}}", + "gix-attributes_0.31.0": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"std\",\"unicode\"],\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2.1\"},{\"name\":\"gix-glob\",\"req\":\"^0.24.0\"},{\"name\":\"gix-path\",\"req\":\"^0.11.1\"},{\"name\":\"gix-quote\",\"req\":\"^0.7.0\"},{\"name\":\"gix-trace\",\"req\":\"^0.1.18\"},{\"name\":\"kstring\",\"req\":\"^2.0.0\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.114\"},{\"name\":\"smallvec\",\"req\":\"^1.15.1\"},{\"name\":\"thiserror\",\"req\":\"^2.0.18\"},{\"name\":\"unicode-bom\",\"req\":\"^2.0.3\"}],\"features\":{\"serde\":[\"dep:serde\",\"bstr/serde\",\"gix-glob/serde\",\"kstring/serde\"]}}", + "gix-bitmap_0.3.0": "{\"dependencies\":[{\"name\":\"gix-error\",\"req\":\"^0.2.0\"}],\"features\":{}}", + "gix-blame_0.11.0": "{\"dependencies\":[{\"name\":\"gix-commitgraph\",\"req\":\"^0.35.0\"},{\"name\":\"gix-date\",\"req\":\"^0.15.1\"},{\"default_features\":false,\"features\":[\"blob\",\"blob-experimental\"],\"name\":\"gix-diff\",\"req\":\"^0.61.0\"},{\"name\":\"gix-error\",\"req\":\"^0.2.1\"},{\"name\":\"gix-hash\",\"req\":\"^0.23.0\"},{\"name\":\"gix-object\",\"req\":\"^0.58.0\"},{\"name\":\"gix-revwalk\",\"req\":\"^0.29.0\"},{\"name\":\"gix-trace\",\"req\":\"^0.1.18\"},{\"name\":\"gix-traverse\",\"req\":\"^0.55.0\"},{\"default_features\":false,\"features\":[\"attributes\"],\"name\":\"gix-worktree\",\"req\":\"^0.50.0\"},{\"kind\":\"dev\",\"name\":\"pretty_assertions\",\"req\":\"^1.4.0\"},{\"name\":\"smallvec\",\"req\":\"^1.15.1\"},{\"name\":\"thiserror\",\"req\":\"^2.0.18\"}],\"features\":{\"sha1\":[\"gix-commitgraph/sha1\",\"gix-diff/sha1\",\"gix-hash/sha1\",\"gix-object/sha1\",\"gix-revwalk/sha1\",\"gix-traverse/sha1\",\"gix-worktree/sha1\"]}}", + "gix-chunk_0.7.0": "{\"dependencies\":[{\"name\":\"gix-error\",\"req\":\"^0.2.0\"}],\"features\":{}}", + "gix-command_0.8.0": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"std\",\"unicode\"],\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"name\":\"gix-path\",\"req\":\"^0.11.1\"},{\"name\":\"gix-quote\",\"req\":\"^0.7.0\"},{\"name\":\"gix-trace\",\"req\":\"^0.1.18\"},{\"name\":\"shell-words\",\"req\":\"^1.1\"}],\"features\":{}}", + "gix-commitgraph_0.35.0": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"std\"],\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2.0\"},{\"name\":\"gix-chunk\",\"req\":\"^0.7.0\"},{\"name\":\"gix-error\",\"req\":\"^0.2.1\"},{\"name\":\"gix-hash\",\"req\":\"^0.23.0\"},{\"name\":\"memmap2\",\"req\":\"^0.9.10\"},{\"name\":\"nonempty\",\"req\":\"^0.12.0\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.114\"}],\"features\":{\"serde\":[\"dep:serde\",\"gix-hash/serde\",\"bstr/serde\"],\"sha1\":[\"gix-hash/sha1\"]}}", + "gix-config-value_0.17.1": "{\"dependencies\":[{\"name\":\"bitflags\",\"req\":\"^2\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2.0\"},{\"name\":\"gix-path\",\"req\":\"^0.11.1\"},{\"name\":\"libc\",\"req\":\"^0.2\",\"target\":\"cfg(not(windows))\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.114\"},{\"name\":\"thiserror\",\"req\":\"^2.0.18\"}],\"features\":{\"serde\":[\"dep:serde\",\"bstr/serde\"]}}", + "gix-config_0.54.0": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"std\"],\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.8.2\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2.0\"},{\"name\":\"gix-config-value\",\"req\":\"^0.17.1\"},{\"name\":\"gix-features\",\"req\":\"^0.46.2\"},{\"name\":\"gix-glob\",\"req\":\"^0.24.0\"},{\"name\":\"gix-path\",\"req\":\"^0.11.2\"},{\"name\":\"gix-ref\",\"req\":\"^0.61.0\"},{\"name\":\"gix-sec\",\"req\":\"^0.13.2\"},{\"name\":\"memchr\",\"req\":\"^2\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.114\"},{\"name\":\"smallvec\",\"req\":\"^1.15.1\"},{\"name\":\"thiserror\",\"req\":\"^2.0.18\"},{\"name\":\"unicode-bom\",\"req\":\"^2.0.3\"},{\"features\":[\"simd\"],\"name\":\"winnow\",\"req\":\"^0.7.14\"}],\"features\":{\"serde\":[\"dep:serde\",\"bstr/serde\",\"gix-sec/serde\",\"gix-ref/serde\",\"gix-glob/serde\",\"gix-config-value/serde\"],\"sha1\":[\"gix-ref/sha1\"]}}", + "gix-date_0.15.1": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"std\"],\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2.0\"},{\"name\":\"gix-error\",\"req\":\"^0.2.1\"},{\"name\":\"itoa\",\"req\":\"^1.0.17\"},{\"name\":\"jiff\",\"req\":\"^0.2.21\"},{\"kind\":\"dev\",\"name\":\"pretty_assertions\",\"req\":\"^1.4.1\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.114\"},{\"features\":[\"write\"],\"name\":\"smallvec\",\"req\":\"^1.15.1\"}],\"features\":{\"serde\":[\"dep:serde\",\"bstr/serde\"]}}", + "gix-diff_0.61.0": "{\"dependencies\":[{\"default_features\":false,\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.8.2\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2.0\"},{\"default_features\":false,\"features\":[\"js\"],\"name\":\"getrandom\",\"optional\":true,\"req\":\"^0.2.17\"},{\"name\":\"gix-attributes\",\"optional\":true,\"req\":\"^0.31.0\"},{\"name\":\"gix-command\",\"optional\":true,\"req\":\"^0.8.0\"},{\"name\":\"gix-filter\",\"optional\":true,\"req\":\"^0.28.0\"},{\"name\":\"gix-fs\",\"optional\":true,\"req\":\"^0.19.2\"},{\"name\":\"gix-hash\",\"req\":\"^0.23.0\"},{\"name\":\"gix-index\",\"optional\":true,\"req\":\"^0.49.0\"},{\"name\":\"gix-object\",\"req\":\"^0.58.0\"},{\"name\":\"gix-path\",\"optional\":true,\"req\":\"^0.11.2\"},{\"name\":\"gix-pathspec\",\"optional\":true,\"req\":\"^0.16.1\"},{\"name\":\"gix-tempfile\",\"optional\":true,\"req\":\"^21.0.0\"},{\"name\":\"gix-trace\",\"optional\":true,\"req\":\"^0.1.18\"},{\"name\":\"gix-traverse\",\"optional\":true,\"req\":\"^0.55.0\"},{\"default_features\":false,\"features\":[\"attributes\"],\"name\":\"gix-worktree\",\"optional\":true,\"req\":\"^0.50.0\"},{\"name\":\"imara-diff\",\"optional\":true,\"req\":\"^0.1.8\"},{\"name\":\"imara-diff-v2\",\"optional\":true,\"package\":\"imara-diff\",\"req\":\"^0.2.0\"},{\"kind\":\"dev\",\"name\":\"imara-diff-v2\",\"package\":\"imara-diff\",\"req\":\"^0.2.0\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.114\"},{\"name\":\"thiserror\",\"req\":\"^2.0.18\"}],\"features\":{\"blob\":[\"dep:imara-diff\",\"dep:gix-filter\",\"dep:gix-worktree\",\"dep:gix-path\",\"dep:gix-fs\",\"dep:gix-command\",\"dep:gix-tempfile\",\"dep:gix-trace\",\"dep:gix-traverse\"],\"blob-experimental\":[\"dep:imara-diff-v2\"],\"default\":[\"blob\",\"index\"],\"index\":[\"dep:gix-index\",\"dep:gix-pathspec\",\"dep:gix-attributes\"],\"serde\":[\"dep:serde\",\"gix-hash/serde\",\"gix-object/serde\",\"gix-index?/serde\"],\"sha1\":[\"gix-hash/sha1\"],\"wasm\":[\"dep:getrandom\"]}}", + "gix-dir_0.23.0": "{\"dependencies\":[{\"default_features\":false,\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"name\":\"gix-discover\",\"req\":\"^0.49.0\"},{\"name\":\"gix-fs\",\"req\":\"^0.19.2\"},{\"name\":\"gix-ignore\",\"req\":\"^0.19.1\"},{\"name\":\"gix-index\",\"req\":\"^0.49.0\"},{\"name\":\"gix-object\",\"req\":\"^0.58.0\"},{\"name\":\"gix-path\",\"req\":\"^0.11.2\"},{\"name\":\"gix-pathspec\",\"req\":\"^0.16.1\"},{\"name\":\"gix-trace\",\"req\":\"^0.1.18\"},{\"features\":[\"bstr\"],\"name\":\"gix-utils\",\"req\":\"^0.3.1\"},{\"default_features\":false,\"name\":\"gix-worktree\",\"req\":\"^0.50.0\"},{\"kind\":\"dev\",\"name\":\"pretty_assertions\",\"req\":\"^1.4.0\"},{\"name\":\"thiserror\",\"req\":\"^2.0.18\"}],\"features\":{\"sha1\":[\"gix-discover/sha1\",\"gix-index/sha1\",\"gix-object/sha1\",\"gix-worktree/sha1\"]}}", + "gix-discover_0.49.0": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"std\",\"unicode\"],\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"kind\":\"dev\",\"name\":\"defer\",\"req\":\"^0.2.1\",\"target\":\"cfg(target_os = \\\"macos\\\")\"},{\"name\":\"dunce\",\"req\":\"^1.0.3\",\"target\":\"cfg(windows)\"},{\"name\":\"gix-fs\",\"req\":\"^0.19.2\"},{\"name\":\"gix-path\",\"req\":\"^0.11.2\"},{\"name\":\"gix-ref\",\"req\":\"^0.61.0\"},{\"name\":\"gix-sec\",\"req\":\"^0.13.2\"},{\"kind\":\"dev\",\"name\":\"is_ci\",\"req\":\"^1.1.1\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"serial_test\",\"req\":\"^3.4.0\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.26.0\",\"target\":\"cfg(any(unix, windows))\"},{\"name\":\"thiserror\",\"req\":\"^2.0.18\"}],\"features\":{\"sha1\":[\"gix-ref/sha1\"]}}", + "gix-error_0.2.1": "{\"dependencies\":[{\"name\":\"anyhow\",\"optional\":true,\"req\":\"^1.0.102\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2.0\"},{\"kind\":\"dev\",\"name\":\"insta\",\"req\":\"^1.46.3\"}],\"features\":{\"anyhow\":[\"dep:anyhow\"],\"auto-chain-error\":[],\"tree-error\":[]}}", + "gix-features_0.46.2": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"name\":\"bytes\",\"optional\":true,\"req\":\"^1.11.1\"},{\"name\":\"bytesize\",\"optional\":true,\"req\":\"^2.3.1\"},{\"name\":\"crc32fast\",\"optional\":true,\"req\":\"^1.5.0\"},{\"name\":\"crossbeam-channel\",\"optional\":true,\"req\":\"^0.5.15\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2.0\"},{\"name\":\"gix-path\",\"optional\":true,\"req\":\"^0.11.2\"},{\"name\":\"gix-trace\",\"req\":\"^0.1.18\"},{\"name\":\"gix-utils\",\"optional\":true,\"req\":\"^0.3.1\"},{\"name\":\"libc\",\"req\":\"^0.2.182\",\"target\":\"cfg(unix)\"},{\"name\":\"once_cell\",\"optional\":true,\"req\":\"^1.21.3\"},{\"default_features\":false,\"name\":\"parking_lot\",\"optional\":true,\"req\":\"^0.12.4\"},{\"name\":\"prodash\",\"optional\":true,\"req\":\"^31.0.0\"},{\"name\":\"thiserror\",\"optional\":true,\"req\":\"^2.0.18\"},{\"name\":\"walkdir\",\"optional\":true,\"req\":\"^2.3.2\"},{\"name\":\"zlib-rs\",\"optional\":true,\"req\":\"^0.6.2\"}],\"features\":{\"cache-efficiency-debug\":[],\"crc32\":[\"dep:crc32fast\"],\"default\":[],\"fs-read-dir\":[\"dep:gix-utils\"],\"io-pipe\":[\"dep:bytes\"],\"once_cell\":[\"dep:once_cell\"],\"parallel\":[\"dep:crossbeam-channel\",\"dep:parking_lot\"],\"progress\":[\"prodash\"],\"progress-unit-bytes\":[\"dep:bytesize\",\"prodash?/unit-bytes\"],\"progress-unit-human-numbers\":[\"prodash?/unit-human\"],\"tracing\":[\"gix-trace/tracing\"],\"tracing-detail\":[\"gix-trace/tracing-detail\"],\"walkdir\":[\"dep:walkdir\",\"dep:gix-path\",\"dep:gix-utils\"],\"zlib\":[\"dep:zlib-rs\",\"dep:thiserror\"]}}", + "gix-filter_0.28.0": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"std\"],\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"name\":\"encoding_rs\",\"req\":\"^0.8.32\"},{\"name\":\"gix-attributes\",\"req\":\"^0.31.0\"},{\"name\":\"gix-command\",\"req\":\"^0.8.0\"},{\"name\":\"gix-hash\",\"req\":\"^0.23.0\"},{\"name\":\"gix-object\",\"req\":\"^0.58.0\"},{\"features\":[\"blocking-io\"],\"name\":\"gix-packetline\",\"req\":\"^0.21.2\"},{\"name\":\"gix-path\",\"req\":\"^0.11.2\"},{\"name\":\"gix-quote\",\"req\":\"^0.7.0\"},{\"name\":\"gix-trace\",\"req\":\"^0.1.18\"},{\"name\":\"gix-utils\",\"req\":\"^0.3.1\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"serial_test\",\"req\":\"^3.4.0\"},{\"name\":\"smallvec\",\"req\":\"^1.15.1\"},{\"name\":\"thiserror\",\"req\":\"^2.0.18\"}],\"features\":{\"sha1\":[\"gix-hash/sha1\",\"gix-object/sha1\"]}}", + "gix-fs_0.19.2": "{\"dependencies\":[{\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"kind\":\"dev\",\"name\":\"crossbeam-channel\",\"req\":\"^0.5.15\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"fastrand\",\"req\":\"^2.1.0\"},{\"features\":[\"fs-read-dir\"],\"name\":\"gix-features\",\"req\":\"^0.46.2\"},{\"name\":\"gix-path\",\"req\":\"^0.11.2\"},{\"name\":\"gix-utils\",\"req\":\"^0.3.1\"},{\"kind\":\"dev\",\"name\":\"is_ci\",\"req\":\"^1.1.1\"},{\"default_features\":false,\"features\":[\"std\",\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.114\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.26.0\"},{\"name\":\"thiserror\",\"req\":\"^2.0.18\"}],\"features\":{\"serde\":[\"dep:serde\"]}}", + "gix-glob_0.24.0": "{\"dependencies\":[{\"name\":\"bitflags\",\"req\":\"^2\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2.0\"},{\"name\":\"gix-features\",\"req\":\"^0.46.0\"},{\"name\":\"gix-path\",\"req\":\"^0.11.0\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.114\"}],\"features\":{\"serde\":[\"dep:serde\",\"bstr/serde\",\"bitflags/serde\"]}}", + "gix-hash_0.23.0": "{\"dependencies\":[{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2.0\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"faster-hex\",\"req\":\"^0.10.0\"},{\"features\":[\"progress\"],\"name\":\"gix-features\",\"req\":\"^0.46.2\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.114\"},{\"default_features\":false,\"name\":\"sha1-checked\",\"optional\":true,\"req\":\"^0.10.0\"},{\"default_features\":false,\"name\":\"sha2\",\"optional\":true,\"req\":\"^0.10.0\"},{\"name\":\"thiserror\",\"req\":\"^2.0.18\"}],\"features\":{\"default\":[],\"serde\":[\"dep:serde\",\"faster-hex/serde\"],\"sha1\":[\"dep:sha1-checked\"],\"sha256\":[\"dep:sha2\"]}}", + "gix-hashtable_0.13.0": "{\"dependencies\":[{\"name\":\"gix-hash\",\"req\":\"^0.23.0\"},{\"default_features\":false,\"features\":[\"inline-more\"],\"name\":\"hashbrown\",\"req\":\"^0.16.0\"},{\"name\":\"parking_lot\",\"req\":\"^0.12.4\"}],\"features\":{\"sha1\":[\"gix-hash/sha1\"]}}", + "gix-ignore_0.19.1": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"std\",\"unicode\"],\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2.1\"},{\"name\":\"gix-glob\",\"req\":\"^0.24.0\"},{\"name\":\"gix-path\",\"req\":\"^0.11.2\"},{\"name\":\"gix-trace\",\"req\":\"^0.1.16\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.114\"},{\"name\":\"unicode-bom\",\"req\":\"^2.0.3\"}],\"features\":{\"serde\":[\"dep:serde\",\"bstr/serde\",\"gix-glob/serde\"]}}", + "gix-index_0.49.0": "{\"dependencies\":[{\"name\":\"bitflags\",\"req\":\"^2\"},{\"default_features\":false,\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2.0\"},{\"name\":\"filetime\",\"req\":\"^0.2.27\"},{\"name\":\"fnv\",\"req\":\"^1.0.7\"},{\"name\":\"gix-bitmap\",\"req\":\"^0.3.0\"},{\"features\":[\"progress\"],\"name\":\"gix-features\",\"req\":\"^0.46.2\"},{\"name\":\"gix-fs\",\"req\":\"^0.19.2\"},{\"name\":\"gix-hash\",\"req\":\"^0.23.0\"},{\"name\":\"gix-lock\",\"req\":\"^21.0.0\"},{\"name\":\"gix-object\",\"req\":\"^0.58.0\"},{\"name\":\"gix-traverse\",\"req\":\"^0.55.0\"},{\"name\":\"gix-utils\",\"req\":\"^0.3.1\"},{\"name\":\"gix-validate\",\"req\":\"^0.11.0\"},{\"name\":\"hashbrown\",\"req\":\"^0.16.0\"},{\"name\":\"itoa\",\"req\":\"^1.0.17\"},{\"name\":\"libc\",\"req\":\"^0.2.182\",\"target\":\"cfg(not(windows))\"},{\"name\":\"memmap2\",\"req\":\"^0.9.10\"},{\"default_features\":false,\"features\":[\"std\",\"fs\"],\"name\":\"rustix\",\"req\":\"^1.1.2\",\"target\":\"cfg(not(windows))\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.114\"},{\"name\":\"smallvec\",\"req\":\"^1.15.1\"},{\"name\":\"thiserror\",\"req\":\"^2.0.18\"}],\"features\":{\"serde\":[\"dep:serde\",\"smallvec/serde\",\"gix-hash/serde\"],\"sha1\":[\"gix-hash/sha1\"]}}", + "gix-lock_21.0.2": "{\"dependencies\":[{\"default_features\":false,\"name\":\"gix-tempfile\",\"req\":\"^21.0.0\"},{\"default_features\":false,\"name\":\"gix-utils\",\"req\":\"^0.3.1\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.26.0\"},{\"name\":\"thiserror\",\"req\":\"^2.0.18\"}],\"features\":{}}", + "gix-merge_0.14.0": "{\"dependencies\":[{\"default_features\":false,\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2.0\"},{\"name\":\"gix-command\",\"req\":\"^0.8.0\"},{\"default_features\":false,\"features\":[\"blob\"],\"name\":\"gix-diff\",\"req\":\"^0.61.0\"},{\"name\":\"gix-filter\",\"req\":\"^0.28.0\"},{\"name\":\"gix-fs\",\"req\":\"^0.19.2\"},{\"name\":\"gix-hash\",\"req\":\"^0.23.0\"},{\"name\":\"gix-index\",\"req\":\"^0.49.0\"},{\"name\":\"gix-object\",\"req\":\"^0.58.0\"},{\"name\":\"gix-path\",\"req\":\"^0.11.2\"},{\"name\":\"gix-quote\",\"req\":\"^0.7.0\"},{\"default_features\":false,\"features\":[\"merge_base\"],\"name\":\"gix-revision\",\"req\":\"^0.43.0\"},{\"name\":\"gix-revwalk\",\"req\":\"^0.29.0\"},{\"name\":\"gix-tempfile\",\"req\":\"^21.0.0\"},{\"name\":\"gix-trace\",\"req\":\"^0.1.18\"},{\"default_features\":false,\"features\":[\"attributes\"],\"name\":\"gix-worktree\",\"req\":\"^0.50.0\"},{\"name\":\"imara-diff\",\"req\":\"^0.1.8\"},{\"name\":\"nonempty\",\"req\":\"^0.12.0\"},{\"kind\":\"dev\",\"name\":\"pretty_assertions\",\"req\":\"^1.4.0\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.114\"},{\"kind\":\"dev\",\"name\":\"termtree\",\"req\":\"^1.0.0\"},{\"name\":\"thiserror\",\"req\":\"^2.0.18\"}],\"features\":{\"serde\":[\"dep:serde\",\"gix-hash/serde\",\"gix-object/serde\"],\"sha1\":[\"gix-hash/sha1\"]}}", + "gix-negotiate_0.29.0": "{\"dependencies\":[{\"name\":\"bitflags\",\"req\":\"^2\"},{\"name\":\"gix-commitgraph\",\"req\":\"^0.35.0\"},{\"name\":\"gix-date\",\"req\":\"^0.15.1\"},{\"name\":\"gix-hash\",\"req\":\"^0.23.0\"},{\"name\":\"gix-object\",\"req\":\"^0.58.0\"},{\"name\":\"gix-revwalk\",\"req\":\"^0.29.0\"}],\"features\":{\"sha1\":[\"gix-commitgraph/sha1\",\"gix-hash/sha1\",\"gix-object/sha1\",\"gix-revwalk/sha1\"]}}", + "gix-object_0.58.0": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"std\",\"unicode\"],\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.8.2\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2.0\"},{\"name\":\"gix-actor\",\"req\":\"^0.40.0\"},{\"name\":\"gix-date\",\"req\":\"^0.15.1\"},{\"features\":[\"progress\"],\"name\":\"gix-features\",\"req\":\"^0.46.2\"},{\"name\":\"gix-hash\",\"req\":\"^0.23.0\"},{\"name\":\"gix-hashtable\",\"req\":\"^0.13.0\"},{\"name\":\"gix-path\",\"req\":\"^0.11.2\"},{\"name\":\"gix-utils\",\"req\":\"^0.3.1\"},{\"name\":\"gix-validate\",\"req\":\"^0.11.0\"},{\"name\":\"itoa\",\"req\":\"^1.0.17\"},{\"kind\":\"dev\",\"name\":\"pretty_assertions\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.114\"},{\"features\":[\"write\"],\"name\":\"smallvec\",\"req\":\"^1.15.1\"},{\"kind\":\"dev\",\"name\":\"termtree\",\"req\":\"^1.0.0\"},{\"name\":\"thiserror\",\"req\":\"^2.0.18\"},{\"features\":[\"simd\"],\"name\":\"winnow\",\"req\":\"^0.7.14\"}],\"features\":{\"serde\":[\"dep:serde\",\"bstr/serde\",\"smallvec/serde\",\"gix-hash/serde\",\"gix-actor/serde\"],\"sha1\":[\"gix-hash/sha1\"],\"verbose-object-parsing-errors\":[\"winnow/std\"]}}", + "gix-odb_0.78.0": "{\"dependencies\":[{\"name\":\"arc-swap\",\"req\":\"^1.8.2\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2.0\"},{\"features\":[\"walkdir\",\"zlib\",\"crc32\"],\"name\":\"gix-features\",\"req\":\"^0.46.2\"},{\"name\":\"gix-fs\",\"req\":\"^0.19.2\"},{\"name\":\"gix-hash\",\"req\":\"^0.23.0\"},{\"name\":\"gix-hashtable\",\"req\":\"^0.13.0\"},{\"name\":\"gix-object\",\"req\":\"^0.58.0\"},{\"default_features\":false,\"name\":\"gix-pack\",\"req\":\"^0.68.0\"},{\"name\":\"gix-path\",\"req\":\"^0.11.2\"},{\"name\":\"gix-quote\",\"req\":\"^0.7.0\"},{\"name\":\"parking_lot\",\"req\":\"^0.12.4\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.114\"},{\"name\":\"tempfile\",\"req\":\"^3.26.0\"},{\"name\":\"thiserror\",\"req\":\"^2.0.18\"}],\"features\":{\"serde\":[\"dep:serde\",\"gix-hash/serde\",\"gix-object/serde\",\"gix-pack/serde\"],\"sha1\":[\"gix-hash/sha1\"]}}", + "gix-pack_0.68.0": "{\"dependencies\":[{\"name\":\"clru\",\"optional\":true,\"req\":\"^0.6.1\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2.0\"},{\"name\":\"gix-chunk\",\"req\":\"^0.7.0\"},{\"default_features\":false,\"name\":\"gix-diff\",\"optional\":true,\"req\":\"^0.61.0\"},{\"name\":\"gix-error\",\"req\":\"^0.2.1\"},{\"features\":[\"crc32\",\"progress\",\"zlib\"],\"name\":\"gix-features\",\"req\":\"^0.46.2\"},{\"name\":\"gix-hash\",\"req\":\"^0.23.0\"},{\"features\":[\"sha256\"],\"kind\":\"dev\",\"name\":\"gix-hash\",\"req\":\"^0.23.0\"},{\"name\":\"gix-hashtable\",\"optional\":true,\"req\":\"^0.13.0\"},{\"name\":\"gix-object\",\"req\":\"^0.58.0\"},{\"name\":\"gix-path\",\"req\":\"^0.11.2\"},{\"default_features\":false,\"name\":\"gix-tempfile\",\"optional\":true,\"req\":\"^21.0.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"gix-traverse\",\"optional\":true,\"req\":\"^0.55.0\"},{\"name\":\"memmap2\",\"req\":\"^0.9.10\"},{\"default_features\":false,\"name\":\"parking_lot\",\"optional\":true,\"req\":\"^0.12.4\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.114\"},{\"name\":\"smallvec\",\"req\":\"^1.15.1\"},{\"name\":\"thiserror\",\"req\":\"^2.0.18\"},{\"name\":\"uluru\",\"optional\":true,\"req\":\"^3.0.0\"}],\"features\":{\"default\":[\"generate\",\"streaming-input\"],\"generate\":[\"dep:gix-traverse\",\"dep:gix-diff\",\"dep:parking_lot\",\"dep:gix-hashtable\"],\"object-cache-dynamic\":[\"dep:clru\",\"dep:gix-hashtable\"],\"pack-cache-lru-dynamic\":[\"dep:clru\"],\"pack-cache-lru-static\":[\"dep:uluru\"],\"serde\":[\"dep:serde\",\"gix-object/serde\"],\"sha1\":[\"gix-hash/sha1\"],\"streaming-input\":[\"dep:parking_lot\",\"dep:gix-tempfile\"],\"wasm\":[\"gix-diff?/wasm\"]}}", + "gix-packetline_0.21.2": "{\"dependencies\":[{\"features\":[\"attributes\"],\"kind\":\"dev\",\"name\":\"async-std\",\"req\":\"^1.9.0\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2.0\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"faster-hex\",\"req\":\"^0.10.0\"},{\"name\":\"futures-io\",\"optional\":true,\"req\":\"^0.3.32\"},{\"name\":\"futures-lite\",\"optional\":true,\"req\":\"^2.1.0\"},{\"name\":\"gix-trace\",\"req\":\"^0.1.18\"},{\"kind\":\"dev\",\"name\":\"maybe-async\",\"req\":\"^0.2.6\"},{\"name\":\"pin-project-lite\",\"optional\":true,\"req\":\"^0.2.6\"},{\"default_features\":false,\"features\":[\"std\",\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.114\"},{\"name\":\"thiserror\",\"req\":\"^2.0.18\"}],\"features\":{\"async-io\":[\"dep:futures-io\",\"futures-lite\",\"dep:pin-project-lite\"],\"blocking-io\":[],\"default\":[],\"serde\":[\"dep:serde\",\"bstr/serde\",\"faster-hex/serde\"]}}", + "gix-path_0.11.2": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"std\"],\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"name\":\"gix-trace\",\"req\":\"^0.1.18\"},{\"name\":\"gix-validate\",\"req\":\"^0.11.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"serial_test\",\"req\":\"^3.4.0\"},{\"name\":\"thiserror\",\"req\":\"^2.0.18\"},{\"features\":[\"Win32_System_Com\",\"Win32_System_Threading\",\"Win32_UI_Shell\"],\"kind\":\"dev\",\"name\":\"windows\",\"req\":\"^0.62.1\",\"target\":\"cfg(windows)\"},{\"kind\":\"dev\",\"name\":\"winreg\",\"req\":\"^0.55.0\",\"target\":\"cfg(windows)\"}],\"features\":{}}", + "gix-pathspec_0.16.1": "{\"dependencies\":[{\"name\":\"bitflags\",\"req\":\"^2\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"name\":\"gix-attributes\",\"req\":\"^0.31.0\"},{\"name\":\"gix-config-value\",\"req\":\"^0.17.1\"},{\"name\":\"gix-glob\",\"req\":\"^0.24.0\"},{\"name\":\"gix-path\",\"req\":\"^0.11.2\"},{\"kind\":\"dev\",\"name\":\"serial_test\",\"req\":\"^3.4.0\"},{\"name\":\"thiserror\",\"req\":\"^2.0.18\"}],\"features\":{}}", + "gix-protocol_0.59.0": "{\"dependencies\":[{\"features\":[\"attributes\"],\"kind\":\"dev\",\"name\":\"async-std\",\"req\":\"^1.9.0\"},{\"name\":\"async-trait\",\"optional\":true,\"req\":\"^0.1.51\"},{\"default_features\":false,\"features\":[\"std\",\"unicode\"],\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2.0\"},{\"name\":\"futures-io\",\"optional\":true,\"req\":\"^0.3.32\"},{\"name\":\"futures-lite\",\"optional\":true,\"req\":\"^2.1.0\"},{\"name\":\"gix-credentials\",\"optional\":true,\"req\":\"^0.37.1\"},{\"name\":\"gix-date\",\"req\":\"^0.15.1\"},{\"features\":[\"progress\"],\"name\":\"gix-features\",\"req\":\"^0.46.2\"},{\"name\":\"gix-hash\",\"req\":\"^0.23.0\"},{\"name\":\"gix-lock\",\"optional\":true,\"req\":\"^21.0.0\"},{\"name\":\"gix-negotiate\",\"optional\":true,\"req\":\"^0.29.0\"},{\"name\":\"gix-object\",\"optional\":true,\"req\":\"^0.58.0\"},{\"kind\":\"dev\",\"name\":\"gix-packetline\",\"req\":\"^0.21.2\"},{\"name\":\"gix-ref\",\"req\":\"^0.61.0\"},{\"name\":\"gix-refspec\",\"optional\":true,\"req\":\"^0.39.0\"},{\"name\":\"gix-revwalk\",\"optional\":true,\"req\":\"^0.29.0\"},{\"name\":\"gix-shallow\",\"req\":\"^0.10.0\"},{\"name\":\"gix-trace\",\"optional\":true,\"req\":\"^0.1.18\"},{\"name\":\"gix-transport\",\"req\":\"^0.55.1\"},{\"name\":\"gix-utils\",\"req\":\"^0.3.1\"},{\"name\":\"maybe-async\",\"req\":\"^0.2.6\"},{\"name\":\"nonempty\",\"req\":\"^0.12.0\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.114\"},{\"name\":\"thiserror\",\"req\":\"^2.0.18\"},{\"features\":[\"simd\"],\"name\":\"winnow\",\"req\":\"^0.7.14\"}],\"features\":{\"async-client\":[\"gix-transport/async-client\",\"dep:async-trait\",\"dep:futures-io\",\"futures-lite\",\"handshake\",\"fetch\"],\"blocking-client\":[\"gix-transport/blocking-client\",\"maybe-async/is_sync\",\"handshake\",\"fetch\"],\"fetch\":[\"dep:gix-negotiate\",\"dep:gix-object\",\"dep:gix-revwalk\",\"dep:gix-lock\",\"dep:gix-refspec\",\"dep:gix-trace\"],\"handshake\":[\"dep:gix-credentials\"],\"serde\":[\"dep:serde\",\"bstr/serde\",\"gix-transport/serde\",\"gix-hash/serde\",\"gix-shallow/serde\"],\"sha1\":[\"gix-hash/sha1\"]}}", + "gix-quote_0.7.0": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"std\"],\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"name\":\"gix-error\",\"req\":\"^0.2.0\"},{\"name\":\"gix-utils\",\"req\":\"^0.3.1\"}],\"features\":{}}", + "gix-ref_0.61.0": "{\"dependencies\":[{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2.1\"},{\"name\":\"gix-actor\",\"req\":\"^0.40.0\"},{\"features\":[\"walkdir\"],\"name\":\"gix-features\",\"req\":\"^0.46.2\"},{\"name\":\"gix-fs\",\"req\":\"^0.19.2\"},{\"name\":\"gix-hash\",\"req\":\"^0.23.0\"},{\"name\":\"gix-lock\",\"req\":\"^21.0.0\"},{\"name\":\"gix-object\",\"req\":\"^0.58.0\"},{\"name\":\"gix-path\",\"req\":\"^0.11.2\"},{\"default_features\":false,\"name\":\"gix-tempfile\",\"req\":\"^21.0.0\"},{\"name\":\"gix-utils\",\"req\":\"^0.3.1\"},{\"name\":\"gix-validate\",\"req\":\"^0.11.0\"},{\"name\":\"memmap2\",\"req\":\"^0.9.10\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.114\"},{\"name\":\"thiserror\",\"req\":\"^2.0.18\"},{\"features\":[\"simd\"],\"name\":\"winnow\",\"req\":\"^0.7.14\"}],\"features\":{\"serde\":[\"dep:serde\",\"gix-hash/serde\",\"gix-actor/serde\",\"gix-object/serde\"],\"sha1\":[\"gix-hash/sha1\"]}}", + "gix-refspec_0.39.0": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"std\"],\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"name\":\"gix-error\",\"req\":\"^0.2.1\"},{\"name\":\"gix-glob\",\"req\":\"^0.24.0\"},{\"name\":\"gix-hash\",\"req\":\"^0.23.0\"},{\"default_features\":false,\"name\":\"gix-revision\",\"req\":\"^0.43.0\"},{\"name\":\"gix-validate\",\"req\":\"^0.11.0\"},{\"kind\":\"dev\",\"name\":\"insta\",\"req\":\"^1.46.3\"},{\"name\":\"smallvec\",\"req\":\"^1.15.1\"},{\"name\":\"thiserror\",\"req\":\"^2.0.18\"}],\"features\":{\"sha1\":[\"gix-hash/sha1\"]}}", + "gix-revision_0.43.0": "{\"dependencies\":[{\"name\":\"bitflags\",\"optional\":true,\"req\":\"^2\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2.1\"},{\"name\":\"gix-commitgraph\",\"req\":\"^0.35.0\"},{\"name\":\"gix-date\",\"req\":\"^0.15.1\"},{\"name\":\"gix-error\",\"req\":\"^0.2.1\"},{\"name\":\"gix-hash\",\"req\":\"^0.23.0\"},{\"name\":\"gix-hashtable\",\"optional\":true,\"req\":\"^0.13.0\"},{\"name\":\"gix-object\",\"req\":\"^0.58.0\"},{\"name\":\"gix-revwalk\",\"req\":\"^0.29.0\"},{\"name\":\"gix-trace\",\"optional\":true,\"req\":\"^0.1.18\"},{\"kind\":\"dev\",\"name\":\"insta\",\"req\":\"^1.46.3\"},{\"name\":\"nonempty\",\"req\":\"^0.12.0\"},{\"kind\":\"dev\",\"name\":\"permutohedron\",\"req\":\"^0.2.4\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.114\"}],\"features\":{\"default\":[\"describe\",\"merge_base\"],\"describe\":[\"dep:gix-trace\",\"dep:gix-hashtable\"],\"merge_base\":[\"dep:gix-trace\",\"dep:bitflags\"],\"serde\":[\"dep:serde\",\"gix-hash/serde\",\"gix-object/serde\"],\"sha1\":[\"gix-hash/sha1\"]}}", + "gix-revwalk_0.29.0": "{\"dependencies\":[{\"name\":\"gix-commitgraph\",\"req\":\"^0.35.0\"},{\"name\":\"gix-date\",\"req\":\"^0.15.1\"},{\"name\":\"gix-error\",\"req\":\"^0.2.1\"},{\"name\":\"gix-hash\",\"req\":\"^0.23.0\"},{\"name\":\"gix-hashtable\",\"req\":\"^0.13.0\"},{\"name\":\"gix-object\",\"req\":\"^0.58.0\"},{\"name\":\"smallvec\",\"req\":\"^1.15.1\"},{\"name\":\"thiserror\",\"req\":\"^2.0.18\"}],\"features\":{\"sha1\":[\"gix-commitgraph/sha1\",\"gix-hash/sha1\",\"gix-hashtable/sha1\",\"gix-object/sha1\"]}}", + "gix-sec_0.13.2": "{\"dependencies\":[{\"name\":\"bitflags\",\"req\":\"^2\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2.1\"},{\"name\":\"gix-path\",\"req\":\"^0.11.2\",\"target\":\"cfg(windows)\"},{\"name\":\"libc\",\"req\":\"^0.2.182\",\"target\":\"cfg(not(windows))\"},{\"default_features\":false,\"features\":[\"std\",\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.114\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.26.0\"},{\"features\":[\"Win32_Foundation\",\"Win32_Security_Authorization\",\"Win32_Storage_FileSystem\",\"Win32_System_Memory\",\"Win32_System_Threading\"],\"name\":\"windows-sys\",\"req\":\"^0.61.1\",\"target\":\"cfg(windows)\"}],\"features\":{\"serde\":[\"dep:serde\",\"bitflags/serde\"]}}", + "gix-shallow_0.10.0": "{\"dependencies\":[{\"default_features\":false,\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"name\":\"gix-hash\",\"req\":\"^0.23.0\"},{\"name\":\"gix-lock\",\"req\":\"^21.0.0\"},{\"name\":\"nonempty\",\"req\":\"^0.12.0\"},{\"default_features\":false,\"features\":[\"std\",\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.114\"},{\"name\":\"thiserror\",\"req\":\"^2.0.18\"}],\"features\":{\"serde\":[\"dep:serde\",\"gix-hash/serde\",\"nonempty/serialize\"],\"sha1\":[\"gix-hash/sha1\"]}}", + "gix-status_0.28.0": "{\"dependencies\":[{\"default_features\":false,\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2.0\"},{\"name\":\"filetime\",\"req\":\"^0.2.27\"},{\"default_features\":false,\"features\":[\"blob\"],\"name\":\"gix-diff\",\"optional\":true,\"req\":\"^0.61.0\"},{\"name\":\"gix-dir\",\"optional\":true,\"req\":\"^0.23.0\"},{\"features\":[\"progress\"],\"name\":\"gix-features\",\"req\":\"^0.46.2\"},{\"name\":\"gix-filter\",\"req\":\"^0.28.0\"},{\"name\":\"gix-fs\",\"req\":\"^0.19.2\"},{\"name\":\"gix-hash\",\"req\":\"^0.23.0\"},{\"name\":\"gix-index\",\"req\":\"^0.49.0\"},{\"name\":\"gix-object\",\"req\":\"^0.58.0\"},{\"name\":\"gix-path\",\"req\":\"^0.11.2\"},{\"name\":\"gix-pathspec\",\"req\":\"^0.16.1\"},{\"default_features\":false,\"features\":[\"attributes\"],\"name\":\"gix-worktree\",\"req\":\"^0.50.0\"},{\"name\":\"portable-atomic\",\"req\":\"^1\",\"target\":\"cfg(not(target_has_atomic = \\\"64\\\"))\"},{\"name\":\"thiserror\",\"req\":\"^2.0.18\"}],\"features\":{\"sha1\":[\"gix-hash/sha1\"],\"worktree-rewrites\":[\"dep:gix-dir\",\"dep:gix-diff\"]}}", + "gix-submodule_0.28.0": "{\"dependencies\":[{\"default_features\":false,\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"name\":\"gix-config\",\"req\":\"^0.54.0\"},{\"name\":\"gix-path\",\"req\":\"^0.11.2\"},{\"name\":\"gix-pathspec\",\"req\":\"^0.16.1\"},{\"name\":\"gix-refspec\",\"req\":\"^0.39.0\"},{\"name\":\"gix-url\",\"req\":\"^0.35.2\"},{\"name\":\"thiserror\",\"req\":\"^2.0.18\"}],\"features\":{\"sha1\":[\"gix-config/sha1\",\"gix-refspec/sha1\"]}}", + "gix-tempfile_21.0.2": "{\"dependencies\":[{\"name\":\"dashmap\",\"optional\":true,\"req\":\"^6.0.1\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2.0\"},{\"name\":\"gix-fs\",\"req\":\"^0.19.2\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.182\",\"target\":\"cfg(not(windows))\"},{\"name\":\"parking_lot\",\"req\":\"^0.12.4\"},{\"default_features\":false,\"name\":\"signal-hook\",\"optional\":true,\"req\":\"^0.4.3\"},{\"name\":\"signal-hook-registry\",\"optional\":true,\"req\":\"^1.4.8\"},{\"name\":\"tempfile\",\"req\":\"^3.26.0\"}],\"features\":{\"default\":[\"hp-hashmap\"],\"hp-hashmap\":[\"dep:dashmap\"],\"signals\":[\"dep:signal-hook\",\"dep:signal-hook-registry\"]}}", + "gix-trace_0.1.18": "{\"dependencies\":[{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2.0\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"tracing\",\"optional\":true,\"req\":\"^0.1.44\"}],\"features\":{\"default\":[],\"tracing\":[\"dep:tracing\"],\"tracing-detail\":[]}}", + "gix-transport_0.55.1": "{\"dependencies\":[{\"name\":\"async-std\",\"optional\":true,\"req\":\"^1.12.0\"},{\"features\":[\"attributes\"],\"kind\":\"dev\",\"name\":\"async-std\",\"req\":\"^1.9.0\"},{\"name\":\"async-trait\",\"optional\":true,\"req\":\"^0.1.51\"},{\"name\":\"base64\",\"optional\":true,\"req\":\"^0.22.1\"},{\"kind\":\"dev\",\"name\":\"blocking\",\"req\":\"^1.6.2\"},{\"default_features\":false,\"features\":[\"std\",\"unicode\"],\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"default_features\":false,\"name\":\"curl\",\"optional\":true,\"req\":\"^0.4\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2.0\"},{\"name\":\"futures-io\",\"optional\":true,\"req\":\"^0.3.32\"},{\"name\":\"futures-lite\",\"optional\":true,\"req\":\"^2.1.0\"},{\"name\":\"gix-command\",\"req\":\"^0.8.0\"},{\"name\":\"gix-credentials\",\"optional\":true,\"req\":\"^0.37.1\"},{\"name\":\"gix-features\",\"req\":\"^0.46.2\"},{\"name\":\"gix-packetline\",\"req\":\"^0.21.2\"},{\"name\":\"gix-quote\",\"req\":\"^0.7.0\"},{\"name\":\"gix-sec\",\"req\":\"^0.13.2\"},{\"name\":\"gix-url\",\"req\":\"^0.35.2\"},{\"kind\":\"dev\",\"name\":\"maybe-async\",\"req\":\"^0.2.6\"},{\"name\":\"pin-project-lite\",\"optional\":true,\"req\":\"^0.2.6\"},{\"default_features\":false,\"features\":[\"blocking\",\"charset\",\"http2\"],\"name\":\"reqwest\",\"optional\":true,\"req\":\"^0.13.2\"},{\"default_features\":false,\"features\":[\"std\",\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.114\"},{\"name\":\"thiserror\",\"req\":\"^2.0.18\"}],\"features\":{\"async-client\":[\"gix-packetline/async-io\",\"async-trait\",\"futures-lite\",\"futures-io\",\"pin-project-lite\"],\"blocking-client\":[\"gix-packetline/blocking-io\"],\"default\":[],\"http-client\":[\"base64\",\"gix-features/io-pipe\",\"blocking-client\",\"gix-credentials\"],\"http-client-curl\":[\"curl\",\"http-client\"],\"http-client-curl-openssl\":[\"http-client-curl\",\"curl/ssl\"],\"http-client-curl-rust-tls\":[\"http-client-curl\",\"curl/rustls\"],\"http-client-insecure-credentials\":[],\"http-client-reqwest\":[\"reqwest\",\"http-client\"],\"http-client-reqwest-native-tls\":[\"http-client-reqwest\",\"reqwest/native-tls\"],\"http-client-reqwest-rust-tls\":[\"http-client-reqwest\",\"reqwest/rustls\"],\"http-client-reqwest-rust-tls-trust-dns\":[\"http-client-reqwest\",\"reqwest/rustls\",\"reqwest/hickory-dns\"],\"serde\":[\"dep:serde\",\"bstr/serde\"]}}", + "gix-traverse_0.55.0": "{\"dependencies\":[{\"name\":\"bitflags\",\"req\":\"^2\"},{\"name\":\"gix-commitgraph\",\"req\":\"^0.35.0\"},{\"name\":\"gix-date\",\"req\":\"^0.15.1\"},{\"name\":\"gix-hash\",\"req\":\"^0.23.0\"},{\"name\":\"gix-hashtable\",\"req\":\"^0.13.0\"},{\"name\":\"gix-object\",\"req\":\"^0.58.0\"},{\"name\":\"gix-revwalk\",\"req\":\"^0.29.0\"},{\"name\":\"smallvec\",\"req\":\"^1.15.1\"},{\"name\":\"thiserror\",\"req\":\"^2.0.18\"}],\"features\":{\"sha1\":[\"gix-hash/sha1\"]}}", + "gix-url_0.35.2": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"assert_matches\",\"req\":\"^1.5.0\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2.0\"},{\"name\":\"gix-path\",\"req\":\"^0.11.1\"},{\"name\":\"percent-encoding\",\"req\":\"^2.3.1\"},{\"default_features\":false,\"features\":[\"std\",\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.114\"},{\"name\":\"thiserror\",\"req\":\"^2.0.18\"}],\"features\":{\"serde\":[\"dep:serde\",\"bstr/serde\"]}}", + "gix-utils_0.3.1": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"std\"],\"name\":\"bstr\",\"optional\":true,\"req\":\"^1.12.0\"},{\"name\":\"fastrand\",\"req\":\"^2.0.0\"},{\"default_features\":false,\"name\":\"unicode-normalization\",\"req\":\"^0.1.19\"}],\"features\":{\"bstr\":[\"dep:bstr\"]}}", + "gix-validate_0.11.0": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"std\"],\"name\":\"bstr\",\"req\":\"^1.12.0\"}],\"features\":{}}", + "gix-worktree-state_0.28.0": "{\"dependencies\":[{\"default_features\":false,\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"name\":\"gix-features\",\"req\":\"^0.46.2\"},{\"name\":\"gix-filter\",\"req\":\"^0.28.0\"},{\"name\":\"gix-fs\",\"req\":\"^0.19.2\"},{\"name\":\"gix-index\",\"req\":\"^0.49.0\"},{\"name\":\"gix-object\",\"req\":\"^0.58.0\"},{\"name\":\"gix-path\",\"req\":\"^0.11.2\"},{\"default_features\":false,\"features\":[\"attributes\"],\"name\":\"gix-worktree\",\"req\":\"^0.50.0\"},{\"name\":\"io-close\",\"req\":\"^0.3.7\"},{\"name\":\"thiserror\",\"req\":\"^2.0.18\"}],\"features\":{\"sha1\":[\"gix-filter/sha1\",\"gix-index/sha1\",\"gix-object/sha1\",\"gix-worktree/sha1\"]}}", + "gix-worktree-stream_0.30.0": "{\"dependencies\":[{\"name\":\"gix-attributes\",\"req\":\"^0.31.0\"},{\"name\":\"gix-error\",\"req\":\"^0.2.1\"},{\"features\":[\"progress\",\"io-pipe\"],\"name\":\"gix-features\",\"req\":\"^0.46.2\"},{\"name\":\"gix-filter\",\"req\":\"^0.28.0\"},{\"name\":\"gix-fs\",\"req\":\"^0.19.2\"},{\"name\":\"gix-hash\",\"req\":\"^0.23.0\"},{\"name\":\"gix-object\",\"req\":\"^0.58.0\"},{\"name\":\"gix-path\",\"req\":\"^0.11.2\"},{\"name\":\"gix-traverse\",\"req\":\"^0.55.0\"},{\"name\":\"parking_lot\",\"req\":\"^0.12.4\"}],\"features\":{\"sha1\":[\"gix-filter/sha1\",\"gix-hash/sha1\",\"gix-object/sha1\",\"gix-traverse/sha1\"]}}", + "gix-worktree_0.50.0": "{\"dependencies\":[{\"default_features\":false,\"name\":\"bstr\",\"req\":\"^1.12.0\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2.0\"},{\"name\":\"gix-attributes\",\"optional\":true,\"req\":\"^0.31.0\"},{\"name\":\"gix-fs\",\"req\":\"^0.19.2\"},{\"name\":\"gix-glob\",\"req\":\"^0.24.0\"},{\"name\":\"gix-hash\",\"req\":\"^0.23.0\"},{\"name\":\"gix-ignore\",\"req\":\"^0.19.1\"},{\"name\":\"gix-index\",\"req\":\"^0.49.0\"},{\"name\":\"gix-object\",\"req\":\"^0.58.0\"},{\"name\":\"gix-path\",\"req\":\"^0.11.2\"},{\"name\":\"gix-validate\",\"optional\":true,\"req\":\"^0.11.0\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.114\"}],\"features\":{\"attributes\":[\"dep:gix-attributes\",\"dep:gix-validate\"],\"default\":[\"attributes\"],\"serde\":[\"dep:serde\",\"bstr/serde\",\"gix-index/serde\",\"gix-hash/serde\",\"gix-object/serde\",\"gix-attributes?/serde\",\"gix-ignore/serde\"],\"sha1\":[\"gix-hash/sha1\"]}}", + "gix_0.81.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1\"},{\"name\":\"async-std\",\"optional\":true,\"req\":\"^1.12.0\"},{\"features\":[\"attributes\"],\"kind\":\"dev\",\"name\":\"async-std\",\"req\":\"^1.12.0\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2.0\"},{\"name\":\"gix-actor\",\"req\":\"^0.40.0\"},{\"default_features\":false,\"name\":\"gix-archive\",\"optional\":true,\"req\":\"^0.30.0\"},{\"name\":\"gix-attributes\",\"optional\":true,\"req\":\"^0.31.0\"},{\"name\":\"gix-blame\",\"optional\":true,\"req\":\"^0.11.0\"},{\"name\":\"gix-command\",\"optional\":true,\"req\":\"^0.8.0\"},{\"name\":\"gix-commitgraph\",\"req\":\"^0.35.0\"},{\"name\":\"gix-config\",\"req\":\"^0.54.0\"},{\"name\":\"gix-credentials\",\"optional\":true,\"req\":\"^0.37.1\"},{\"name\":\"gix-date\",\"req\":\"^0.15.1\"},{\"default_features\":false,\"name\":\"gix-diff\",\"req\":\"^0.61.0\"},{\"name\":\"gix-dir\",\"optional\":true,\"req\":\"^0.23.0\"},{\"name\":\"gix-discover\",\"req\":\"^0.49.0\"},{\"name\":\"gix-error\",\"req\":\"^0.2.1\"},{\"features\":[\"progress\",\"once_cell\"],\"name\":\"gix-features\",\"req\":\"^0.46.2\"},{\"name\":\"gix-filter\",\"optional\":true,\"req\":\"^0.28.0\"},{\"name\":\"gix-fs\",\"req\":\"^0.19.2\"},{\"name\":\"gix-glob\",\"req\":\"^0.24.0\"},{\"name\":\"gix-hash\",\"req\":\"^0.23.0\"},{\"features\":[\"sha256\"],\"kind\":\"dev\",\"name\":\"gix-hash\",\"req\":\"^0.23.0\"},{\"name\":\"gix-hashtable\",\"req\":\"^0.13.0\"},{\"name\":\"gix-ignore\",\"optional\":true,\"req\":\"^0.19.1\"},{\"name\":\"gix-index\",\"optional\":true,\"req\":\"^0.49.0\"},{\"name\":\"gix-lock\",\"req\":\"^21.0.0\"},{\"name\":\"gix-mailmap\",\"optional\":true,\"req\":\"^0.32.0\"},{\"default_features\":false,\"name\":\"gix-merge\",\"optional\":true,\"req\":\"^0.14.0\"},{\"name\":\"gix-negotiate\",\"optional\":true,\"req\":\"^0.29.0\"},{\"name\":\"gix-object\",\"req\":\"^0.58.0\"},{\"name\":\"gix-odb\",\"req\":\"^0.78.0\"},{\"default_features\":false,\"features\":[\"object-cache-dynamic\"],\"name\":\"gix-pack\",\"req\":\"^0.68.0\"},{\"name\":\"gix-path\",\"req\":\"^0.11.2\"},{\"name\":\"gix-pathspec\",\"optional\":true,\"req\":\"^0.16.1\"},{\"name\":\"gix-prompt\",\"optional\":true,\"req\":\"^0.14.1\"},{\"name\":\"gix-protocol\",\"req\":\"^0.59.0\"},{\"name\":\"gix-ref\",\"req\":\"^0.61.0\"},{\"name\":\"gix-refspec\",\"req\":\"^0.39.0\"},{\"default_features\":false,\"name\":\"gix-revision\",\"req\":\"^0.43.0\"},{\"name\":\"gix-revwalk\",\"req\":\"^0.29.0\"},{\"name\":\"gix-sec\",\"req\":\"^0.13.2\"},{\"name\":\"gix-shallow\",\"req\":\"^0.10.0\"},{\"features\":[\"worktree-rewrites\"],\"name\":\"gix-status\",\"optional\":true,\"req\":\"^0.28.0\"},{\"name\":\"gix-submodule\",\"optional\":true,\"req\":\"^0.28.0\"},{\"default_features\":false,\"name\":\"gix-tempfile\",\"req\":\"^21.0.0\"},{\"name\":\"gix-trace\",\"req\":\"^0.1.18\"},{\"name\":\"gix-transport\",\"optional\":true,\"req\":\"^0.55.1\"},{\"name\":\"gix-traverse\",\"req\":\"^0.55.0\"},{\"name\":\"gix-url\",\"req\":\"^0.35.2\"},{\"name\":\"gix-utils\",\"req\":\"^0.3.1\"},{\"name\":\"gix-validate\",\"req\":\"^0.11.0\"},{\"default_features\":false,\"name\":\"gix-worktree\",\"optional\":true,\"req\":\"^0.50.0\"},{\"name\":\"gix-worktree-state\",\"optional\":true,\"req\":\"^0.28.0\"},{\"name\":\"gix-worktree-stream\",\"optional\":true,\"req\":\"^0.30.0\"},{\"kind\":\"dev\",\"name\":\"insta\",\"req\":\"^1.46.3\"},{\"kind\":\"dev\",\"name\":\"is_ci\",\"req\":\"^1.1.1\"},{\"name\":\"nonempty\",\"req\":\"^0.12.0\"},{\"name\":\"parking_lot\",\"optional\":true,\"req\":\"^0.12.4\"},{\"kind\":\"dev\",\"name\":\"pretty_assertions\",\"req\":\"^1.4.0\"},{\"features\":[\"progress-tree\"],\"name\":\"prodash\",\"optional\":true,\"req\":\"^31.0.0\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"regex\",\"optional\":true,\"req\":\"^1.12.3\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.114\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"serial_test\",\"req\":\"^3.4.0\"},{\"default_features\":false,\"name\":\"signal-hook\",\"optional\":true,\"req\":\"^0.4.3\"},{\"name\":\"smallvec\",\"req\":\"^1.15.1\"},{\"kind\":\"dev\",\"name\":\"termtree\",\"req\":\"^1.0.0\"},{\"name\":\"thiserror\",\"req\":\"^2.0.18\"},{\"kind\":\"dev\",\"name\":\"walkdir\",\"req\":\"^2.3.2\"}],\"features\":{\"async-network-client\":[\"gix-protocol/async-client\",\"gix-pack/streaming-input\",\"dep:gix-transport\",\"attributes\",\"credentials\"],\"async-network-client-async-std\":[\"async-std\",\"async-network-client\",\"gix-transport/async-std\"],\"attributes\":[\"excludes\",\"dep:gix-filter\",\"dep:gix-pathspec\",\"dep:gix-attributes\",\"dep:gix-submodule\",\"gix-worktree?/attributes\",\"command\"],\"auto-chain-error\":[\"gix-error/auto-chain-error\"],\"basic\":[\"blob-diff\",\"revision\",\"index\"],\"blame\":[\"dep:gix-blame\",\"blob-diff\"],\"blob-diff\":[\"gix-diff/blob\",\"attributes\"],\"blocking-http-transport-curl\":[\"blocking-network-client\",\"gix-transport/http-client-curl\"],\"blocking-http-transport-curl-openssl\":[\"blocking-http-transport-curl\",\"gix-transport/http-client-curl-openssl\"],\"blocking-http-transport-curl-rustls\":[\"blocking-http-transport-curl\",\"gix-transport/http-client-curl-rust-tls\"],\"blocking-http-transport-reqwest\":[\"blocking-network-client\",\"gix-transport/http-client-reqwest\"],\"blocking-http-transport-reqwest-native-tls\":[\"blocking-http-transport-reqwest\",\"gix-transport/http-client-reqwest-native-tls\"],\"blocking-http-transport-reqwest-rust-tls\":[\"blocking-http-transport-reqwest\",\"gix-transport/http-client-reqwest-rust-tls\"],\"blocking-http-transport-reqwest-rust-tls-trust-dns\":[\"blocking-http-transport-reqwest\",\"gix-transport/http-client-reqwest-rust-tls-trust-dns\"],\"blocking-network-client\":[\"gix-protocol/blocking-client\",\"gix-pack/streaming-input\",\"dep:gix-transport\",\"attributes\",\"credentials\"],\"cache-efficiency-debug\":[\"gix-features/cache-efficiency-debug\"],\"comfort\":[\"gix-features/progress-unit-bytes\",\"gix-features/progress-unit-human-numbers\"],\"command\":[\"dep:gix-command\"],\"credentials\":[\"dep:gix-credentials\",\"dep:gix-prompt\",\"dep:gix-negotiate\"],\"default\":[\"max-performance-safe\",\"comfort\",\"basic\",\"extras\",\"auto-chain-error\",\"sha1\"],\"dirwalk\":[\"dep:gix-dir\",\"attributes\",\"excludes\"],\"excludes\":[\"dep:gix-ignore\",\"dep:gix-worktree\",\"index\"],\"extras\":[\"worktree-stream\",\"worktree-archive\",\"revparse-regex\",\"mailmap\",\"excludes\",\"attributes\",\"worktree-mutation\",\"credentials\",\"interrupt\",\"status\",\"dirwalk\",\"blame\"],\"hp-tempfile-registry\":[\"gix-tempfile/hp-hashmap\"],\"index\":[\"dep:gix-index\"],\"interrupt\":[\"dep:signal-hook\",\"gix-tempfile/signals\",\"dep:parking_lot\"],\"mailmap\":[\"dep:gix-mailmap\",\"revision\"],\"max-control\":[\"parallel\",\"pack-cache-lru-static\",\"pack-cache-lru-dynamic\"],\"max-performance\":[\"max-performance-safe\"],\"max-performance-safe\":[\"max-control\"],\"merge\":[\"tree-editor\",\"blob-diff\",\"dep:gix-merge\",\"attributes\"],\"need-more-recent-msrv\":[\"merge\",\"tree-editor\"],\"pack-cache-lru-dynamic\":[\"gix-pack/pack-cache-lru-dynamic\"],\"pack-cache-lru-static\":[\"gix-pack/pack-cache-lru-static\"],\"parallel\":[\"gix-features/parallel\"],\"progress-tree\":[\"prodash/progress-tree\"],\"revision\":[\"gix-revision/describe\",\"gix-revision/merge_base\",\"index\"],\"revparse-regex\":[\"regex\",\"revision\"],\"serde\":[\"dep:serde\",\"gix-pack/serde\",\"gix-object/serde\",\"gix-protocol/serde\",\"gix-transport?/serde\",\"gix-ref/serde\",\"gix-odb/serde\",\"gix-index?/serde\",\"gix-mailmap?/serde\",\"gix-url/serde\",\"gix-attributes?/serde\",\"gix-ignore?/serde\",\"gix-revision/serde\",\"gix-worktree?/serde\",\"gix-commitgraph/serde\",\"gix-credentials?/serde\"],\"sha1\":[\"gix-archive?/sha1\",\"gix-blame?/sha1\",\"gix-commitgraph/sha1\",\"gix-config/sha1\",\"gix-diff/sha1\",\"gix-dir?/sha1\",\"gix-discover/sha1\",\"gix-filter?/sha1\",\"gix-hash/sha1\",\"gix-hashtable/sha1\",\"gix-index?/sha1\",\"gix-merge?/sha1\",\"gix-negotiate?/sha1\",\"gix-object/sha1\",\"gix-odb/sha1\",\"gix-pack/sha1\",\"gix-protocol/sha1\",\"gix-ref/sha1\",\"gix-refspec/sha1\",\"gix-revision/sha1\",\"gix-revwalk/sha1\",\"gix-shallow/sha1\",\"gix-status?/sha1\",\"gix-submodule?/sha1\",\"gix-traverse/sha1\",\"gix-worktree?/sha1\",\"gix-worktree-state?/sha1\",\"gix-worktree-stream?/sha1\"],\"status\":[\"gix-status\",\"dirwalk\",\"index\",\"blob-diff\",\"gix-diff/index\"],\"tracing\":[\"gix-features/tracing\"],\"tracing-detail\":[\"gix-features/tracing-detail\",\"tracing\"],\"tree-editor\":[],\"tree-error\":[\"gix-error/tree-error\"],\"verbose-object-parsing-errors\":[\"gix-object/verbose-object-parsing-errors\"],\"worktree-archive\":[\"gix-archive\",\"worktree-stream\",\"attributes\"],\"worktree-mutation\":[\"attributes\",\"dep:gix-worktree-state\"],\"worktree-stream\":[\"gix-worktree-stream\",\"attributes\"],\"zlib-ng\":[\"gix-features/zlib\"],\"zlib-ng-compat\":[\"gix-features/zlib\"],\"zlib-rs\":[\"gix-features/zlib\"],\"zlib-stock\":[\"gix-features/zlib\"]}}", "glib-macros_0.21.5": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"glib\",\"req\":\"^0.21\"},{\"name\":\"heck\",\"req\":\"^0.5\"},{\"name\":\"proc-macro-crate\",\"req\":\"^3.3\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0\"},{\"name\":\"quote\",\"req\":\"^1.0\"},{\"features\":[\"full\"],\"name\":\"syn\",\"req\":\"^2.0.104\"},{\"kind\":\"dev\",\"name\":\"trybuild2\",\"req\":\"^1.2\"}],\"features\":{}}", "glib-sys_0.21.5": "{\"dependencies\":[{\"name\":\"libc\",\"req\":\"^0.2\"},{\"kind\":\"dev\",\"name\":\"shell-words\",\"req\":\"^1.0.0\"},{\"kind\":\"build\",\"name\":\"system-deps\",\"req\":\"^7\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3\"}],\"features\":{\"v2_58\":[],\"v2_60\":[\"v2_58\"],\"v2_62\":[\"v2_60\"],\"v2_64\":[\"v2_62\"],\"v2_66\":[\"v2_64\"],\"v2_68\":[\"v2_66\"],\"v2_70\":[\"v2_68\"],\"v2_72\":[\"v2_70\"],\"v2_74\":[\"v2_72\"],\"v2_76\":[\"v2_74\"],\"v2_78\":[\"v2_76\"],\"v2_80\":[\"v2_78\"],\"v2_82\":[\"v2_80\"],\"v2_84\":[\"v2_82\"],\"v2_86\":[\"v2_84\"]}}", "glib_0.21.5": "{\"dependencies\":[{\"name\":\"bitflags\",\"req\":\"^2.9\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.7.0\"},{\"name\":\"futures-channel\",\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"futures-core\",\"req\":\"^0.3\"},{\"name\":\"futures-executor\",\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"futures-task\",\"req\":\"^0.3\"},{\"name\":\"futures-util\",\"req\":\"^0.3\"},{\"name\":\"gio-sys\",\"optional\":true,\"req\":\"^0.21\"},{\"kind\":\"dev\",\"name\":\"gir-format-check\",\"req\":\"^0.1\"},{\"name\":\"glib-macros\",\"req\":\"^0.21\"},{\"name\":\"glib-sys\",\"req\":\"^0.21\"},{\"name\":\"gobject-sys\",\"req\":\"^0.21\"},{\"name\":\"libc\",\"req\":\"^0.2\"},{\"name\":\"memchr\",\"req\":\"^2.7.5\"},{\"name\":\"rs-log\",\"optional\":true,\"package\":\"log\",\"req\":\"^0.4\"},{\"features\":[\"union\",\"const_generics\",\"const_new\"],\"name\":\"smallvec\",\"req\":\"^1.15\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3\"},{\"kind\":\"dev\",\"name\":\"trybuild2\",\"req\":\"^1\"}],\"features\":{\"compiletests\":[],\"default\":[\"gio\"],\"gio\":[\"gio-sys\"],\"log\":[\"rs-log\"],\"log_macros\":[\"log\"],\"v2_58\":[\"glib-sys/v2_58\",\"gobject-sys/v2_58\"],\"v2_60\":[\"v2_58\",\"glib-sys/v2_60\"],\"v2_62\":[\"v2_60\",\"glib-sys/v2_62\",\"gobject-sys/v2_62\"],\"v2_64\":[\"v2_62\",\"glib-sys/v2_64\"],\"v2_66\":[\"v2_64\",\"glib-sys/v2_66\",\"gobject-sys/v2_66\"],\"v2_68\":[\"v2_66\",\"glib-sys/v2_68\",\"gobject-sys/v2_68\"],\"v2_70\":[\"v2_68\",\"glib-sys/v2_70\",\"gobject-sys/v2_70\"],\"v2_72\":[\"v2_70\",\"glib-sys/v2_72\",\"gobject-sys/v2_72\"],\"v2_74\":[\"v2_72\",\"glib-sys/v2_74\",\"gobject-sys/v2_74\"],\"v2_76\":[\"v2_74\",\"glib-sys/v2_76\",\"gobject-sys/v2_76\"],\"v2_78\":[\"v2_76\",\"glib-sys/v2_78\",\"gobject-sys/v2_78\"],\"v2_80\":[\"v2_78\",\"glib-sys/v2_80\",\"gobject-sys/v2_80\"],\"v2_82\":[\"v2_80\",\"glib-sys/v2_82\",\"gobject-sys/v2_82\"],\"v2_84\":[\"v2_82\",\"glib-sys/v2_84\",\"gobject-sys/v2_84\"],\"v2_86\":[\"v2_84\",\"glib-sys/v2_86\",\"gobject-sys/v2_86\"]}}", @@ -954,6 +1010,7 @@ "h2_0.4.13": "{\"dependencies\":[{\"name\":\"atomic-waker\",\"req\":\"^1.0.0\"},{\"name\":\"bytes\",\"req\":\"^1\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.10\"},{\"name\":\"fnv\",\"req\":\"^1.0.5\"},{\"default_features\":false,\"name\":\"futures-core\",\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"futures-sink\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"hex\",\"req\":\"^0.4.3\"},{\"name\":\"http\",\"req\":\"^1\"},{\"features\":[\"std\"],\"name\":\"indexmap\",\"req\":\"^2\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0.3\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.4\"},{\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.0\"},{\"name\":\"slab\",\"req\":\"^0.4.2\"},{\"features\":[\"io-util\"],\"name\":\"tokio\",\"req\":\"^1\"},{\"features\":[\"rt-multi-thread\",\"macros\",\"sync\",\"net\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"tokio-rustls\",\"req\":\"^0.26\"},{\"features\":[\"codec\",\"io\"],\"name\":\"tokio-util\",\"req\":\"^0.7.1\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"tracing\",\"req\":\"^0.1.35\"},{\"kind\":\"dev\",\"name\":\"walkdir\",\"req\":\"^2.3.2\"},{\"kind\":\"dev\",\"name\":\"webpki-roots\",\"req\":\"^1\"}],\"features\":{\"stream\":[],\"unstable\":[]}}", "h2_0.4.6": "{\"dependencies\":[{\"name\":\"atomic-waker\",\"req\":\"^1.0.0\"},{\"name\":\"bytes\",\"req\":\"^1\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.10\"},{\"name\":\"fnv\",\"req\":\"^1.0.5\"},{\"default_features\":false,\"name\":\"futures-core\",\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"futures-sink\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"hex\",\"req\":\"^0.4.3\"},{\"name\":\"http\",\"req\":\"^1\"},{\"features\":[\"std\"],\"name\":\"indexmap\",\"req\":\"^2\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0.3\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.4\"},{\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.0\"},{\"name\":\"slab\",\"req\":\"^0.4.2\"},{\"features\":[\"io-util\"],\"name\":\"tokio\",\"req\":\"^1\"},{\"features\":[\"rt-multi-thread\",\"macros\",\"sync\",\"net\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"tokio-rustls\",\"req\":\"^0.26\"},{\"features\":[\"codec\",\"io\"],\"name\":\"tokio-util\",\"req\":\"^0.7.1\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"tracing\",\"req\":\"^0.1.35\"},{\"kind\":\"dev\",\"name\":\"walkdir\",\"req\":\"^2.3.2\"},{\"kind\":\"dev\",\"name\":\"webpki-roots\",\"req\":\"^0.26\"}],\"features\":{\"stream\":[],\"unstable\":[]}}", "half_2.7.1": "{\"dependencies\":[{\"features\":[\"derive\"],\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1.4.1\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"bytemuck\",\"optional\":true,\"req\":\"^1.4.1\"},{\"name\":\"cfg-if\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5\"},{\"name\":\"crunchy\",\"req\":\"^0.2.2\",\"target\":\"cfg(target_arch = \\\"spirv\\\")\"},{\"kind\":\"dev\",\"name\":\"crunchy\",\"req\":\"^0.2.2\"},{\"default_features\":false,\"features\":[\"libm\"],\"name\":\"num-traits\",\"optional\":true,\"req\":\"^0.2.16\"},{\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"quickcheck_macros\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"thread_rng\"],\"name\":\"rand\",\"optional\":true,\"req\":\"^0.9.0\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9.0\"},{\"default_features\":false,\"name\":\"rand_distr\",\"optional\":true,\"req\":\"^0.5.0\"},{\"name\":\"rkyv\",\"optional\":true,\"req\":\"^0.8.0\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"derive\",\"simd\"],\"name\":\"zerocopy\",\"req\":\"^0.8.26\"}],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"nightly\":[],\"rand_distr\":[\"dep:rand\",\"dep:rand_distr\"],\"std\":[\"alloc\"],\"use-intrinsics\":[],\"zerocopy\":[]}}", + "hash32_0.3.1": "{\"dependencies\":[{\"default_features\":false,\"name\":\"byteorder\",\"req\":\"^1.2.2\"}],\"features\":{}}", "hashbrown_0.12.3": "{\"dependencies\":[{\"default_features\":false,\"name\":\"ahash\",\"optional\":true,\"req\":\"^0.7.0\"},{\"name\":\"alloc\",\"optional\":true,\"package\":\"rustc-std-workspace-alloc\",\"req\":\"^1.0.0\"},{\"name\":\"bumpalo\",\"optional\":true,\"req\":\"^3.5.0\"},{\"name\":\"compiler_builtins\",\"optional\":true,\"req\":\"^0.1.2\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3.1\"},{\"kind\":\"dev\",\"name\":\"fnv\",\"req\":\"^1.0.7\"},{\"kind\":\"dev\",\"name\":\"lazy_static\",\"req\":\"^1.4\"},{\"features\":[\"small_rng\"],\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.3\"},{\"name\":\"rayon\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.25\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0\"}],\"features\":{\"ahash-compile-time-rng\":[\"ahash/compile-time-rng\"],\"default\":[\"ahash\",\"inline-more\"],\"inline-more\":[],\"nightly\":[],\"raw\":[],\"rustc-dep-of-std\":[\"nightly\",\"core\",\"compiler_builtins\",\"alloc\",\"rustc-internal-api\"],\"rustc-internal-api\":[]}}", "hashbrown_0.14.5": "{\"dependencies\":[{\"default_features\":false,\"name\":\"ahash\",\"optional\":true,\"req\":\"^0.8.7\"},{\"name\":\"alloc\",\"optional\":true,\"package\":\"rustc-std-workspace-alloc\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"allocator-api2\",\"optional\":true,\"req\":\"^0.2.9\"},{\"features\":[\"allocator-api2\"],\"kind\":\"dev\",\"name\":\"bumpalo\",\"req\":\"^3.13.0\"},{\"name\":\"compiler_builtins\",\"optional\":true,\"req\":\"^0.1.2\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3.1\"},{\"default_features\":false,\"name\":\"equivalent\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"fnv\",\"req\":\"^1.0.7\"},{\"kind\":\"dev\",\"name\":\"lazy_static\",\"req\":\"^1.4\"},{\"features\":[\"small_rng\"],\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.3\"},{\"name\":\"rayon\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"rkyv\",\"optional\":true,\"req\":\"^0.7.42\"},{\"features\":[\"validation\"],\"kind\":\"dev\",\"name\":\"rkyv\",\"req\":\"^0.7.42\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.25\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0\"}],\"features\":{\"default\":[\"ahash\",\"inline-more\",\"allocator-api2\"],\"inline-more\":[],\"nightly\":[\"allocator-api2?/nightly\",\"bumpalo/allocator_api\"],\"raw\":[],\"rustc-dep-of-std\":[\"nightly\",\"core\",\"compiler_builtins\",\"alloc\",\"rustc-internal-api\"],\"rustc-internal-api\":[]}}", "hashbrown_0.15.5": "{\"dependencies\":[{\"name\":\"alloc\",\"optional\":true,\"package\":\"rustc-std-workspace-alloc\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"allocator-api2\",\"optional\":true,\"req\":\"^0.2.9\"},{\"features\":[\"allocator-api2\"],\"kind\":\"dev\",\"name\":\"bumpalo\",\"req\":\"^3.13.0\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3.1\"},{\"default_features\":false,\"name\":\"equivalent\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"fnv\",\"req\":\"^1.0.7\"},{\"default_features\":false,\"name\":\"foldhash\",\"optional\":true,\"req\":\"^0.1.2\"},{\"kind\":\"dev\",\"name\":\"lazy_static\",\"req\":\"^1.4\"},{\"features\":[\"small_rng\"],\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9.0\"},{\"name\":\"rayon\",\"optional\":true,\"req\":\"^1.2\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1.2\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.25\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0\"}],\"features\":{\"default\":[\"default-hasher\",\"inline-more\",\"allocator-api2\",\"equivalent\",\"raw-entry\"],\"default-hasher\":[\"dep:foldhash\"],\"inline-more\":[],\"nightly\":[\"bumpalo/allocator_api\"],\"raw-entry\":[],\"rustc-dep-of-std\":[\"nightly\",\"core\",\"alloc\",\"rustc-internal-api\"],\"rustc-internal-api\":[]}}", @@ -961,6 +1018,7 @@ "hashlink_0.10.0": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"default-hasher\",\"inline-more\"],\"name\":\"hashbrown\",\"req\":\"^0.15\"},{\"kind\":\"dev\",\"name\":\"rustc-hash\",\"req\":\"^2\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0\"}],\"features\":{\"serde_impl\":[\"serde\"]}}", "headers-core_0.3.0": "{\"dependencies\":[{\"name\":\"http\",\"req\":\"^1.0.0\"}],\"features\":{}}", "headers_0.4.1": "{\"dependencies\":[{\"name\":\"base64\",\"req\":\"^0.22\"},{\"name\":\"bytes\",\"req\":\"^1\"},{\"name\":\"headers-core\",\"req\":\"^0.3\"},{\"name\":\"http\",\"req\":\"^1.0.0\"},{\"name\":\"httpdate\",\"req\":\"^1\"},{\"name\":\"mime\",\"req\":\"^0.3.14\"},{\"name\":\"sha1\",\"req\":\"^0.10\"}],\"features\":{\"nightly\":[]}}", + "heapless_0.8.0": "{\"dependencies\":[{\"name\":\"defmt\",\"optional\":true,\"req\":\">=0.2.0, <0.4\"},{\"name\":\"hash32\",\"req\":\"^0.3.0\"},{\"name\":\"portable-atomic\",\"optional\":true,\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1\"},{\"default_features\":false,\"name\":\"stable_deref_trait\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"ufmt\",\"req\":\"^0.2\"},{\"name\":\"ufmt-write\",\"optional\":true,\"req\":\"^0.1\"}],\"features\":{\"defmt-03\":[\"dep:defmt\"],\"mpmc_large\":[],\"portable-atomic\":[\"dep:portable-atomic\"],\"portable-atomic-critical-section\":[\"dep:portable-atomic\",\"portable-atomic\",\"portable-atomic?/critical-section\"],\"portable-atomic-unsafe-assume-single-core\":[\"dep:portable-atomic\",\"portable-atomic\",\"portable-atomic?/unsafe-assume-single-core\"],\"serde\":[\"dep:serde\"],\"ufmt\":[\"dep:ufmt-write\"]}}", "heck_0.4.1": "{\"dependencies\":[{\"name\":\"unicode-segmentation\",\"optional\":true,\"req\":\"^1.2.0\"}],\"features\":{\"default\":[],\"unicode\":[\"unicode-segmentation\"]}}", "heck_0.5.0": "{\"dependencies\":[],\"features\":{}}", "hermit-abi_0.5.2": "{\"dependencies\":[{\"name\":\"alloc\",\"optional\":true,\"package\":\"rustc-std-workspace-alloc\",\"req\":\"^1.0.0\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"}],\"features\":{\"default\":[],\"rustc-dep-of-std\":[\"core\",\"alloc\"]}}", @@ -1011,6 +1069,8 @@ "ignore_0.4.25": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"bstr\",\"req\":\"^1.6.2\"},{\"kind\":\"dev\",\"name\":\"crossbeam-channel\",\"req\":\"^0.5.15\"},{\"name\":\"crossbeam-deque\",\"req\":\"^0.8.3\"},{\"name\":\"globset\",\"req\":\"^0.4.18\"},{\"name\":\"log\",\"req\":\"^0.4.20\"},{\"name\":\"memchr\",\"req\":\"^2.6.3\"},{\"default_features\":false,\"features\":[\"std\",\"perf\",\"syntax\",\"meta\",\"nfa\",\"hybrid\",\"dfa-onepass\"],\"name\":\"regex-automata\",\"req\":\"^0.4.0\"},{\"name\":\"same-file\",\"req\":\"^1.0.6\"},{\"name\":\"walkdir\",\"req\":\"^2.4.0\"},{\"name\":\"winapi-util\",\"req\":\"^0.1.2\",\"target\":\"cfg(windows)\"}],\"features\":{\"simd-accel\":[]}}", "image-webp_0.2.4": "{\"dependencies\":[{\"name\":\"byteorder-lite\",\"req\":\"^0.1.0\"},{\"kind\":\"dev\",\"name\":\"paste\",\"req\":\"^1.0.14\"},{\"kind\":\"dev\",\"name\":\"png\",\"req\":\"^0.17.12\"},{\"name\":\"quick-error\",\"req\":\"^2.0.1\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.5\"},{\"kind\":\"dev\",\"name\":\"webp\",\"req\":\"^0.3.0\"}],\"features\":{\"_benchmarks\":[]}}", "image_0.25.9": "{\"dependencies\":[{\"features\":[\"extern_crate_alloc\"],\"name\":\"bytemuck\",\"req\":\"^1.8.0\"},{\"name\":\"byteorder-lite\",\"req\":\"^0.1.0\"},{\"name\":\"color_quant\",\"optional\":true,\"req\":\"^1.1\"},{\"kind\":\"dev\",\"name\":\"crc32fast\",\"req\":\"^1.2.0\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5.0\"},{\"name\":\"dav1d\",\"optional\":true,\"req\":\"^0.10.3\"},{\"default_features\":false,\"name\":\"exr\",\"optional\":true,\"req\":\"^1.74.0\"},{\"name\":\"gif\",\"optional\":true,\"req\":\"^0.14.0\"},{\"kind\":\"dev\",\"name\":\"glob\",\"req\":\"^0.3\"},{\"name\":\"image-webp\",\"optional\":true,\"req\":\"^0.2.0\"},{\"name\":\"moxcms\",\"req\":\"^0.7.4\"},{\"name\":\"mp4parse\",\"optional\":true,\"req\":\"^0.17.0\"},{\"kind\":\"dev\",\"name\":\"num-complex\",\"req\":\"^0.4\"},{\"name\":\"num-traits\",\"req\":\"^0.2.0\"},{\"name\":\"png\",\"optional\":true,\"req\":\"^0.18.0\"},{\"name\":\"qoi\",\"optional\":true,\"req\":\"^0.4\"},{\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"ravif\",\"optional\":true,\"req\":\"^0.12\"},{\"name\":\"rayon\",\"optional\":true,\"req\":\"^1.7.0\"},{\"default_features\":false,\"name\":\"rgb\",\"optional\":true,\"req\":\"^0.8.48\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.214\"},{\"name\":\"tiff\",\"optional\":true,\"req\":\"^0.10.3\"},{\"default_features\":false,\"name\":\"zune-core\",\"optional\":true,\"req\":\"^0.5.0\"},{\"name\":\"zune-jpeg\",\"optional\":true,\"req\":\"^0.5.5\"}],\"features\":{\"avif\":[\"dep:ravif\",\"dep:rgb\"],\"avif-native\":[\"dep:mp4parse\",\"dep:dav1d\"],\"benchmarks\":[],\"bmp\":[],\"color_quant\":[\"dep:color_quant\"],\"dds\":[],\"default\":[\"rayon\",\"default-formats\"],\"default-formats\":[\"avif\",\"bmp\",\"dds\",\"exr\",\"ff\",\"gif\",\"hdr\",\"ico\",\"jpeg\",\"png\",\"pnm\",\"qoi\",\"tga\",\"tiff\",\"webp\"],\"exr\":[\"dep:exr\"],\"ff\":[],\"gif\":[\"dep:gif\",\"dep:color_quant\"],\"hdr\":[],\"ico\":[\"bmp\",\"png\"],\"jpeg\":[\"dep:zune-core\",\"dep:zune-jpeg\"],\"nasm\":[\"ravif?/asm\"],\"png\":[\"dep:png\"],\"pnm\":[],\"qoi\":[\"dep:qoi\"],\"rayon\":[\"dep:rayon\",\"ravif?/threading\",\"exr?/rayon\"],\"serde\":[\"dep:serde\"],\"tga\":[],\"tiff\":[\"dep:tiff\"],\"webp\":[\"dep:image-webp\"]}}", + "imara-diff_0.1.8": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"expect-test\",\"req\":\"^1.4.0\"},{\"default_features\":false,\"features\":[\"default-hasher\",\"inline-more\"],\"name\":\"hashbrown\",\"req\":\"^0.15\"}],\"features\":{\"default\":[\"unified_diff\"],\"unified_diff\":[]}}", + "imara-diff_0.2.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"expect-test\",\"req\":\"^1.4.0\"},{\"default_features\":false,\"features\":[\"default-hasher\",\"inline-more\"],\"name\":\"hashbrown\",\"req\":\"^0.15\"},{\"name\":\"memchr\",\"req\":\"^2.7.4\"}],\"features\":{\"default\":[\"unified_diff\"],\"unified_diff\":[]}}", "impl-more_0.1.9": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"eyre\",\"req\":\"^0.6\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.1\"}],\"features\":{}}", "include_dir_0.7.4": "{\"dependencies\":[{\"name\":\"glob\",\"optional\":true,\"req\":\"^0.3\"},{\"name\":\"include_dir_macros\",\"req\":\"^0.7.4\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3\"}],\"features\":{\"default\":[],\"metadata\":[\"include_dir_macros/metadata\"],\"nightly\":[\"include_dir_macros/nightly\"]}}", "include_dir_macros_0.7.4": "{\"dependencies\":[{\"name\":\"proc-macro2\",\"req\":\"^1\"},{\"name\":\"quote\",\"req\":\"^1\"}],\"features\":{\"metadata\":[],\"nightly\":[]}}", @@ -1026,6 +1086,7 @@ "intl-memoizer_0.5.3": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"fluent-langneg\",\"req\":\"^0.13\"},{\"kind\":\"dev\",\"name\":\"intl_pluralrules\",\"req\":\"^7.0\"},{\"name\":\"type-map\",\"req\":\"^0.5\"},{\"name\":\"unic-langid\",\"req\":\"^0.9\"}],\"features\":{}}", "intl_pluralrules_7.0.2": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.3\"},{\"name\":\"unic-langid\",\"req\":\"^0.9\"},{\"features\":[\"macros\"],\"kind\":\"dev\",\"name\":\"unic-langid\",\"req\":\"^0.9\"}],\"features\":{}}", "inventory_0.3.21": "{\"dependencies\":[{\"name\":\"rustversion\",\"req\":\"^1.0\",\"target\":\"cfg(target_family = \\\"wasm\\\")\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0\"},{\"features\":[\"diff\"],\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.89\"}],\"features\":{}}", + "io-close_0.3.7": "{\"dependencies\":[{\"name\":\"libc\",\"req\":\"^0.2.80\",\"target\":\"cfg(unix)\"},{\"name\":\"os_pipe\",\"optional\":true,\"req\":\"^0.9.2\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.1.0\"},{\"features\":[\"handleapi\",\"std\",\"winsock2\"],\"name\":\"winapi\",\"req\":\"^0.3.9\",\"target\":\"cfg(windows)\"}],\"features\":{}}", "io_tee_0.1.1": "{\"dependencies\":[],\"features\":{}}", "ipconfig_0.3.2": "{\"dependencies\":[{\"name\":\"socket2\",\"req\":\"^0.5.1\",\"target\":\"cfg(windows)\"},{\"name\":\"widestring\",\"req\":\"^1.0.2\",\"target\":\"cfg(windows)\"},{\"features\":[\"Win32_Foundation\",\"Win32_Networking_WinSock\",\"Win32_System_Registry\"],\"name\":\"windows-sys\",\"req\":\"^0.48.0\",\"target\":\"cfg(windows)\"},{\"name\":\"winreg\",\"optional\":true,\"req\":\"^0.50.0\",\"target\":\"cfg(windows)\"}],\"features\":{\"computer\":[\"winreg\"],\"default\":[\"computer\"]}}", "ipnet_2.11.0": "{\"dependencies\":[{\"name\":\"heapless\",\"optional\":true,\"req\":\"^0\"},{\"name\":\"schemars\",\"optional\":true,\"req\":\"^0.8\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"package\":\"serde\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1\"}],\"features\":{\"default\":[\"std\"],\"json\":[\"serde\",\"schemars\"],\"ser_as_str\":[\"heapless\"],\"std\":[]}}", @@ -1041,9 +1102,9 @@ "itoa_1.0.17": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.8\",\"target\":\"cfg(not(miri))\"},{\"name\":\"no-panic\",\"optional\":true,\"req\":\"^0.1\"}],\"features\":{}}", "itoa_1.0.18": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.8\",\"target\":\"cfg(not(miri))\"},{\"name\":\"no-panic\",\"optional\":true,\"req\":\"^0.1\"}],\"features\":{}}", "ixdtf_0.6.4": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"serde-json-core\",\"req\":\"^0.6.0\"}],\"features\":{\"default\":[\"duration\"],\"duration\":[]}}", - "jiff-static_0.2.18": "{\"dependencies\":[{\"name\":\"jiff-tzdb\",\"optional\":true,\"req\":\"^0.1.4\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.93\"},{\"name\":\"quote\",\"req\":\"^1.0.38\"},{\"name\":\"syn\",\"req\":\"^2.0.98\"}],\"features\":{\"default\":[],\"perf-inline\":[],\"tz-fat\":[],\"tzdb\":[\"dep:jiff-tzdb\"]}}", "jiff-static_0.2.23": "{\"dependencies\":[{\"name\":\"jiff-tzdb\",\"optional\":true,\"req\":\"^0.1.6\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.93\"},{\"name\":\"quote\",\"req\":\"^1.0.38\"},{\"name\":\"syn\",\"req\":\"^2.0.98\"}],\"features\":{\"default\":[],\"perf-inline\":[],\"tz-fat\":[],\"tzdb\":[\"dep:jiff-tzdb\"]}}", - "jiff_0.2.18": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0.81\"},{\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"chrono\",\"req\":\"^0.4.38\"},{\"kind\":\"dev\",\"name\":\"chrono-tz\",\"req\":\"^0.10.0\"},{\"kind\":\"dev\",\"name\":\"hifitime\",\"req\":\"^3.9.0\",\"target\":\"cfg(not(target_family = \\\"wasm\\\"))\"},{\"kind\":\"dev\",\"name\":\"humantime\",\"req\":\"^2.1.0\"},{\"kind\":\"dev\",\"name\":\"insta\",\"req\":\"^1.39.0\"},{\"name\":\"jiff-static\",\"req\":\"=0.2.18\",\"target\":\"cfg(any())\"},{\"name\":\"jiff-static\",\"optional\":true,\"req\":\"^0.2\"},{\"name\":\"jiff-tzdb\",\"optional\":true,\"req\":\"^0.1.5\"},{\"name\":\"jiff-tzdb-platform\",\"optional\":true,\"req\":\"^0.1.3\",\"target\":\"cfg(any(windows, target_family = \\\"wasm\\\"))\"},{\"name\":\"js-sys\",\"optional\":true,\"req\":\"^0.3.50\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"},{\"default_features\":false,\"name\":\"log\",\"optional\":true,\"req\":\"^0.4.21\"},{\"kind\":\"dev\",\"name\":\"log\",\"req\":\"^0.4.21\"},{\"default_features\":false,\"name\":\"portable-atomic\",\"req\":\"^1.10.0\",\"target\":\"cfg(not(target_has_atomic = \\\"ptr\\\"))\"},{\"default_features\":false,\"name\":\"portable-atomic-util\",\"req\":\"^0.2.4\",\"target\":\"cfg(not(target_has_atomic = \\\"ptr\\\"))\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0.3\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.203\"},{\"default_features\":false,\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0.221\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.117\"},{\"kind\":\"dev\",\"name\":\"serde_yaml\",\"req\":\"^0.9.34\"},{\"kind\":\"dev\",\"name\":\"tabwriter\",\"req\":\"^1.4.0\"},{\"features\":[\"local-offset\",\"macros\",\"parsing\"],\"kind\":\"dev\",\"name\":\"time\",\"req\":\"^0.3.36\"},{\"kind\":\"dev\",\"name\":\"tzfile\",\"req\":\"^0.1.3\"},{\"kind\":\"dev\",\"name\":\"walkdir\",\"req\":\"^2.5.0\"},{\"name\":\"wasm-bindgen\",\"optional\":true,\"req\":\"^0.2.70\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"},{\"default_features\":false,\"features\":[\"Win32_Foundation\",\"Win32_System_Time\"],\"name\":\"windows-sys\",\"optional\":true,\"req\":\">=0.52.0, <=0.61\",\"target\":\"cfg(windows)\"}],\"features\":{\"alloc\":[\"serde_core?/alloc\",\"portable-atomic-util/alloc\"],\"default\":[\"std\",\"tz-system\",\"tz-fat\",\"tzdb-bundle-platform\",\"tzdb-zoneinfo\",\"tzdb-concatenated\",\"perf-inline\"],\"js\":[\"dep:wasm-bindgen\",\"dep:js-sys\"],\"logging\":[\"dep:log\"],\"perf-inline\":[],\"serde\":[\"dep:serde_core\"],\"static\":[\"static-tz\",\"jiff-static?/tzdb\"],\"static-tz\":[\"dep:jiff-static\"],\"std\":[\"alloc\",\"log?/std\",\"serde_core?/std\"],\"tz-fat\":[\"jiff-static?/tz-fat\"],\"tz-system\":[\"std\",\"dep:windows-sys\"],\"tzdb-bundle-always\":[\"dep:jiff-tzdb\",\"alloc\"],\"tzdb-bundle-platform\":[\"dep:jiff-tzdb-platform\",\"alloc\"],\"tzdb-concatenated\":[\"std\"],\"tzdb-zoneinfo\":[\"std\"]}}", + "jiff-tzdb-platform_0.1.3": "{\"dependencies\":[{\"name\":\"jiff-tzdb\",\"req\":\"^0.1.4\"}],\"features\":{}}", + "jiff-tzdb_0.1.6": "{\"dependencies\":[],\"features\":{}}", "jiff_0.2.23": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0.81\"},{\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"chrono\",\"req\":\"^0.4.38\"},{\"kind\":\"dev\",\"name\":\"chrono-tz\",\"req\":\"^0.10.0\"},{\"kind\":\"dev\",\"name\":\"hifitime\",\"req\":\"^3.9.0\",\"target\":\"cfg(not(target_family = \\\"wasm\\\"))\"},{\"kind\":\"dev\",\"name\":\"humantime\",\"req\":\"^2.1.0\"},{\"kind\":\"dev\",\"name\":\"insta\",\"req\":\"^1.39.0\"},{\"name\":\"jiff-static\",\"req\":\"=0.2.23\",\"target\":\"cfg(any())\"},{\"name\":\"jiff-static\",\"optional\":true,\"req\":\"^0.2\"},{\"name\":\"jiff-tzdb\",\"optional\":true,\"req\":\"^0.1.6\"},{\"name\":\"jiff-tzdb-platform\",\"optional\":true,\"req\":\"^0.1.3\",\"target\":\"cfg(any(windows, target_family = \\\"wasm\\\"))\"},{\"name\":\"js-sys\",\"optional\":true,\"req\":\"^0.3.50\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"},{\"default_features\":false,\"name\":\"log\",\"optional\":true,\"req\":\"^0.4.21\"},{\"kind\":\"dev\",\"name\":\"log\",\"req\":\"^0.4.21\"},{\"default_features\":false,\"name\":\"portable-atomic\",\"req\":\"^1.10.0\",\"target\":\"cfg(not(target_has_atomic = \\\"ptr\\\"))\"},{\"default_features\":false,\"name\":\"portable-atomic-util\",\"req\":\"^0.2.4\",\"target\":\"cfg(not(target_has_atomic = \\\"ptr\\\"))\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0.3\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.203\"},{\"default_features\":false,\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0.221\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.117\"},{\"kind\":\"dev\",\"name\":\"serde_yaml\",\"req\":\"^0.9.34\"},{\"kind\":\"dev\",\"name\":\"tabwriter\",\"req\":\"^1.4.0\"},{\"features\":[\"local-offset\",\"macros\",\"parsing\"],\"kind\":\"dev\",\"name\":\"time\",\"req\":\"^0.3.36\"},{\"kind\":\"dev\",\"name\":\"time-tz\",\"req\":\"^2.0.0\"},{\"kind\":\"dev\",\"name\":\"tzfile\",\"req\":\"^0.1.3\"},{\"kind\":\"dev\",\"name\":\"walkdir\",\"req\":\"^2.5.0\"},{\"name\":\"wasm-bindgen\",\"optional\":true,\"req\":\"^0.2.70\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"},{\"default_features\":false,\"features\":[\"Win32_Foundation\",\"Win32_System_Time\"],\"name\":\"windows-sys\",\"optional\":true,\"req\":\">=0.52.0, <=0.61\",\"target\":\"cfg(windows)\"}],\"features\":{\"alloc\":[\"serde_core?/alloc\",\"portable-atomic-util/alloc\"],\"default\":[\"std\",\"tz-system\",\"tz-fat\",\"tzdb-bundle-platform\",\"tzdb-zoneinfo\",\"tzdb-concatenated\",\"perf-inline\"],\"js\":[\"dep:wasm-bindgen\",\"dep:js-sys\"],\"logging\":[\"dep:log\"],\"perf-inline\":[],\"serde\":[\"dep:serde_core\"],\"static\":[\"static-tz\",\"jiff-static?/tzdb\"],\"static-tz\":[\"dep:jiff-static\"],\"std\":[\"alloc\",\"log?/std\",\"serde_core?/std\"],\"tz-fat\":[\"jiff-static?/tz-fat\"],\"tz-system\":[\"std\",\"dep:windows-sys\"],\"tzdb-bundle-always\":[\"dep:jiff-tzdb\",\"alloc\"],\"tzdb-bundle-platform\":[\"dep:jiff-tzdb-platform\",\"alloc\"],\"tzdb-concatenated\":[\"std\"],\"tzdb-zoneinfo\":[\"std\"]}}", "jni-sys_0.3.0": "{\"dependencies\":[],\"features\":{}}", "jni_0.21.1": "{\"dependencies\":[{\"name\":\"cesu8\",\"req\":\"^1.1.0\"},{\"name\":\"cfg-if\",\"req\":\"^1.0.0\"},{\"name\":\"combine\",\"req\":\"^4.1.0\"},{\"name\":\"java-locator\",\"optional\":true,\"req\":\"^0.1\"},{\"name\":\"jni-sys\",\"req\":\"^0.3.0\"},{\"name\":\"libloading\",\"optional\":true,\"req\":\"^0.7\"},{\"name\":\"log\",\"req\":\"^0.4.4\"},{\"name\":\"thiserror\",\"req\":\"^1.0.20\"},{\"kind\":\"dev\",\"name\":\"assert_matches\",\"req\":\"^1.5.0\"},{\"kind\":\"dev\",\"name\":\"lazy_static\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"rusty-fork\",\"req\":\"^0.3.0\"},{\"kind\":\"build\",\"name\":\"walkdir\",\"req\":\"^2\"},{\"features\":[\"Win32_Globalization\"],\"name\":\"windows-sys\",\"req\":\"^0.45.0\",\"target\":\"cfg(windows)\"},{\"kind\":\"dev\",\"name\":\"bytemuck\",\"req\":\"^1.13.0\",\"target\":\"cfg(windows)\"}],\"features\":{\"default\":[],\"invocation\":[\"java-locator\",\"libloading\"]}}", @@ -1053,6 +1114,7 @@ "keyring_3.6.3": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"base64\",\"req\":\"^0.22\"},{\"name\":\"byteorder\",\"optional\":true,\"req\":\"^1.2\",\"target\":\"cfg(target_os = \\\"windows\\\")\"},{\"features\":[\"derive\",\"wrap_help\"],\"kind\":\"dev\",\"name\":\"clap\",\"req\":\"^4\"},{\"name\":\"dbus-secret-service\",\"optional\":true,\"req\":\"^4.0.0-rc.1\",\"target\":\"cfg(target_os = \\\"openbsd\\\")\"},{\"name\":\"dbus-secret-service\",\"optional\":true,\"req\":\"^4.0.0-rc.2\",\"target\":\"cfg(target_os = \\\"linux\\\")\"},{\"name\":\"dbus-secret-service\",\"optional\":true,\"req\":\"^4.0.1\",\"target\":\"cfg(target_os = \\\"freebsd\\\")\"},{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.11.5\"},{\"kind\":\"dev\",\"name\":\"fastrand\",\"req\":\"^2\"},{\"features\":[\"std\"],\"name\":\"linux-keyutils\",\"optional\":true,\"req\":\"^0.2\",\"target\":\"cfg(target_os = \\\"linux\\\")\"},{\"name\":\"log\",\"req\":\"^0.4.22\"},{\"name\":\"openssl\",\"optional\":true,\"req\":\"^0.10.66\"},{\"kind\":\"dev\",\"name\":\"rpassword\",\"req\":\"^7\"},{\"kind\":\"dev\",\"name\":\"rprompt\",\"req\":\"^2\"},{\"name\":\"secret-service\",\"optional\":true,\"req\":\"^4\",\"target\":\"cfg(target_os = \\\"freebsd\\\")\"},{\"name\":\"secret-service\",\"optional\":true,\"req\":\"^4\",\"target\":\"cfg(target_os = \\\"linux\\\")\"},{\"name\":\"secret-service\",\"optional\":true,\"req\":\"^4\",\"target\":\"cfg(target_os = \\\"openbsd\\\")\"},{\"name\":\"security-framework\",\"optional\":true,\"req\":\"^2\",\"target\":\"cfg(target_os = \\\"ios\\\")\"},{\"name\":\"security-framework\",\"optional\":true,\"req\":\"^3\",\"target\":\"cfg(target_os = \\\"macos\\\")\"},{\"kind\":\"dev\",\"name\":\"whoami\",\"req\":\"^1.5\"},{\"features\":[\"Win32_Foundation\",\"Win32_Security_Credentials\"],\"name\":\"windows-sys\",\"optional\":true,\"req\":\"^0.60\",\"target\":\"cfg(target_os = \\\"windows\\\")\"},{\"name\":\"zbus\",\"optional\":true,\"req\":\"^4\",\"target\":\"cfg(target_os = \\\"freebsd\\\")\"},{\"name\":\"zbus\",\"optional\":true,\"req\":\"^4\",\"target\":\"cfg(target_os = \\\"linux\\\")\"},{\"name\":\"zbus\",\"optional\":true,\"req\":\"^4\",\"target\":\"cfg(target_os = \\\"openbsd\\\")\"},{\"name\":\"zeroize\",\"req\":\"^1.8.1\",\"target\":\"cfg(target_os = \\\"windows\\\")\"}],\"features\":{\"apple-native\":[\"dep:security-framework\"],\"async-io\":[\"zbus?/async-io\"],\"async-secret-service\":[\"dep:secret-service\",\"dep:zbus\"],\"crypto-openssl\":[\"dbus-secret-service?/crypto-openssl\",\"secret-service?/crypto-openssl\"],\"crypto-rust\":[\"dbus-secret-service?/crypto-rust\",\"secret-service?/crypto-rust\"],\"linux-native\":[\"dep:linux-keyutils\"],\"linux-native-async-persistent\":[\"linux-native\",\"async-secret-service\"],\"linux-native-sync-persistent\":[\"linux-native\",\"sync-secret-service\"],\"sync-secret-service\":[\"dep:dbus-secret-service\"],\"tokio\":[\"zbus?/tokio\"],\"vendored\":[\"dbus-secret-service?/vendored\",\"openssl?/vendored\"],\"windows-native\":[\"dep:windows-sys\",\"dep:byteorder\"]}}", "kqueue-sys_1.0.4": "{\"dependencies\":[{\"name\":\"bitflags\",\"req\":\"^1.2.1\"},{\"name\":\"libc\",\"req\":\"^0.2.74\"}],\"features\":{}}", "kqueue_1.1.1": "{\"dependencies\":[{\"features\":[\"html_reports\"],\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5\"},{\"kind\":\"dev\",\"name\":\"dhat\",\"req\":\"^0.3.2\"},{\"name\":\"kqueue-sys\",\"req\":\"^1.0.4\"},{\"name\":\"libc\",\"req\":\"^0.2.17\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.1.0\"}],\"features\":{}}", + "kstring_2.0.2": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1.4.0\"},{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"name\":\"static_assertions\",\"req\":\"^1.1.0\"}],\"features\":{\"arc\":[],\"default\":[\"std\",\"unsafe\"],\"max_inline\":[],\"std\":[],\"unsafe\":[],\"unstable_bench_subset\":[]}}", "lalrpop-util_0.19.12": "{\"dependencies\":[{\"name\":\"regex\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"default\":[\"std\"],\"lexer\":[\"regex/std\",\"std\"],\"std\":[]}}", "lalrpop_0.19.12": "{\"dependencies\":[{\"default_features\":false,\"name\":\"ascii-canvas\",\"req\":\"^3.0\"},{\"default_features\":false,\"name\":\"bit-set\",\"req\":\"^0.5.2\"},{\"default_features\":false,\"name\":\"diff\",\"req\":\"^0.1.12\"},{\"default_features\":false,\"name\":\"ena\",\"req\":\"^0.14\"},{\"name\":\"is-terminal\",\"req\":\"^0.4.2\"},{\"default_features\":false,\"features\":[\"use_std\"],\"name\":\"itertools\",\"req\":\"^0.10\"},{\"name\":\"lalrpop-util\",\"req\":\"^0.19.12\"},{\"default_features\":false,\"name\":\"petgraph\",\"req\":\"^0.6\"},{\"default_features\":false,\"name\":\"pico-args\",\"optional\":true,\"req\":\"^0.4\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"regex\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"std\",\"unicode-case\",\"unicode-perl\"],\"kind\":\"dev\",\"name\":\"regex\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"unicode\"],\"name\":\"regex-syntax\",\"req\":\"^0.6\"},{\"default_features\":false,\"features\":[\"unicode-case\",\"unicode-perl\"],\"kind\":\"dev\",\"name\":\"regex-syntax\",\"req\":\"^0.6\"},{\"default_features\":false,\"name\":\"string_cache\",\"req\":\"^0.8\"},{\"default_features\":false,\"name\":\"term\",\"req\":\"^0.7\"},{\"features\":[\"sha3\"],\"name\":\"tiny-keccak\",\"req\":\"^2.0.2\"},{\"default_features\":false,\"name\":\"unicode-xid\",\"req\":\"^0.2\"}],\"features\":{\"default\":[\"lexer\"],\"lexer\":[\"lalrpop-util/lexer\"],\"test\":[]}}", "landlock_0.4.4": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0\"},{\"name\":\"enumflags2\",\"req\":\"^0.7\"},{\"kind\":\"dev\",\"name\":\"lazy_static\",\"req\":\"^1\"},{\"name\":\"libc\",\"req\":\"^0.2.175\"},{\"kind\":\"dev\",\"name\":\"strum\",\"req\":\"^0.26\"},{\"kind\":\"dev\",\"name\":\"strum_macros\",\"req\":\"^0.26\"},{\"name\":\"thiserror\",\"req\":\"^2.0\"}],\"features\":{}}", @@ -1074,7 +1136,6 @@ "link-cplusplus_1.0.12": "{\"dependencies\":[{\"kind\":\"build\",\"name\":\"cc\",\"req\":\"^1\"}],\"features\":{\"default\":[],\"libc++\":[],\"libcxx\":[\"libc++\"],\"libstdc++\":[],\"libstdcxx\":[\"libstdc++\"],\"nothing\":[]}}", "linked-hash-map_0.5.6": "{\"dependencies\":[{\"name\":\"heapsize\",\"optional\":true,\"req\":\"^0.4\"},{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0\"}],\"features\":{\"heapsize_impl\":[\"heapsize\"],\"nightly\":[],\"serde_impl\":[\"serde\"]}}", "linux-keyutils_0.2.4": "{\"dependencies\":[{\"default_features\":false,\"name\":\"bitflags\",\"req\":\"^2.4\"},{\"default_features\":false,\"features\":[\"std\",\"derive\"],\"kind\":\"dev\",\"name\":\"clap\",\"req\":\"^4.4.11\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.132\"},{\"kind\":\"dev\",\"name\":\"zeroize\",\"req\":\"^1.5.7\"}],\"features\":{\"default\":[],\"std\":[\"bitflags/std\"]}}", - "linux-raw-sys_0.11.0": "{\"dependencies\":[{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"^0.2.100\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.1.0\"}],\"features\":{\"auxvec\":[],\"bootparam\":[],\"btrfs\":[],\"default\":[\"std\",\"general\",\"errno\"],\"elf\":[],\"elf_uapi\":[],\"errno\":[],\"general\":[],\"if_arp\":[],\"if_ether\":[],\"if_packet\":[],\"image\":[],\"io_uring\":[],\"ioctl\":[],\"landlock\":[],\"loop_device\":[],\"mempolicy\":[],\"net\":[],\"netlink\":[],\"no_std\":[],\"prctl\":[],\"ptrace\":[],\"rustc-dep-of-std\":[\"core\",\"no_std\"],\"std\":[],\"system\":[],\"xdp\":[]}}", "linux-raw-sys_0.12.1": "{\"dependencies\":[{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"^0.2.100\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.1.0\"}],\"features\":{\"auxvec\":[],\"bootparam\":[],\"btrfs\":[],\"default\":[\"std\",\"general\",\"errno\"],\"elf\":[],\"elf_uapi\":[],\"errno\":[],\"general\":[],\"if_arp\":[],\"if_ether\":[],\"if_packet\":[],\"if_tun\":[],\"image\":[],\"io_uring\":[],\"ioctl\":[],\"landlock\":[],\"loop_device\":[],\"mempolicy\":[],\"net\":[],\"netlink\":[],\"no_std\":[],\"prctl\":[],\"ptrace\":[],\"rustc-dep-of-std\":[\"core\",\"no_std\"],\"std\":[],\"system\":[],\"vm_sockets\":[],\"xdp\":[]}}", "linux-raw-sys_0.4.15": "{\"dependencies\":[{\"name\":\"compiler_builtins\",\"optional\":true,\"req\":\"^0.1.49\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"^0.2.100\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.1.0\"}],\"features\":{\"bootparam\":[],\"btrfs\":[],\"default\":[\"std\",\"general\",\"errno\"],\"elf\":[],\"elf_uapi\":[],\"errno\":[],\"general\":[],\"if_arp\":[],\"if_ether\":[],\"if_packet\":[],\"io_uring\":[],\"ioctl\":[],\"landlock\":[],\"loop_device\":[],\"mempolicy\":[],\"net\":[],\"netlink\":[],\"no_std\":[],\"prctl\":[],\"ptrace\":[],\"rustc-dep-of-std\":[\"core\",\"compiler_builtins\",\"no_std\"],\"std\":[],\"system\":[],\"xdp\":[]}}", "litemap_0.8.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1.3.1\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"name\":\"databake\",\"optional\":true,\"req\":\"^0.2.0\"},{\"default_features\":false,\"features\":[\"use-std\"],\"kind\":\"dev\",\"name\":\"postcard\",\"req\":\"^1.0.3\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\"},{\"features\":[\"validation\"],\"kind\":\"dev\",\"name\":\"rkyv\",\"req\":\"^0.7\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0.220\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"serde_core\",\"req\":\"^1.0.220\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.45\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"yoke\",\"optional\":true,\"req\":\"^0.8.0\"}],\"features\":{\"alloc\":[],\"databake\":[\"dep:databake\"],\"default\":[\"alloc\"],\"serde\":[\"dep:serde_core\",\"alloc\"],\"testing\":[\"alloc\"],\"yoke\":[\"dep:yoke\"]}}", @@ -1096,10 +1157,12 @@ "matchit_0.7.3": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"actix-router\",\"req\":\"^0.2.7\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.3.4\"},{\"kind\":\"dev\",\"name\":\"gonzales\",\"req\":\"^0.0.3-beta\"},{\"features\":[\"full\"],\"kind\":\"dev\",\"name\":\"hyper\",\"req\":\"^0.14\"},{\"kind\":\"dev\",\"name\":\"path-tree\",\"req\":\"^0.2.2\"},{\"kind\":\"dev\",\"name\":\"regex\",\"req\":\"^1.5.4\"},{\"kind\":\"dev\",\"name\":\"route-recognizer\",\"req\":\"^0.3.0\"},{\"kind\":\"dev\",\"name\":\"routefinder\",\"req\":\"^0.5.2\"},{\"features\":[\"full\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"features\":[\"make\",\"util\"],\"kind\":\"dev\",\"name\":\"tower\",\"req\":\"^0.4\"}],\"features\":{\"__test_helpers\":[],\"default\":[]}}", "matchit_0.8.4": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"actix-router\",\"req\":\"^0.2.7\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.3.4\"},{\"kind\":\"dev\",\"name\":\"gonzales\",\"req\":\"^0.0.3-beta\"},{\"features\":[\"full\"],\"kind\":\"dev\",\"name\":\"hyper\",\"req\":\"^0.14\"},{\"kind\":\"dev\",\"name\":\"path-tree\",\"req\":\"^0.2.2\"},{\"kind\":\"dev\",\"name\":\"regex\",\"req\":\"^1.5.4\"},{\"kind\":\"dev\",\"name\":\"route-recognizer\",\"req\":\"^0.3.0\"},{\"kind\":\"dev\",\"name\":\"routefinder\",\"req\":\"^0.5.2\"},{\"features\":[\"full\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"features\":[\"make\",\"util\"],\"kind\":\"dev\",\"name\":\"tower\",\"req\":\"^0.4\"}],\"features\":{\"__test_helpers\":[],\"default\":[]}}", "matchit_0.9.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"actix-router\",\"req\":\"^0.5\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5\"},{\"kind\":\"dev\",\"name\":\"gonzales\",\"req\":\"^0.0.3-beta\"},{\"kind\":\"dev\",\"name\":\"http-body-util\",\"req\":\"^0.1\"},{\"features\":[\"http1\",\"server\"],\"kind\":\"dev\",\"name\":\"hyper\",\"req\":\"^1\"},{\"features\":[\"tokio\"],\"kind\":\"dev\",\"name\":\"hyper-util\",\"req\":\"^0.1\"},{\"kind\":\"dev\",\"name\":\"path-tree\",\"req\":\"^0.8\"},{\"kind\":\"dev\",\"name\":\"regex\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"route-recognizer\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"routefinder\",\"req\":\"^0.5\"},{\"features\":[\"full\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"features\":[\"make\",\"util\"],\"kind\":\"dev\",\"name\":\"tower\",\"req\":\"^0.5.2\"},{\"kind\":\"dev\",\"name\":\"wayfind\",\"req\":\"^0.8\"}],\"features\":{\"__test_helpers\":[],\"default\":[]}}", + "maybe-async_0.2.10": "{\"dependencies\":[{\"features\":[\"attributes\"],\"kind\":\"dev\",\"name\":\"async-std\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"async-trait\",\"req\":\"^0.1\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0\"},{\"name\":\"quote\",\"req\":\"^1.0\"},{\"features\":[\"visit-mut\",\"full\"],\"name\":\"syn\",\"req\":\"^2.0\"},{\"features\":[\"macros\",\"rt-multi-thread\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"features\":[\"diff\"],\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1\"}],\"features\":{\"default\":[],\"is_sync\":[]}}", "md-5_0.10.6": "{\"dependencies\":[{\"name\":\"cfg-if\",\"req\":\"^1.0\"},{\"name\":\"digest\",\"req\":\"^0.10.7\"},{\"features\":[\"dev\"],\"kind\":\"dev\",\"name\":\"digest\",\"req\":\"^0.10.7\"},{\"kind\":\"dev\",\"name\":\"hex-literal\",\"req\":\"^0.2.2\"},{\"name\":\"md5-asm\",\"optional\":true,\"req\":\"^0.5\",\"target\":\"cfg(any(target_arch = \\\"x86\\\", target_arch = \\\"x86_64\\\"))\"}],\"features\":{\"asm\":[\"md5-asm\"],\"default\":[\"std\"],\"force-soft\":[],\"loongarch64_asm\":[],\"oid\":[\"digest/oid\"],\"std\":[\"digest/std\"]}}", "md5_0.8.0": "{\"dependencies\":[],\"features\":{\"default\":[\"std\"],\"std\":[]}}", "memchr_2.7.6": "{\"dependencies\":[{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"name\":\"log\",\"optional\":true,\"req\":\"^0.4.20\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0.3\"}],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"libc\":[],\"logging\":[\"dep:log\"],\"rustc-dep-of-std\":[\"core\"],\"std\":[\"alloc\"],\"use_std\":[\"std\"]}}", "memchr_2.8.0": "{\"dependencies\":[{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"name\":\"log\",\"optional\":true,\"req\":\"^0.4.20\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0.3\"}],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"libc\":[],\"logging\":[\"dep:log\"],\"rustc-dep-of-std\":[\"core\"],\"std\":[\"alloc\"],\"use_std\":[\"std\"]}}", + "memmap2_0.9.10": "{\"dependencies\":[{\"name\":\"libc\",\"req\":\"^0.2.151\",\"target\":\"cfg(unix)\"},{\"kind\":\"dev\",\"name\":\"owning_ref\",\"req\":\"^0.4.1\"},{\"name\":\"stable_deref_trait\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3\"}],\"features\":{}}", "memoffset_0.6.5": "{\"dependencies\":[{\"kind\":\"build\",\"name\":\"autocfg\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3\"}],\"features\":{\"default\":[],\"unstable_const\":[]}}", "memoffset_0.9.1": "{\"dependencies\":[{\"kind\":\"build\",\"name\":\"autocfg\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3\"}],\"features\":{\"default\":[],\"unstable_const\":[],\"unstable_offset_of\":[]}}", "mime_0.3.17": "{\"dependencies\":[],\"features\":{}}", @@ -1122,6 +1185,7 @@ "nix_0.30.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"assert-impl\",\"req\":\"^0.1\"},{\"name\":\"bitflags\",\"req\":\"^2.3.3\"},{\"kind\":\"dev\",\"name\":\"caps\",\"req\":\"^0.5.3\",\"target\":\"cfg(any(target_os = \\\"android\\\", target_os = \\\"linux\\\"))\"},{\"name\":\"cfg-if\",\"req\":\"^1.0\"},{\"kind\":\"build\",\"name\":\"cfg_aliases\",\"req\":\"^0.2.1\"},{\"features\":[\"extra_traits\"],\"name\":\"libc\",\"req\":\"^0.2.171\"},{\"name\":\"memoffset\",\"optional\":true,\"req\":\"^0.9\"},{\"kind\":\"dev\",\"name\":\"parking_lot\",\"req\":\"^0.12\"},{\"name\":\"pin-utils\",\"optional\":true,\"req\":\"^0.1.0\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\"},{\"kind\":\"dev\",\"name\":\"semver\",\"req\":\"^1.0.7\"},{\"kind\":\"dev\",\"name\":\"sysctl\",\"req\":\"^0.4\",\"target\":\"cfg(target_os = \\\"freebsd\\\")\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.7.1\"}],\"features\":{\"acct\":[],\"aio\":[\"pin-utils\"],\"default\":[],\"dir\":[\"fs\"],\"env\":[],\"event\":[\"poll\"],\"fanotify\":[],\"feature\":[],\"fs\":[],\"hostname\":[],\"inotify\":[],\"ioctl\":[],\"kmod\":[],\"mman\":[],\"mount\":[\"uio\"],\"mqueue\":[\"fs\"],\"net\":[\"socket\"],\"personality\":[],\"poll\":[],\"process\":[],\"pthread\":[],\"ptrace\":[\"process\"],\"quota\":[],\"reboot\":[],\"resource\":[],\"sched\":[\"process\"],\"signal\":[\"process\"],\"socket\":[\"memoffset\"],\"syslog\":[],\"term\":[],\"time\":[],\"ucontext\":[\"signal\"],\"uio\":[],\"user\":[\"feature\"],\"zerocopy\":[\"fs\",\"uio\"]}}", "nom_7.1.3": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"memchr\",\"req\":\"^2.3\"},{\"default_features\":false,\"name\":\"minimal-lexical\",\"req\":\"^0.2.0\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1.0.0\"}],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"docsrs\":[],\"std\":[\"alloc\",\"memchr/std\",\"minimal-lexical/std\"]}}", "nom_8.0.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"memchr\",\"req\":\"^2.3\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"=1.0.0\"}],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"docsrs\":[],\"std\":[\"alloc\",\"memchr/std\"]}}", + "nonempty_0.12.0": "{\"dependencies\":[{\"features\":[\"derive\"],\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"bincode\",\"optional\":true,\"req\":\"^2.0.1\"},{\"default_features\":false,\"features\":[\"derive\",\"alloc\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1\"}],\"features\":{\"arbitrary\":[\"dep:arbitrary\"],\"bincode\":[\"dep:bincode\"],\"default\":[\"std\"],\"serialize\":[\"dep:serde\"],\"std\":[]}}", "normalize-line-endings_0.3.0": "{\"dependencies\":[],\"features\":{}}", "notify-types_2.1.0": "{\"dependencies\":[{\"name\":\"bitflags\",\"req\":\"^2\"},{\"kind\":\"dev\",\"name\":\"insta\",\"req\":\"^1.34.0\"},{\"kind\":\"dev\",\"name\":\"rstest\",\"req\":\"^0.26.0\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.89\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.39\"},{\"name\":\"web-time\",\"optional\":true,\"req\":\"^1.1.0\"}],\"features\":{\"serde\":[\"dep:serde\",\"bitflags/serde\"],\"serialization-compat-6\":[]}}", "notify_8.2.0": "{\"dependencies\":[{\"name\":\"bitflags\",\"req\":\"^2.7.0\",\"target\":\"cfg(target_os=\\\"macos\\\")\"},{\"name\":\"crossbeam-channel\",\"optional\":true,\"req\":\"^0.5.0\"},{\"name\":\"flume\",\"optional\":true,\"req\":\"^0.11.1\"},{\"name\":\"fsevent-sys\",\"optional\":true,\"req\":\"^4.0.0\",\"target\":\"cfg(target_os=\\\"macos\\\")\"},{\"default_features\":false,\"name\":\"inotify\",\"req\":\"^0.11.0\",\"target\":\"cfg(any(target_os=\\\"linux\\\", target_os=\\\"android\\\"))\"},{\"kind\":\"dev\",\"name\":\"insta\",\"req\":\"^1.34.0\"},{\"name\":\"kqueue\",\"req\":\"^1.1.1\",\"target\":\"cfg(any(target_os=\\\"freebsd\\\", target_os=\\\"openbsd\\\", target_os = \\\"netbsd\\\", target_os = \\\"dragonflybsd\\\", target_os = \\\"ios\\\"))\"},{\"name\":\"kqueue\",\"optional\":true,\"req\":\"^1.1.1\",\"target\":\"cfg(target_os=\\\"macos\\\")\"},{\"name\":\"libc\",\"req\":\"^0.2.4\"},{\"name\":\"log\",\"req\":\"^0.4.17\"},{\"features\":[\"os-ext\"],\"name\":\"mio\",\"req\":\"^1.0\",\"target\":\"cfg(any(target_os=\\\"freebsd\\\", target_os=\\\"openbsd\\\", target_os = \\\"netbsd\\\", target_os = \\\"dragonflybsd\\\", target_os = \\\"ios\\\"))\"},{\"features\":[\"os-ext\"],\"name\":\"mio\",\"req\":\"^1.0\",\"target\":\"cfg(any(target_os=\\\"linux\\\", target_os=\\\"android\\\"))\"},{\"features\":[\"os-ext\"],\"name\":\"mio\",\"optional\":true,\"req\":\"^1.0\",\"target\":\"cfg(target_os=\\\"macos\\\")\"},{\"kind\":\"dev\",\"name\":\"nix\",\"req\":\"^0.29.0\"},{\"name\":\"notify-types\",\"req\":\"^2.0.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.39\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.10.0\"},{\"kind\":\"dev\",\"name\":\"trash\",\"req\":\"^5.2.2\",\"target\":\"cfg(target_os = \\\"windows\\\")\"},{\"name\":\"walkdir\",\"req\":\"^2.4.0\"},{\"features\":[\"Win32_System_Threading\",\"Win32_Foundation\",\"Win32_Storage_FileSystem\",\"Win32_Security\",\"Win32_System_WindowsProgramming\",\"Win32_System_IO\"],\"name\":\"windows-sys\",\"req\":\"^0.60.1\",\"target\":\"cfg(windows)\"}],\"features\":{\"default\":[\"macos_fsevent\"],\"macos_fsevent\":[\"fsevent-sys\"],\"macos_kqueue\":[\"kqueue\",\"mio\"],\"serde\":[\"notify-types/serde\"],\"serialization-compat-6\":[\"notify-types/serialization-compat-6\"]}}", @@ -1239,6 +1303,7 @@ "proc-macro-error2_2.0.1": "{\"dependencies\":[{\"name\":\"proc-macro-error-attr2\",\"req\":\"=2.0.0\"},{\"name\":\"proc-macro2\",\"req\":\"^1\"},{\"name\":\"quote\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"syn\",\"optional\":true,\"req\":\"^2\"},{\"features\":[\"full\"],\"kind\":\"dev\",\"name\":\"syn\",\"req\":\"^2\"},{\"features\":[\"diff\"],\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.99\"}],\"features\":{\"default\":[\"syn-error\"],\"nightly\":[],\"syn-error\":[\"dep:syn\"]}}", "proc-macro2_1.0.106": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"flate2\",\"req\":\"^1.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quote\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"tar\",\"req\":\"^0.4\"},{\"name\":\"unicode-ident\",\"req\":\"^1.0\"}],\"features\":{\"default\":[\"proc-macro\"],\"nightly\":[],\"proc-macro\":[],\"span-locations\":[]}}", "process-wrap_9.0.1": "{\"dependencies\":[{\"name\":\"futures\",\"optional\":true,\"req\":\"^0.3.30\"},{\"name\":\"indexmap\",\"req\":\"^2.9.0\"},{\"default_features\":false,\"features\":[\"fs\",\"poll\",\"signal\"],\"name\":\"nix\",\"optional\":true,\"req\":\"^0.30.1\",\"target\":\"cfg(unix)\"},{\"kind\":\"dev\",\"name\":\"remoteprocess\",\"req\":\"^0.5.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.20.0\"},{\"features\":[\"io-util\",\"macros\",\"process\",\"rt\"],\"name\":\"tokio\",\"optional\":true,\"req\":\"^1.38.2\"},{\"features\":[\"io-util\",\"macros\",\"process\",\"rt\",\"rt-multi-thread\",\"time\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.38.2\"},{\"name\":\"tracing\",\"optional\":true,\"req\":\"^0.1.40\"},{\"name\":\"windows\",\"optional\":true,\"req\":\"^0.62.2\",\"target\":\"cfg(windows)\"}],\"features\":{\"creation-flags\":[\"dep:windows\",\"windows/Win32_System_Threading\"],\"default\":[\"creation-flags\",\"job-object\",\"kill-on-drop\",\"process-group\",\"process-session\",\"tracing\"],\"job-object\":[\"dep:windows\",\"windows/Win32_Security\",\"windows/Win32_System_Diagnostics_ToolHelp\",\"windows/Win32_System_IO\",\"windows/Win32_System_JobObjects\",\"windows/Win32_System_Threading\"],\"kill-on-drop\":[],\"process-group\":[],\"process-session\":[\"process-group\"],\"reset-sigmask\":[],\"std\":[\"dep:nix\"],\"tokio1\":[\"dep:nix\",\"dep:futures\",\"dep:tokio\"],\"tracing\":[\"dep:tracing\"]}}", + "prodash_31.0.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"argh\",\"req\":\"^0.1.3\"},{\"kind\":\"dev\",\"name\":\"async-executor\",\"req\":\"^1.1.0\"},{\"name\":\"async-io\",\"optional\":true,\"req\":\"^2.2.1\"},{\"kind\":\"dev\",\"name\":\"async-io\",\"req\":\"^2.2.1\"},{\"kind\":\"dev\",\"name\":\"blocking\",\"req\":\"^1.0.0\"},{\"name\":\"bytesize\",\"optional\":true,\"req\":\"^2.0.1\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.8.1\"},{\"default_features\":false,\"name\":\"crosstermion\",\"optional\":true,\"req\":\"^0.16.0\"},{\"default_features\":false,\"features\":[\"termination\"],\"name\":\"ctrlc\",\"optional\":true,\"req\":\"^3.1.4\"},{\"default_features\":false,\"name\":\"dashmap\",\"optional\":true,\"req\":\"^6.0.1\"},{\"default_features\":false,\"features\":[\"humantime\"],\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.11.0\"},{\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3.5\"},{\"default_features\":false,\"name\":\"futures-core\",\"optional\":true,\"req\":\"^0.3.4\"},{\"name\":\"futures-lite\",\"optional\":true,\"req\":\"^2.1.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"futures-util\",\"req\":\"^0.3.4\"},{\"name\":\"human_format\",\"optional\":true,\"req\":\"^1.0.3\"},{\"name\":\"is-terminal\",\"optional\":true,\"req\":\"^0.4.9\"},{\"kind\":\"dev\",\"name\":\"is-terminal\",\"req\":\"^0.4.9\"},{\"name\":\"jiff\",\"optional\":true,\"req\":\"^0.2.4\"},{\"name\":\"log\",\"optional\":true,\"req\":\"^0.4.8\"},{\"kind\":\"dev\",\"name\":\"once_cell\",\"req\":\"^1.4.0\"},{\"default_features\":false,\"name\":\"parking_lot\",\"optional\":true,\"req\":\"^0.12.1\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.1\"},{\"default_features\":false,\"name\":\"signal-hook\",\"optional\":true,\"req\":\"^0.4.1\"},{\"default_features\":false,\"name\":\"tui\",\"optional\":true,\"package\":\"ratatui\",\"req\":\"^0.30.0\"},{\"name\":\"tui-react\",\"optional\":true,\"req\":\"^0.24.0\"},{\"name\":\"unicode-segmentation\",\"optional\":true,\"req\":\"^1.6.0\"},{\"name\":\"unicode-width\",\"optional\":true,\"req\":\"^0.2.2\"}],\"features\":{\"default\":[\"progress-tree\"],\"local-time\":[\"jiff\"],\"progress-log\":[\"log\"],\"progress-tree\":[\"parking_lot\"],\"progress-tree-hp-hashmap\":[\"dashmap\"],\"progress-tree-log\":[\"log\"],\"render-line\":[\"crosstermion/color\",\"jiff\",\"unicode-width\"],\"render-line-autoconfigure\":[\"is-terminal\"],\"render-line-crossterm\":[\"crosstermion/crossterm\"],\"render-tui\":[\"tui\",\"unicode-segmentation\",\"unicode-width\",\"crosstermion/input-async\",\"tui-react\",\"futures-lite\",\"futures-core\",\"async-io\",\"jiff\"],\"render-tui-crossterm\":[\"crosstermion/tui-react-crossterm\",\"crosstermion/input-async-crossterm\"],\"unit-bytes\":[\"bytesize\"],\"unit-duration\":[\"jiff\"],\"unit-human\":[\"human_format\"]}}", "proptest_1.9.0": "{\"dependencies\":[{\"name\":\"bit-set\",\"optional\":true,\"req\":\"^0.8.0\"},{\"name\":\"bit-vec\",\"optional\":true,\"req\":\"^0.8.0\"},{\"name\":\"bitflags\",\"req\":\"^2.9\"},{\"default_features\":false,\"name\":\"num-traits\",\"req\":\"^0.2.15\"},{\"name\":\"proptest-macro\",\"optional\":true,\"req\":\"^0.4.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"rand\",\"req\":\"^0.9\"},{\"default_features\":false,\"name\":\"rand_chacha\",\"req\":\"^0.9\"},{\"name\":\"rand_xorshift\",\"req\":\"^0.4\"},{\"kind\":\"dev\",\"name\":\"regex\",\"req\":\"^1.0\"},{\"name\":\"regex-syntax\",\"optional\":true,\"req\":\"^0.8\"},{\"default_features\":false,\"name\":\"rusty-fork\",\"optional\":true,\"req\":\"^0.3.0\"},{\"name\":\"tempfile\",\"optional\":true,\"req\":\"^3.0\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"=1.0.112\"},{\"name\":\"unarray\",\"req\":\"^0.1.4\"},{\"name\":\"x86\",\"optional\":true,\"req\":\"^0.52.0\"}],\"features\":{\"alloc\":[],\"atomic64bit\":[],\"attr-macro\":[\"proptest-macro\"],\"bit-set\":[\"dep:bit-set\",\"dep:bit-vec\"],\"default\":[\"std\",\"fork\",\"timeout\",\"bit-set\"],\"default-code-coverage\":[\"std\",\"fork\",\"timeout\",\"bit-set\"],\"fork\":[\"std\",\"rusty-fork\",\"tempfile\"],\"handle-panics\":[\"std\"],\"hardware-rng\":[\"x86\"],\"no_std\":[\"num-traits/libm\"],\"std\":[\"rand/std\",\"rand/os_rng\",\"regex-syntax\",\"num-traits/std\"],\"timeout\":[\"fork\",\"rusty-fork/timeout\"],\"unstable\":[]}}", "prost-build_0.12.6": "{\"dependencies\":[{\"default_features\":false,\"name\":\"bytes\",\"req\":\"^1\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.10\"},{\"name\":\"heck\",\"req\":\">=0.4, <=0.5\"},{\"default_features\":false,\"features\":[\"use_alloc\"],\"name\":\"itertools\",\"req\":\">=0.10, <=0.12\"},{\"name\":\"log\",\"req\":\"^0.4.4\"},{\"default_features\":false,\"name\":\"multimap\",\"req\":\">=0.8, <=0.10\"},{\"name\":\"once_cell\",\"req\":\"^1.17.1\"},{\"default_features\":false,\"name\":\"petgraph\",\"req\":\"^0.6\"},{\"name\":\"prettyplease\",\"optional\":true,\"req\":\"^0.2\"},{\"default_features\":false,\"name\":\"prost\",\"req\":\"^0.12.6\"},{\"default_features\":false,\"name\":\"prost-types\",\"req\":\"^0.12.6\"},{\"default_features\":false,\"name\":\"pulldown-cmark\",\"optional\":true,\"req\":\"^0.9.1\"},{\"name\":\"pulldown-cmark-to-cmark\",\"optional\":true,\"req\":\"^10.0.1\"},{\"default_features\":false,\"features\":[\"std\",\"unicode-bool\"],\"name\":\"regex\",\"req\":\"^1.8.1\"},{\"features\":[\"full\"],\"name\":\"syn\",\"optional\":true,\"req\":\"^2\"},{\"name\":\"tempfile\",\"req\":\"^3\"}],\"features\":{\"cleanup-markdown\":[\"dep:pulldown-cmark\",\"dep:pulldown-cmark-to-cmark\"],\"default\":[\"format\"],\"format\":[\"dep:prettyplease\",\"dep:syn\"]}}", "prost-build_0.13.1": "{\"dependencies\":[{\"default_features\":false,\"name\":\"bytes\",\"req\":\"^1\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.11\"},{\"name\":\"heck\",\"req\":\">=0.4, <=0.5\"},{\"default_features\":false,\"features\":[\"use_alloc\"],\"name\":\"itertools\",\"req\":\">=0.10, <=0.13\"},{\"name\":\"log\",\"req\":\"^0.4.4\"},{\"default_features\":false,\"name\":\"multimap\",\"req\":\">=0.8, <=0.10\"},{\"name\":\"once_cell\",\"req\":\"^1.17.1\"},{\"default_features\":false,\"name\":\"petgraph\",\"req\":\"^0.6\"},{\"name\":\"prettyplease\",\"optional\":true,\"req\":\"^0.2\"},{\"default_features\":false,\"name\":\"prost\",\"req\":\"^0.13.1\"},{\"default_features\":false,\"name\":\"prost-types\",\"req\":\"^0.13.1\"},{\"default_features\":false,\"name\":\"pulldown-cmark\",\"optional\":true,\"req\":\"^0.9.1\"},{\"name\":\"pulldown-cmark-to-cmark\",\"optional\":true,\"req\":\"^10.0.1\"},{\"default_features\":false,\"features\":[\"std\",\"unicode-bool\"],\"name\":\"regex\",\"req\":\"^1.8.1\"},{\"features\":[\"full\"],\"name\":\"syn\",\"optional\":true,\"req\":\"^2\"},{\"name\":\"tempfile\",\"req\":\"^3\"}],\"features\":{\"cleanup-markdown\":[\"dep:pulldown-cmark\",\"dep:pulldown-cmark-to-cmark\"],\"default\":[\"format\"],\"format\":[\"dep:prettyplease\",\"dep:syn\"]}}", @@ -1331,7 +1396,6 @@ "rustfix_0.8.7": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0.86\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1.5.0\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"req\":\"^1.0.204\"},{\"name\":\"serde_json\",\"req\":\"^1.0.120\"},{\"kind\":\"dev\",\"name\":\"similar\",\"req\":\"^2.6.0\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.10.1\"},{\"name\":\"thiserror\",\"req\":\"^1.0.63\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"tracing\",\"req\":\"^0.1.40\"},{\"features\":[\"env-filter\"],\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3.18\"}],\"features\":{}}", "rusticata-macros_4.1.0": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"std\"],\"name\":\"nom\",\"req\":\"^7.0\"}],\"features\":{}}", "rustix_0.38.44": "{\"dependencies\":[{\"default_features\":false,\"name\":\"bitflags\",\"req\":\"^2.4.0\"},{\"name\":\"compiler_builtins\",\"optional\":true,\"req\":\"^0.1.49\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.4\",\"target\":\"cfg(all(criterion, not(any(target_os = \\\"emscripten\\\", target_os = \\\"wasi\\\"))))\"},{\"kind\":\"dev\",\"name\":\"flate2\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"itoa\",\"optional\":true,\"req\":\"^1.0.13\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.161\",\"target\":\"cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", target_arch = \\\"s390x\\\"), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\"},{\"default_features\":false,\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2.161\",\"target\":\"cfg(all(not(rustix_use_libc), not(miri), target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", target_arch = \\\"s390x\\\"), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\"))))\"},{\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"^0.2.161\"},{\"default_features\":false,\"name\":\"libc_errno\",\"package\":\"errno\",\"req\":\"^0.3.10\",\"target\":\"cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", target_arch = \\\"s390x\\\"), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\"},{\"default_features\":false,\"name\":\"libc_errno\",\"package\":\"errno\",\"req\":\"^0.3.10\",\"target\":\"cfg(windows)\"},{\"default_features\":false,\"name\":\"libc_errno\",\"optional\":true,\"package\":\"errno\",\"req\":\"^0.3.10\",\"target\":\"cfg(all(not(rustix_use_libc), not(miri), target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", target_arch = \\\"s390x\\\"), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\"))))\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"libc_errno\",\"package\":\"errno\",\"req\":\"^0.3.10\"},{\"default_features\":false,\"features\":[\"general\",\"ioctl\",\"no_std\"],\"name\":\"linux-raw-sys\",\"req\":\"^0.4.14\",\"target\":\"cfg(all(any(target_os = \\\"android\\\", target_os = \\\"linux\\\"), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", target_arch = \\\"s390x\\\"), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\"},{\"default_features\":false,\"features\":[\"general\",\"errno\",\"ioctl\",\"no_std\",\"elf\"],\"name\":\"linux-raw-sys\",\"req\":\"^0.4.14\",\"target\":\"cfg(all(not(rustix_use_libc), not(miri), target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", target_arch = \\\"s390x\\\"), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\"))))\"},{\"kind\":\"dev\",\"name\":\"memoffset\",\"req\":\"^0.9.0\"},{\"name\":\"once_cell\",\"optional\":true,\"req\":\"^1.5.2\",\"target\":\"cfg(any(target_os = \\\"android\\\", target_os = \\\"linux\\\"))\"},{\"name\":\"rustc-std-workspace-alloc\",\"optional\":true,\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"serial_test\",\"req\":\"^2.0.0\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.1.0\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.5.0\"},{\"features\":[\"Win32_Foundation\",\"Win32_Networking_WinSock\",\"Win32_NetworkManagement_IpHelper\",\"Win32_System_Threading\"],\"name\":\"windows-sys\",\"req\":\">=0.52, <=0.59\",\"target\":\"cfg(windows)\"}],\"features\":{\"all-apis\":[\"event\",\"fs\",\"io_uring\",\"mm\",\"mount\",\"net\",\"param\",\"pipe\",\"process\",\"procfs\",\"pty\",\"rand\",\"runtime\",\"shm\",\"stdio\",\"system\",\"termios\",\"thread\",\"time\"],\"alloc\":[],\"cc\":[],\"default\":[\"std\",\"use-libc-auxv\"],\"event\":[],\"fs\":[],\"io_uring\":[\"event\",\"fs\",\"net\",\"linux-raw-sys/io_uring\"],\"libc-extra-traits\":[\"libc?/extra_traits\"],\"linux_4_11\":[],\"linux_latest\":[\"linux_4_11\"],\"mm\":[],\"mount\":[],\"net\":[\"linux-raw-sys/net\",\"linux-raw-sys/netlink\",\"linux-raw-sys/if_ether\",\"linux-raw-sys/xdp\"],\"param\":[\"fs\"],\"pipe\":[],\"process\":[\"linux-raw-sys/prctl\"],\"procfs\":[\"once_cell\",\"itoa\",\"fs\"],\"pty\":[\"itoa\",\"fs\"],\"rand\":[],\"runtime\":[\"linux-raw-sys/prctl\"],\"rustc-dep-of-std\":[\"core\",\"rustc-std-workspace-alloc\",\"compiler_builtins\",\"linux-raw-sys/rustc-dep-of-std\",\"bitflags/rustc-dep-of-std\",\"compiler_builtins?/rustc-dep-of-std\"],\"shm\":[\"fs\"],\"std\":[\"bitflags/std\",\"alloc\",\"libc?/std\",\"libc_errno?/std\",\"libc-extra-traits\"],\"stdio\":[],\"system\":[\"linux-raw-sys/system\"],\"termios\":[],\"thread\":[\"linux-raw-sys/prctl\"],\"time\":[],\"try_close\":[],\"use-explicitly-provided-auxv\":[],\"use-libc\":[\"libc_errno\",\"libc\",\"libc-extra-traits\"],\"use-libc-auxv\":[]}}", - "rustix_1.1.3": "{\"dependencies\":[{\"default_features\":false,\"name\":\"bitflags\",\"req\":\"^2.4.0\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.4\",\"target\":\"cfg(all(criterion, not(any(target_os = \\\"emscripten\\\", target_os = \\\"wasi\\\"))))\"},{\"kind\":\"dev\",\"name\":\"flate2\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.177\",\"target\":\"cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\"},{\"default_features\":false,\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2.177\",\"target\":\"cfg(all(not(rustix_use_libc), not(miri), target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\"))))\"},{\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"^0.2.171\"},{\"default_features\":false,\"name\":\"libc_errno\",\"package\":\"errno\",\"req\":\"^0.3.10\",\"target\":\"cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\"},{\"default_features\":false,\"name\":\"libc_errno\",\"package\":\"errno\",\"req\":\"^0.3.10\",\"target\":\"cfg(windows)\"},{\"default_features\":false,\"name\":\"libc_errno\",\"optional\":true,\"package\":\"errno\",\"req\":\"^0.3.10\",\"target\":\"cfg(all(not(rustix_use_libc), not(miri), target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\"))))\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"libc_errno\",\"package\":\"errno\",\"req\":\"^0.3.10\"},{\"default_features\":false,\"features\":[\"general\",\"ioctl\",\"no_std\"],\"name\":\"linux-raw-sys\",\"req\":\"^0.11.0\",\"target\":\"cfg(all(any(target_os = \\\"linux\\\", target_os = \\\"android\\\"), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\"},{\"default_features\":false,\"features\":[\"auxvec\",\"general\",\"errno\",\"ioctl\",\"no_std\",\"elf\"],\"name\":\"linux-raw-sys\",\"req\":\"^0.11.0\",\"target\":\"cfg(all(not(rustix_use_libc), not(miri), target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\"))))\"},{\"kind\":\"dev\",\"name\":\"memoffset\",\"req\":\"^0.9.0\"},{\"kind\":\"dev\",\"name\":\"once_cell\",\"req\":\"^1.20.3\",\"target\":\"cfg(windows)\"},{\"name\":\"rustc-std-workspace-alloc\",\"optional\":true,\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"serial_test\",\"req\":\"^2.0.0\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.1.0\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.5.0\"},{\"features\":[\"Win32_Foundation\",\"Win32_Networking_WinSock\"],\"name\":\"windows-sys\",\"req\":\">=0.52, <0.62\",\"target\":\"cfg(windows)\"}],\"features\":{\"all-apis\":[\"event\",\"fs\",\"io_uring\",\"mm\",\"mount\",\"net\",\"param\",\"pipe\",\"process\",\"pty\",\"rand\",\"runtime\",\"shm\",\"stdio\",\"system\",\"termios\",\"thread\",\"time\"],\"alloc\":[],\"default\":[\"std\"],\"event\":[],\"fs\":[],\"io_uring\":[\"event\",\"fs\",\"net\",\"thread\",\"linux-raw-sys/io_uring\"],\"linux_4_11\":[],\"linux_5_1\":[\"linux_4_11\"],\"linux_5_11\":[\"linux_5_1\"],\"linux_latest\":[\"linux_5_11\"],\"mm\":[],\"mount\":[],\"net\":[\"linux-raw-sys/net\",\"linux-raw-sys/netlink\",\"linux-raw-sys/if_ether\",\"linux-raw-sys/xdp\"],\"param\":[],\"pipe\":[],\"process\":[\"linux-raw-sys/prctl\"],\"pty\":[\"fs\"],\"rand\":[],\"runtime\":[\"linux-raw-sys/prctl\"],\"rustc-dep-of-std\":[\"core\",\"rustc-std-workspace-alloc\",\"linux-raw-sys/rustc-dep-of-std\",\"bitflags/rustc-dep-of-std\"],\"shm\":[\"fs\"],\"std\":[\"bitflags/std\",\"alloc\",\"libc?/std\",\"libc_errno?/std\"],\"stdio\":[],\"system\":[\"linux-raw-sys/system\"],\"termios\":[],\"thread\":[\"linux-raw-sys/prctl\"],\"time\":[],\"try_close\":[],\"use-explicitly-provided-auxv\":[],\"use-libc\":[\"libc_errno\",\"libc\"],\"use-libc-auxv\":[]}}", "rustix_1.1.4": "{\"dependencies\":[{\"default_features\":false,\"name\":\"bitflags\",\"req\":\"^2.4.0\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.4\",\"target\":\"cfg(all(criterion, not(any(target_os = \\\"emscripten\\\", target_os = \\\"wasi\\\"))))\"},{\"kind\":\"dev\",\"name\":\"flate2\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.182\",\"target\":\"cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\"},{\"default_features\":false,\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2.182\",\"target\":\"cfg(all(not(rustix_use_libc), not(miri), target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\"))))\"},{\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"^0.2.171\"},{\"default_features\":false,\"name\":\"libc_errno\",\"package\":\"errno\",\"req\":\"^0.3.10\",\"target\":\"cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\"},{\"default_features\":false,\"name\":\"libc_errno\",\"package\":\"errno\",\"req\":\"^0.3.10\",\"target\":\"cfg(windows)\"},{\"default_features\":false,\"name\":\"libc_errno\",\"optional\":true,\"package\":\"errno\",\"req\":\"^0.3.10\",\"target\":\"cfg(all(not(rustix_use_libc), not(miri), target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\"))))\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"libc_errno\",\"package\":\"errno\",\"req\":\"^0.3.10\"},{\"default_features\":false,\"features\":[\"general\",\"ioctl\",\"no_std\"],\"name\":\"linux-raw-sys\",\"req\":\"^0.12\",\"target\":\"cfg(all(any(target_os = \\\"linux\\\", target_os = \\\"android\\\"), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\"},{\"default_features\":false,\"features\":[\"auxvec\",\"general\",\"errno\",\"ioctl\",\"no_std\",\"elf\"],\"name\":\"linux-raw-sys\",\"req\":\"^0.12\",\"target\":\"cfg(all(not(rustix_use_libc), not(miri), target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\"))))\"},{\"kind\":\"dev\",\"name\":\"memoffset\",\"req\":\"^0.9.0\"},{\"kind\":\"dev\",\"name\":\"once_cell\",\"req\":\"^1.20.3\",\"target\":\"cfg(windows)\"},{\"name\":\"rustc-std-workspace-alloc\",\"optional\":true,\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"serial_test\",\"req\":\"^2.0.0\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.1.0\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.5.0\"},{\"features\":[\"Win32_Foundation\",\"Win32_Networking_WinSock\"],\"name\":\"windows-sys\",\"req\":\">=0.52, <0.62\",\"target\":\"cfg(windows)\"}],\"features\":{\"all-apis\":[\"event\",\"fs\",\"io_uring\",\"mm\",\"mount\",\"net\",\"param\",\"pipe\",\"process\",\"pty\",\"rand\",\"runtime\",\"shm\",\"stdio\",\"system\",\"termios\",\"thread\",\"time\"],\"alloc\":[],\"default\":[\"std\"],\"event\":[],\"fs\":[],\"io_uring\":[\"event\",\"fs\",\"net\",\"thread\",\"linux-raw-sys/io_uring\"],\"linux_4_11\":[],\"linux_5_1\":[\"linux_4_11\"],\"linux_5_11\":[\"linux_5_1\"],\"linux_latest\":[\"linux_5_11\"],\"mm\":[],\"mount\":[],\"net\":[\"linux-raw-sys/net\",\"linux-raw-sys/netlink\",\"linux-raw-sys/if_ether\",\"linux-raw-sys/xdp\"],\"param\":[],\"pipe\":[],\"process\":[\"linux-raw-sys/prctl\"],\"pty\":[\"fs\"],\"rand\":[],\"runtime\":[\"linux-raw-sys/prctl\"],\"rustc-dep-of-std\":[\"core\",\"rustc-std-workspace-alloc\",\"linux-raw-sys/rustc-dep-of-std\",\"bitflags/rustc-dep-of-std\"],\"shm\":[\"fs\"],\"std\":[\"bitflags/std\",\"alloc\",\"libc?/std\",\"libc_errno?/std\"],\"stdio\":[],\"system\":[\"linux-raw-sys/system\"],\"termios\":[],\"thread\":[\"linux-raw-sys/prctl\"],\"time\":[],\"try_close\":[],\"use-explicitly-provided-auxv\":[],\"use-libc\":[\"libc_errno\",\"libc\"],\"use-libc-auxv\":[]}}", "rustls-native-certs_0.8.3": "{\"dependencies\":[{\"name\":\"openssl-probe\",\"req\":\"^0.2\",\"target\":\"cfg(all(unix, not(target_os = \\\"macos\\\")))\"},{\"features\":[\"std\"],\"name\":\"pki-types\",\"package\":\"rustls-pki-types\",\"req\":\"^1.10\"},{\"kind\":\"dev\",\"name\":\"ring\",\"req\":\"^0.17\"},{\"kind\":\"dev\",\"name\":\"rustls\",\"req\":\"^0.23\"},{\"kind\":\"dev\",\"name\":\"rustls-webpki\",\"req\":\"^0.103\"},{\"name\":\"schannel\",\"req\":\"^0.1\",\"target\":\"cfg(windows)\"},{\"name\":\"security-framework\",\"req\":\"^3\",\"target\":\"cfg(target_os = \\\"macos\\\")\"},{\"kind\":\"dev\",\"name\":\"serial_test\",\"req\":\"^3\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.5\"},{\"kind\":\"dev\",\"name\":\"untrusted\",\"req\":\"^0.9\"},{\"kind\":\"dev\",\"name\":\"webpki-roots\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"x509-parser\",\"req\":\"^0.18\"}],\"features\":{}}", "rustls-pki-types_1.14.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"crabgrind\",\"req\":\"=0.1.9\",\"target\":\"cfg(all(target_os = \\\"linux\\\", target_arch = \\\"x86_64\\\"))\"},{\"name\":\"web-time\",\"optional\":true,\"req\":\"^1\",\"target\":\"cfg(all(target_family = \\\"wasm\\\", target_os = \\\"unknown\\\"))\"},{\"name\":\"zeroize\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"alloc\":[\"dep:zeroize\"],\"default\":[\"alloc\"],\"std\":[\"alloc\"],\"web\":[\"web-time\"]}}", @@ -1391,6 +1455,7 @@ "serial2_0.2.33": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"assert2\",\"req\":\"^0.3.11\"},{\"name\":\"cfg-if\",\"req\":\"^1.0.0\",\"target\":\"cfg(unix)\"},{\"name\":\"libc\",\"req\":\"^0.2.109\",\"target\":\"cfg(unix)\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.108\"},{\"features\":[\"commapi\",\"fileapi\",\"handleapi\",\"ioapiset\",\"std\",\"synchapi\",\"winbase\",\"winerror\",\"winreg\"],\"name\":\"winapi\",\"req\":\"^0.3.9\",\"target\":\"cfg(windows)\"}],\"features\":{\"doc\":[],\"doc-cfg\":[],\"rs4xx\":[],\"serde\":[\"dep:serde\"],\"unix\":[],\"windows\":[]}}", "serial_test_3.3.1": "{\"dependencies\":[{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2\"},{\"default_features\":false,\"name\":\"env_logger\",\"optional\":true,\"req\":\">=0.6.1\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"fslock\",\"optional\":true,\"req\":\"^0.2\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"futures-executor\",\"optional\":true,\"req\":\"^0.3\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"futures-util\",\"optional\":true,\"req\":\"^0.3\"},{\"default_features\":false,\"features\":[\"use_std\"],\"kind\":\"dev\",\"name\":\"itertools\",\"req\":\">=0.4\"},{\"name\":\"log\",\"optional\":true,\"req\":\">=0.4.4\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"once_cell\",\"req\":\"^1.19\"},{\"default_features\":false,\"name\":\"parking_lot\",\"req\":\"^0.12\"},{\"default_features\":false,\"name\":\"scc\",\"req\":\"^2\"},{\"name\":\"serial_test_derive\",\"req\":\"~3.3.1\"}],\"features\":{\"async\":[\"dep:futures-executor\",\"dep:futures-util\",\"serial_test_derive/async\"],\"default\":[\"logging\",\"async\"],\"docsrs\":[\"dep:document-features\"],\"file_locks\":[\"dep:fslock\"],\"logging\":[\"dep:log\"],\"test_logging\":[\"logging\",\"dep:env_logger\",\"serial_test_derive/test_logging\"]}}", "serial_test_derive_3.3.1": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\">=0.6.1\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"prettyplease\",\"req\":\"^0.2\"},{\"default_features\":false,\"features\":[\"proc-macro\"],\"name\":\"proc-macro2\",\"req\":\"^1.0.60\"},{\"default_features\":false,\"name\":\"quote\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"full\",\"printing\",\"parsing\",\"clone-impls\"],\"name\":\"syn\",\"req\":\"^2\"}],\"features\":{\"async\":[],\"default\":[],\"file_locks\":[],\"test_logging\":[]}}", + "sha1-checked_0.10.0": "{\"dependencies\":[{\"name\":\"digest\",\"req\":\"^0.10.7\"},{\"features\":[\"dev\"],\"kind\":\"dev\",\"name\":\"digest\",\"req\":\"^0.10.7\"},{\"kind\":\"dev\",\"name\":\"hex-literal\",\"req\":\"^0.4\"},{\"default_features\":false,\"features\":[\"compress\"],\"name\":\"sha1\",\"req\":\"^0.10.6\"},{\"default_features\":false,\"name\":\"zeroize\",\"optional\":true,\"req\":\"^1.7\"}],\"features\":{\"default\":[\"oid\",\"std\"],\"oid\":[\"digest/oid\",\"sha1/oid\"],\"std\":[\"digest/std\",\"sha1/std\"],\"zeroize\":[\"dep:zeroize\"]}}", "sha1_0.10.6": "{\"dependencies\":[{\"name\":\"cfg-if\",\"req\":\"^1.0\"},{\"name\":\"cpufeatures\",\"req\":\"^0.2\",\"target\":\"cfg(any(target_arch = \\\"aarch64\\\", target_arch = \\\"x86\\\", target_arch = \\\"x86_64\\\"))\"},{\"name\":\"digest\",\"req\":\"^0.10.7\"},{\"features\":[\"dev\"],\"kind\":\"dev\",\"name\":\"digest\",\"req\":\"^0.10.7\"},{\"kind\":\"dev\",\"name\":\"hex-literal\",\"req\":\"^0.2.2\"},{\"name\":\"sha1-asm\",\"optional\":true,\"req\":\"^0.5\",\"target\":\"cfg(any(target_arch = \\\"aarch64\\\", target_arch = \\\"x86\\\", target_arch = \\\"x86_64\\\"))\"}],\"features\":{\"asm\":[\"sha1-asm\"],\"compress\":[],\"default\":[\"std\"],\"force-soft\":[],\"loongarch64_asm\":[],\"oid\":[\"digest/oid\"],\"std\":[\"digest/std\"]}}", "sha1_smol_1.0.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"openssl\",\"req\":\"^0.10\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.4\"},{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"}],\"features\":{\"alloc\":[],\"std\":[\"alloc\"]}}", "sha2_0.10.9": "{\"dependencies\":[{\"name\":\"cfg-if\",\"req\":\"^1.0\"},{\"name\":\"cpufeatures\",\"req\":\"^0.2\",\"target\":\"cfg(any(target_arch = \\\"aarch64\\\", target_arch = \\\"x86_64\\\", target_arch = \\\"x86\\\"))\"},{\"name\":\"digest\",\"req\":\"^0.10.7\"},{\"features\":[\"dev\"],\"kind\":\"dev\",\"name\":\"digest\",\"req\":\"^0.10.7\"},{\"kind\":\"dev\",\"name\":\"hex-literal\",\"req\":\"^0.2.2\"},{\"name\":\"sha2-asm\",\"optional\":true,\"req\":\"^0.6.1\",\"target\":\"cfg(any(target_arch = \\\"aarch64\\\", target_arch = \\\"x86_64\\\", target_arch = \\\"x86\\\"))\"}],\"features\":{\"asm\":[\"sha2-asm\"],\"asm-aarch64\":[\"asm\"],\"compress\":[],\"default\":[\"std\"],\"force-soft\":[],\"force-soft-compact\":[],\"loongarch64_asm\":[],\"oid\":[\"digest/oid\"],\"std\":[\"digest/std\"]}}", @@ -1458,7 +1523,6 @@ "tagptr_0.2.0": "{\"dependencies\":[],\"features\":{}}", "tar_0.4.44": "{\"dependencies\":[{\"name\":\"filetime\",\"req\":\"^0.2.8\"},{\"name\":\"libc\",\"req\":\"^0.2\",\"target\":\"cfg(unix)\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3\"},{\"name\":\"xattr\",\"optional\":true,\"req\":\"^1.1.3\",\"target\":\"cfg(unix)\"}],\"features\":{\"default\":[\"xattr\"]}}", "target-lexicon_0.13.3": "{\"dependencies\":[{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"}],\"features\":{\"arch_z80\":[],\"arch_zkasm\":[],\"default\":[],\"serde_support\":[\"serde\",\"std\"],\"std\":[]}}", - "tempfile_3.24.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3\"},{\"name\":\"fastrand\",\"req\":\"^2.1.1\"},{\"default_features\":false,\"name\":\"getrandom\",\"optional\":true,\"req\":\"^0.3.0\",\"target\":\"cfg(any(unix, windows, target_os = \\\"wasi\\\"))\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"once_cell\",\"req\":\"^1.19.0\"},{\"features\":[\"fs\"],\"name\":\"rustix\",\"req\":\"^1.1.3\",\"target\":\"cfg(any(unix, target_os = \\\"wasi\\\"))\"},{\"features\":[\"Win32_Storage_FileSystem\",\"Win32_Foundation\"],\"name\":\"windows-sys\",\"req\":\">=0.52, <0.62\",\"target\":\"cfg(windows)\"}],\"features\":{\"default\":[\"getrandom\"],\"nightly\":[]}}", "tempfile_3.27.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3\"},{\"name\":\"fastrand\",\"req\":\"^2.1.1\"},{\"default_features\":false,\"name\":\"getrandom\",\"optional\":true,\"req\":\">=0.3.0, <0.5\",\"target\":\"cfg(any(unix, windows, target_os = \\\"wasi\\\"))\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"once_cell\",\"req\":\"^1.19.0\"},{\"features\":[\"fs\"],\"name\":\"rustix\",\"req\":\"^1.1.4\",\"target\":\"cfg(any(unix, target_os = \\\"wasi\\\"))\"},{\"features\":[\"Win32_Storage_FileSystem\",\"Win32_Foundation\"],\"name\":\"windows-sys\",\"req\":\">=0.52, <0.62\",\"target\":\"cfg(windows)\"}],\"features\":{\"default\":[\"getrandom\"],\"nightly\":[]}}", "temporal_capi_0.1.2": "{\"dependencies\":[{\"default_features\":false,\"name\":\"diplomat\",\"req\":\"^0.14.0\"},{\"default_features\":false,\"name\":\"diplomat-runtime\",\"req\":\"^0.14.0\"},{\"default_features\":false,\"features\":[\"unstable\"],\"name\":\"icu_calendar\",\"req\":\"^2.1.0\"},{\"name\":\"icu_locale\",\"req\":\"^2.1.0\"},{\"default_features\":false,\"name\":\"num-traits\",\"req\":\"^0.2.19\"},{\"default_features\":false,\"name\":\"temporal_rs\",\"req\":\"^0.1.2\"},{\"name\":\"timezone_provider\",\"req\":\"^0.1.2\"},{\"name\":\"writeable\",\"req\":\"^0.6.0\"},{\"name\":\"zoneinfo64\",\"optional\":true,\"req\":\"^0.2.0\"}],\"features\":{\"compiled_data\":[\"temporal_rs/compiled_data\"],\"zoneinfo64\":[\"dep:zoneinfo64\",\"timezone_provider/zoneinfo64\"]}}", "temporal_rs_0.1.2": "{\"dependencies\":[{\"name\":\"core_maths\",\"req\":\"^0.1.1\"},{\"name\":\"iana-time-zone\",\"optional\":true,\"req\":\"^0.1.64\"},{\"default_features\":false,\"features\":[\"unstable\",\"compiled_data\"],\"name\":\"icu_calendar\",\"req\":\"^2.1.0\"},{\"name\":\"icu_locale\",\"req\":\"^2.1.0\"},{\"features\":[\"duration\"],\"name\":\"ixdtf\",\"req\":\"^0.6.4\"},{\"name\":\"log\",\"optional\":true,\"req\":\"^0.4.28\"},{\"default_features\":false,\"name\":\"num-traits\",\"req\":\"^0.2.19\"},{\"name\":\"timezone_provider\",\"req\":\"^0.1.2\"},{\"name\":\"tinystr\",\"req\":\"^0.8.0\"},{\"name\":\"web-time\",\"optional\":true,\"req\":\"^1.1.0\"},{\"name\":\"writeable\",\"req\":\"^0.6.0\"}],\"features\":{\"compiled_data\":[\"tzdb\"],\"default\":[\"sys\"],\"float64_representable_durations\":[],\"log\":[\"dep:log\"],\"std\":[],\"sys\":[\"std\",\"compiled_data\",\"dep:web-time\",\"dep:iana-time-zone\"],\"tzdb\":[\"std\",\"timezone_provider/tzif\"]}}", @@ -1549,6 +1613,7 @@ "unic-langid_0.9.6": "{\"dependencies\":[{\"name\":\"unic-langid-impl\",\"req\":\"^0.9.6\"},{\"name\":\"unic-langid-macros\",\"optional\":true,\"req\":\"^0.9.6\"},{\"kind\":\"dev\",\"name\":\"unic-langid-macros\",\"req\":\"^0.9.6\"}],\"features\":{\"default\":[],\"likelysubtags\":[\"unic-langid-impl/likelysubtags\"],\"macros\":[\"unic-langid-macros\"],\"serde\":[\"unic-langid-impl/serde\"]}}", "unicase_2.9.0": "{\"dependencies\":[],\"features\":{\"nightly\":[]}}", "unicode-bidi_0.3.18": "{\"dependencies\":[{\"name\":\"flame\",\"optional\":true,\"req\":\"^0.2\"},{\"name\":\"flamer\",\"optional\":true,\"req\":\"^0.4\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\">=0.8, <2.0\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\">=0.8, <2.0\"},{\"features\":[\"union\"],\"name\":\"smallvec\",\"optional\":true,\"req\":\">=1.13\"}],\"features\":{\"bench_it\":[],\"default\":[\"std\",\"hardcoded-data\"],\"flame_it\":[\"flame\",\"flamer\"],\"hardcoded-data\":[],\"std\":[],\"unstable\":[],\"with_serde\":[\"serde\"]}}", + "unicode-bom_2.0.3": "{\"dependencies\":[],\"features\":{}}", "unicode-ident_1.0.22": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.7\"},{\"kind\":\"dev\",\"name\":\"fst\",\"req\":\"^0.4\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\"},{\"kind\":\"dev\",\"name\":\"roaring\",\"req\":\"^0.11\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"ucd-trie\",\"req\":\"^0.1\"},{\"kind\":\"dev\",\"name\":\"unicode-xid\",\"req\":\"^0.2.6\"}],\"features\":{}}", "unicode-ident_1.0.24": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.8\",\"target\":\"cfg(not(miri))\"},{\"kind\":\"dev\",\"name\":\"fst\",\"req\":\"^0.4\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.10\"},{\"kind\":\"dev\",\"name\":\"roaring\",\"req\":\"^0.11\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"ucd-trie\",\"req\":\"^0.1\"},{\"kind\":\"dev\",\"name\":\"unicode-xid\",\"req\":\"^0.2.6\"}],\"features\":{}}", "unicode-linebreak_0.1.5": "{\"dependencies\":[],\"features\":{}}", @@ -1723,6 +1788,7 @@ "zerovec_0.11.5": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"databake\",\"optional\":true,\"req\":\"^0.2.0\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.220\"},{\"default_features\":false,\"features\":[\"xxhash64\"],\"name\":\"twox-hash\",\"optional\":true,\"req\":\"^2.0.0\"},{\"default_features\":false,\"name\":\"yoke\",\"optional\":true,\"req\":\"^0.8.0\"},{\"default_features\":false,\"name\":\"zerofrom\",\"req\":\"^0.1.3\"},{\"default_features\":false,\"name\":\"zerovec-derive\",\"optional\":true,\"req\":\"^0.11.1\"}],\"features\":{\"alloc\":[\"serde?/alloc\"],\"databake\":[\"dep:databake\"],\"derive\":[\"dep:zerovec-derive\"],\"hashmap\":[\"dep:twox-hash\",\"alloc\"],\"serde\":[\"dep:serde\"],\"std\":[],\"yoke\":[\"dep:yoke\"]}}", "zip_0.6.6": "{\"dependencies\":[{\"name\":\"aes\",\"optional\":true,\"req\":\"^0.8.2\"},{\"kind\":\"dev\",\"name\":\"bencher\",\"req\":\"^0.1.5\"},{\"name\":\"byteorder\",\"req\":\"^1.4.3\"},{\"name\":\"bzip2\",\"optional\":true,\"req\":\"^0.4.3\"},{\"name\":\"constant_time_eq\",\"optional\":true,\"req\":\"^0.1.5\"},{\"name\":\"crc32fast\",\"req\":\"^1.3.2\"},{\"name\":\"crossbeam-utils\",\"req\":\"^0.8.8\",\"target\":\"cfg(any(all(target_arch = \\\"arm\\\", target_pointer_width = \\\"32\\\"), target_arch = \\\"mips\\\", target_arch = \\\"powerpc\\\"))\"},{\"default_features\":false,\"name\":\"flate2\",\"optional\":true,\"req\":\"^1.0.23\"},{\"kind\":\"dev\",\"name\":\"getrandom\",\"req\":\"^0.2.5\"},{\"features\":[\"reset\"],\"name\":\"hmac\",\"optional\":true,\"req\":\"^0.12.1\"},{\"name\":\"pbkdf2\",\"optional\":true,\"req\":\"^0.11.0\"},{\"name\":\"sha1\",\"optional\":true,\"req\":\"^0.10.1\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"time\",\"optional\":true,\"req\":\"^0.3.7\"},{\"features\":[\"formatting\",\"macros\"],\"kind\":\"dev\",\"name\":\"time\",\"req\":\"^0.3.7\"},{\"kind\":\"dev\",\"name\":\"walkdir\",\"req\":\"^2.3.2\"},{\"name\":\"zstd\",\"optional\":true,\"req\":\"^0.11.2\"}],\"features\":{\"aes-crypto\":[\"aes\",\"constant_time_eq\",\"hmac\",\"pbkdf2\",\"sha1\"],\"default\":[\"aes-crypto\",\"bzip2\",\"deflate\",\"time\",\"zstd\"],\"deflate\":[\"flate2/rust_backend\"],\"deflate-miniz\":[\"flate2/default\"],\"deflate-zlib\":[\"flate2/zlib\"],\"unreserved\":[]}}", "zip_2.4.2": "{\"dependencies\":[{\"name\":\"aes\",\"optional\":true,\"req\":\"^0.8\"},{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0.95\"},{\"features\":[\"derive\"],\"name\":\"arbitrary\",\"req\":\"^1.4.1\",\"target\":\"cfg(fuzzing)\"},{\"kind\":\"dev\",\"name\":\"bencher\",\"req\":\"^0.1.5\"},{\"name\":\"bzip2\",\"optional\":true,\"req\":\"^0.5.0\"},{\"name\":\"chrono\",\"optional\":true,\"req\":\"^0.4\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"clap\",\"req\":\"=4.4.18\"},{\"name\":\"constant_time_eq\",\"optional\":true,\"req\":\"^0.3\"},{\"name\":\"crc32fast\",\"req\":\"^1.4\"},{\"name\":\"crossbeam-utils\",\"req\":\"^0.8.21\",\"target\":\"cfg(any(all(target_arch = \\\"arm\\\", target_pointer_width = \\\"32\\\"), target_arch = \\\"mips\\\", target_arch = \\\"powerpc\\\"))\"},{\"name\":\"deflate64\",\"optional\":true,\"req\":\"^0.1.9\"},{\"default_features\":false,\"name\":\"displaydoc\",\"req\":\"^0.2\"},{\"default_features\":false,\"name\":\"flate2\",\"optional\":true,\"req\":\"^1.0\"},{\"features\":[\"wasm_js\",\"std\"],\"name\":\"getrandom\",\"optional\":true,\"req\":\"^0.3.1\"},{\"features\":[\"wasm_js\",\"std\"],\"kind\":\"dev\",\"name\":\"getrandom\",\"req\":\"^0.3.1\"},{\"features\":[\"reset\"],\"name\":\"hmac\",\"optional\":true,\"req\":\"^0.12\"},{\"name\":\"indexmap\",\"req\":\"^2\"},{\"default_features\":false,\"name\":\"lzma-rs\",\"optional\":true,\"req\":\"^0.3\"},{\"name\":\"memchr\",\"req\":\"^2.7\"},{\"default_features\":false,\"name\":\"nt-time\",\"optional\":true,\"req\":\"^0.10.6\"},{\"name\":\"pbkdf2\",\"optional\":true,\"req\":\"^0.12\"},{\"name\":\"sha1\",\"optional\":true,\"req\":\"^0.10\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.15\"},{\"name\":\"thiserror\",\"req\":\"^2\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"time\",\"optional\":true,\"req\":\"^0.3.37\"},{\"default_features\":false,\"features\":[\"formatting\",\"macros\"],\"kind\":\"dev\",\"name\":\"time\",\"req\":\"^0.3.37\"},{\"kind\":\"dev\",\"name\":\"walkdir\",\"req\":\"^2.5\"},{\"name\":\"xz2\",\"optional\":true,\"req\":\"^0.1.7\"},{\"features\":[\"zeroize_derive\"],\"name\":\"zeroize\",\"optional\":true,\"req\":\"^1.8\"},{\"name\":\"zopfli\",\"optional\":true,\"req\":\"^0.8\"},{\"default_features\":false,\"name\":\"zstd\",\"optional\":true,\"req\":\"^0.13\"}],\"features\":{\"_all-features\":[],\"_deflate-any\":[],\"aes-crypto\":[\"aes\",\"constant_time_eq\",\"hmac\",\"pbkdf2\",\"sha1\",\"getrandom\",\"zeroize\"],\"chrono\":[\"chrono/default\"],\"default\":[\"aes-crypto\",\"bzip2\",\"deflate64\",\"deflate\",\"lzma\",\"time\",\"zstd\",\"xz\"],\"deflate\":[\"flate2/rust_backend\",\"deflate-zopfli\",\"deflate-flate2\"],\"deflate-flate2\":[\"_deflate-any\"],\"deflate-miniz\":[\"deflate\",\"deflate-flate2\"],\"deflate-zlib\":[\"flate2/zlib\",\"deflate-flate2\"],\"deflate-zlib-ng\":[\"flate2/zlib-ng\",\"deflate-flate2\"],\"deflate-zopfli\":[\"zopfli\",\"_deflate-any\"],\"lzma\":[\"lzma-rs/stream\"],\"nt-time\":[\"dep:nt-time\"],\"unreserved\":[],\"xz\":[\"dep:xz2\"]}}", + "zlib-rs_0.6.3": "{\"dependencies\":[{\"features\":[\"derive\"],\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"crc32fast\",\"req\":\"^1.3.2\"},{\"kind\":\"dev\",\"name\":\"memoffset\",\"req\":\"^0.9.1\"},{\"default_features\":false,\"name\":\"quickcheck\",\"optional\":true,\"req\":\"^1.0.3\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0.3\"}],\"features\":{\"ZLIB_DEBUG\":[],\"__internal-api\":[],\"__internal-fuzz\":[\"arbitrary\"],\"__internal-fuzz-disable-checksum\":[],\"__internal-test\":[\"quickcheck\"],\"avx512\":[\"vpclmulqdq\"],\"c-allocator\":[],\"default\":[\"std\",\"c-allocator\"],\"rust-allocator\":[],\"std\":[\"rust-allocator\"],\"vpclmulqdq\":[]}}", "zmij_1.0.19": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.8\",\"target\":\"cfg(not(miri))\"},{\"name\":\"no-panic\",\"optional\":true,\"req\":\"^0.1.36\"},{\"kind\":\"dev\",\"name\":\"num-bigint\",\"req\":\"^0.4\"},{\"kind\":\"dev\",\"name\":\"num-integer\",\"req\":\"^0.1\"},{\"kind\":\"dev\",\"name\":\"num_cpus\",\"req\":\"^1.8\"},{\"kind\":\"dev\",\"name\":\"opt-level\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\"},{\"kind\":\"dev\",\"name\":\"ryu\",\"req\":\"^1\"}],\"features\":{}}", "zmij_1.0.21": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.8\",\"target\":\"cfg(not(miri))\"},{\"name\":\"no-panic\",\"optional\":true,\"req\":\"^0.1.36\"},{\"kind\":\"dev\",\"name\":\"num-bigint\",\"req\":\"^0.4\"},{\"kind\":\"dev\",\"name\":\"num-integer\",\"req\":\"^0.1\"},{\"kind\":\"dev\",\"name\":\"num_cpus\",\"req\":\"^1.8\"},{\"kind\":\"dev\",\"name\":\"opt-level\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.10\"},{\"kind\":\"dev\",\"name\":\"ryu\",\"req\":\"^1\"}],\"features\":{}}", "zoneinfo64_0.2.1": "{\"dependencies\":[{\"default_features\":false,\"name\":\"calendrical_calculations\",\"req\":\"^0.2.3\"},{\"name\":\"chrono\",\"optional\":true,\"req\":\"^0.4\"},{\"kind\":\"dev\",\"name\":\"chrono-tz\",\"req\":\"^0.10.4\"},{\"default_features\":false,\"name\":\"icu_locale_core\",\"req\":\"^2.1.0\"},{\"kind\":\"dev\",\"name\":\"itertools\",\"req\":\"^0.14.0\"},{\"default_features\":false,\"features\":[\"tzdb-bundle-always\",\"std\"],\"kind\":\"dev\",\"name\":\"jiff\",\"req\":\"^0.2.15\"},{\"default_features\":false,\"name\":\"potential_utf\",\"req\":\"^0.1.3\"},{\"default_features\":false,\"name\":\"resb\",\"req\":\"^0.1.0\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"req\":\"^1.0.220\"}],\"features\":{\"chrono\":[\"dep:chrono\"]}}", diff --git a/codex-rs/Cargo.lock b/codex-rs/Cargo.lock index 15ca924a8b..de1db07093 100644 --- a/codex-rs/Cargo.lock +++ b/codex-rs/Cargo.lock @@ -616,7 +616,7 @@ dependencies = [ "futures-lite", "parking", "polling", - "rustix 1.1.3", + "rustix 1.1.4", "slab", "windows-sys 0.61.2", ] @@ -647,7 +647,7 @@ dependencies = [ "cfg-if", "event-listener", "futures-lite", - "rustix 1.1.3", + "rustix 1.1.4", ] [[package]] @@ -673,7 +673,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", @@ -1349,6 +1349,15 @@ dependencies = [ "error-code", ] +[[package]] +name = "clru" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "197fd99cb113a8d5d9b6376f3aa817f32c1078f2343b714fff7d2ca44fdf67d5" +dependencies = [ + "hashbrown 0.16.1", +] + [[package]] name = "cmake" version = "0.1.57" @@ -1499,11 +1508,13 @@ dependencies = [ "sha2", "shlex", "tempfile", + "thiserror 2.0.18", "time", "tokio", "tokio-tungstenite", "tokio-util", "toml 0.9.11+spec-1.1.0", + "toml_edit 0.24.0+spec-1.1.0", "tracing", "tracing-opentelemetry", "tracing-subscriber", @@ -2272,16 +2283,20 @@ dependencies = [ name = "codex-git-utils" version = "0.0.0" dependencies = [ + "anyhow", "assert_matches", + "chrono", "codex-exec-server", "codex-protocol", "codex-utils-absolute-path", "futures", + "gix", "once_cell", "pretty_assertions", "regex", "schemars 0.8.22", "serde", + "similar", "tempfile", "thiserror 2.0.18", "tokio", @@ -3979,6 +3994,20 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + [[package]] name = "dasp_sample" version = "0.11.0" @@ -4615,6 +4644,16 @@ dependencies = [ "once_cell", ] +[[package]] +name = "faster-hex" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7223ae2d2f179b803433d9c830478527e92b8117eab39460edae7f1614d9fb73" +dependencies = [ + "heapless", + "serde", +] + [[package]] name = "fastrand" version = "2.3.0" @@ -4651,7 +4690,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", ] @@ -4681,6 +4720,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "filetime" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db" +dependencies = [ + "cfg-if", + "libc", + "libredox", +] + [[package]] name = "find-crate" version = "0.6.3" @@ -5049,7 +5099,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", ] @@ -5118,6 +5168,861 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "gix" +version = "0.81.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0473c64d9ccbcfb9953a133b47c8b9a335b87ac6c52b983ee4b03d49000b0f3f" +dependencies = [ + "gix-actor", + "gix-archive", + "gix-blame", + "gix-commitgraph", + "gix-config", + "gix-date", + "gix-diff", + "gix-dir", + "gix-discover", + "gix-error", + "gix-features", + "gix-filter", + "gix-fs", + "gix-glob", + "gix-hash", + "gix-hashtable", + "gix-index", + "gix-lock", + "gix-merge", + "gix-negotiate", + "gix-object", + "gix-odb", + "gix-pack", + "gix-path", + "gix-protocol", + "gix-ref", + "gix-refspec", + "gix-revision", + "gix-revwalk", + "gix-sec", + "gix-shallow", + "gix-status", + "gix-submodule", + "gix-tempfile", + "gix-trace", + "gix-traverse", + "gix-url", + "gix-utils", + "gix-validate", + "gix-worktree", + "gix-worktree-state", + "gix-worktree-stream", + "nonempty", + "smallvec", + "thiserror 2.0.18", +] + +[[package]] +name = "gix-actor" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e5e5b518339d5e6718af108fd064d4e9ba33caf728cf487352873d76411df35" +dependencies = [ + "bstr", + "gix-date", + "gix-error", + "winnow", +] + +[[package]] +name = "gix-archive" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "651c99be11aac9b303483193ae50b45eb6e094da4f5ed797019b03948f51aad6" +dependencies = [ + "bstr", + "gix-date", + "gix-error", + "gix-object", + "gix-worktree-stream", +] + +[[package]] +name = "gix-attributes" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c233d6eaa098c0ca5ce03236fd7a96e27f1abe72fad74b46003fbd11fe49563c" +dependencies = [ + "bstr", + "gix-glob", + "gix-path", + "gix-quote", + "gix-trace", + "kstring", + "smallvec", + "thiserror 2.0.18", + "unicode-bom", +] + +[[package]] +name = "gix-bitmap" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7add20f40d060db8c9b1314d499bac6ed7480f33eb113ce3e1cf5d6ff85d989" +dependencies = [ + "gix-error", +] + +[[package]] +name = "gix-blame" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c77aaf9f7348f4da3ebfbfbbc35fa0d07155d98377856198dde6f695fd648705" +dependencies = [ + "gix-commitgraph", + "gix-date", + "gix-diff", + "gix-error", + "gix-hash", + "gix-object", + "gix-revwalk", + "gix-trace", + "gix-traverse", + "gix-worktree", + "smallvec", + "thiserror 2.0.18", +] + +[[package]] +name = "gix-chunk" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1096b6608fbe5d27fb4984e20f992b4e76fb8c613f6acb87d07c5831b53a6959" +dependencies = [ + "gix-error", +] + +[[package]] +name = "gix-command" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b849c65a609f50d02f8a2774fe371650b3384a743c79c2a070ce0da49b7fb7da" +dependencies = [ + "bstr", + "gix-path", + "gix-quote", + "gix-trace", + "shell-words", +] + +[[package]] +name = "gix-commitgraph" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3196655fd1443f3c58a48c114aa480be3e4e87b393d7292daaa0d543862eb445" +dependencies = [ + "bstr", + "gix-chunk", + "gix-error", + "gix-hash", + "memmap2", + "nonempty", +] + +[[package]] +name = "gix-config" +version = "0.54.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08939b4c4ed7a663d0e64be9e1e9bdf23a1fb4fcee1febdf449f12229542e50d" +dependencies = [ + "bstr", + "gix-config-value", + "gix-features", + "gix-glob", + "gix-path", + "gix-ref", + "gix-sec", + "memchr", + "smallvec", + "thiserror 2.0.18", + "unicode-bom", + "winnow", +] + +[[package]] +name = "gix-config-value" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "441a300bc3645a1f45cba495b9175f90f47256ce43f2ee161da0031e3ac77c92" +dependencies = [ + "bitflags 2.10.0", + "bstr", + "gix-path", + "libc", + "thiserror 2.0.18", +] + +[[package]] +name = "gix-date" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39acf819aa9fee65e4838a2eec5cb2506e47ebb89e02a5ab9918196e491571ea" +dependencies = [ + "bstr", + "gix-error", + "itoa", + "jiff", + "smallvec", +] + +[[package]] +name = "gix-diff" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88f3b3475e5d3877d7c30c40827cc2441936ce890efc226e5ba4afe3a7ae33f0" +dependencies = [ + "bstr", + "gix-command", + "gix-filter", + "gix-fs", + "gix-hash", + "gix-object", + "gix-path", + "gix-tempfile", + "gix-trace", + "gix-traverse", + "gix-worktree", + "imara-diff 0.1.8", + "imara-diff 0.2.0", + "thiserror 2.0.18", +] + +[[package]] +name = "gix-dir" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5da4604a360988f0ba8efe6f90093ca5a844f4a7f8e1a3dcda501ec44e600ea9" +dependencies = [ + "bstr", + "gix-discover", + "gix-fs", + "gix-ignore", + "gix-index", + "gix-object", + "gix-path", + "gix-pathspec", + "gix-trace", + "gix-utils", + "gix-worktree", + "thiserror 2.0.18", +] + +[[package]] +name = "gix-discover" +version = "0.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c65bd3330fe0cb9d40d875bf862fd5e8ad6fa4164ddbc4842fbeb889c3f0b2c6" +dependencies = [ + "bstr", + "dunce", + "gix-fs", + "gix-path", + "gix-ref", + "gix-sec", + "thiserror 2.0.18", +] + +[[package]] +name = "gix-error" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e86d01da904d4a9265def43bd42a18c5e6dc7000a73af512946ba14579c9fbd" +dependencies = [ + "bstr", +] + +[[package]] +name = "gix-features" +version = "0.46.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "752493cd4b1d5eaaa0138a7493f65c96863fefa990fc021e0e519579e389ab20" +dependencies = [ + "bytes", + "crc32fast", + "gix-path", + "gix-trace", + "gix-utils", + "libc", + "once_cell", + "prodash", + "thiserror 2.0.18", + "walkdir", + "zlib-rs", +] + +[[package]] +name = "gix-filter" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d37598282a6566da6fb52667570c7fe0aedcb122ac886724a9e62a2180523e35" +dependencies = [ + "bstr", + "encoding_rs", + "gix-attributes", + "gix-command", + "gix-hash", + "gix-object", + "gix-packetline", + "gix-path", + "gix-quote", + "gix-trace", + "gix-utils", + "smallvec", + "thiserror 2.0.18", +] + +[[package]] +name = "gix-fs" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a964b4aec683eb0bacb87533defa80805bb4768056371a47ab38b00a2d377b72" +dependencies = [ + "bstr", + "fastrand", + "gix-features", + "gix-path", + "gix-utils", + "thiserror 2.0.18", +] + +[[package]] +name = "gix-glob" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b03e6cd88cc0dc1eafa1fddac0fb719e4e74b6ea58dd016e71125fde4a326bee" +dependencies = [ + "bitflags 2.10.0", + "bstr", + "gix-features", + "gix-path", +] + +[[package]] +name = "gix-hash" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fb896a02d9ab96fa518475a5f30ad3952010f801a8de5840f633f4a6b985dfb" +dependencies = [ + "faster-hex", + "gix-features", + "sha1-checked", + "thiserror 2.0.18", +] + +[[package]] +name = "gix-hashtable" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2664216fc5e89b51e756a4a3ac676315602ce2dac07acf1da959a22038d69b33" +dependencies = [ + "gix-hash", + "hashbrown 0.16.1", + "parking_lot", +] + +[[package]] +name = "gix-ignore" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09f915dcf6911e3027537166d34e13f0fe101ed12225178d2ae29cd1272cff26" +dependencies = [ + "bstr", + "gix-glob", + "gix-path", + "gix-trace", + "unicode-bom", +] + +[[package]] +name = "gix-index" +version = "0.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bae54ab14e4e74d5dda60b82ea7afad7c8eb3be68283d6d5f29bd2e6d47fff7" +dependencies = [ + "bitflags 2.10.0", + "bstr", + "filetime", + "fnv", + "gix-bitmap", + "gix-features", + "gix-fs", + "gix-hash", + "gix-lock", + "gix-object", + "gix-traverse", + "gix-utils", + "gix-validate", + "hashbrown 0.16.1", + "itoa", + "libc", + "memmap2", + "rustix 1.1.4", + "smallvec", + "thiserror 2.0.18", +] + +[[package]] +name = "gix-lock" +version = "21.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "054fbd0989700c69dc5aa80bc66944f05df1e15aa7391a9e42aca7366337905f" +dependencies = [ + "gix-tempfile", + "gix-utils", + "thiserror 2.0.18", +] + +[[package]] +name = "gix-merge" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4606747466512d22c2dffc019142e1941238f543987ea51353c938cca80c500" +dependencies = [ + "bstr", + "gix-command", + "gix-diff", + "gix-filter", + "gix-fs", + "gix-hash", + "gix-index", + "gix-object", + "gix-path", + "gix-quote", + "gix-revision", + "gix-revwalk", + "gix-tempfile", + "gix-trace", + "gix-worktree", + "imara-diff 0.1.8", + "nonempty", + "thiserror 2.0.18", +] + +[[package]] +name = "gix-negotiate" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea064c7595eea08fdd01c70748af747d9acc40f727b61f4c8a2145a5c5fc28c" +dependencies = [ + "bitflags 2.10.0", + "gix-commitgraph", + "gix-date", + "gix-hash", + "gix-object", + "gix-revwalk", +] + +[[package]] +name = "gix-object" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cafb802bb688a7c1e69ef965612ff5ff859f046bfb616377e4a0ba4c01e43d47" +dependencies = [ + "bstr", + "gix-actor", + "gix-date", + "gix-features", + "gix-hash", + "gix-hashtable", + "gix-path", + "gix-utils", + "gix-validate", + "itoa", + "smallvec", + "thiserror 2.0.18", + "winnow", +] + +[[package]] +name = "gix-odb" +version = "0.78.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24833ae9323b4f7079575fb9f961cf9c414b0afbec428a536ab8e7dd93bc002b" +dependencies = [ + "arc-swap", + "gix-features", + "gix-fs", + "gix-hash", + "gix-hashtable", + "gix-object", + "gix-pack", + "gix-path", + "gix-quote", + "parking_lot", + "tempfile", + "thiserror 2.0.18", +] + +[[package]] +name = "gix-pack" +version = "0.68.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3484119cd19859d7d7639413c27e192478fa354d3f4ff5f7e3c041e8040f0f4" +dependencies = [ + "clru", + "gix-chunk", + "gix-error", + "gix-features", + "gix-hash", + "gix-hashtable", + "gix-object", + "gix-path", + "memmap2", + "smallvec", + "thiserror 2.0.18", +] + +[[package]] +name = "gix-packetline" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be19313dcdb7dff75a3ce2f99be00878458295bcc3b6c7f0005591597573345c" +dependencies = [ + "bstr", + "faster-hex", + "gix-trace", + "thiserror 2.0.18", +] + +[[package]] +name = "gix-path" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09c31d4373bda7fab9eb01822927b55185a378d6e1bf737e0a54c743ad806658" +dependencies = [ + "bstr", + "gix-trace", + "gix-validate", + "thiserror 2.0.18", +] + +[[package]] +name = "gix-pathspec" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f89611f13544ca5ebeb68a502673814ef57200df60c24a61c2ce7b96f612f08b" +dependencies = [ + "bitflags 2.10.0", + "bstr", + "gix-attributes", + "gix-config-value", + "gix-glob", + "gix-path", + "thiserror 2.0.18", +] + +[[package]] +name = "gix-protocol" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f38666350736b5877c79f57ddae02bde07a4ce186d889adc391e831cddcbe76" +dependencies = [ + "bstr", + "gix-date", + "gix-features", + "gix-hash", + "gix-ref", + "gix-shallow", + "gix-transport", + "gix-utils", + "maybe-async", + "nonempty", + "thiserror 2.0.18", + "winnow", +] + +[[package]] +name = "gix-quote" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68533db71259c8776dd4e770d2b7b98696213ecdc1f5c9e3507119e274e0c578" +dependencies = [ + "bstr", + "gix-error", + "gix-utils", +] + +[[package]] +name = "gix-ref" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2159978abb99b7027c8579d15211e262ef0ef2594d5cecb3334fbcbdfe2997c" +dependencies = [ + "gix-actor", + "gix-features", + "gix-fs", + "gix-hash", + "gix-lock", + "gix-object", + "gix-path", + "gix-tempfile", + "gix-utils", + "gix-validate", + "memmap2", + "thiserror 2.0.18", + "winnow", +] + +[[package]] +name = "gix-refspec" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc806ee13f437428f8a1ba4c72ecfaa3f20e14f5f0d4c2bc17d0b33e794aa6ac" +dependencies = [ + "bstr", + "gix-error", + "gix-glob", + "gix-hash", + "gix-revision", + "gix-validate", + "smallvec", + "thiserror 2.0.18", +] + +[[package]] +name = "gix-revision" +version = "0.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c08f1ec5d1e6a524f8ba291c41f0ccaef64e48ed0e8cf790b3461cae45f6d3d" +dependencies = [ + "bitflags 2.10.0", + "bstr", + "gix-commitgraph", + "gix-date", + "gix-error", + "gix-hash", + "gix-object", + "gix-revwalk", + "gix-trace", + "nonempty", +] + +[[package]] +name = "gix-revwalk" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4b2b87772b21ca449249e86d32febadba5cba32b0fcce804ab9cefc6f2111c" +dependencies = [ + "gix-commitgraph", + "gix-date", + "gix-error", + "gix-hash", + "gix-hashtable", + "gix-object", + "smallvec", + "thiserror 2.0.18", +] + +[[package]] +name = "gix-sec" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf82ae037de9c62850ce67beaa92ec8e3e17785ea307cdde7618edc215603b4f" +dependencies = [ + "bitflags 2.10.0", + "gix-path", + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "gix-shallow" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf60711c9083b2364b3fac8a352444af76b17201f3682fdebe74fa66d89a772" +dependencies = [ + "bstr", + "gix-hash", + "gix-lock", + "nonempty", + "thiserror 2.0.18", +] + +[[package]] +name = "gix-status" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d6c598e3fdbc352fba1c5ba7e709e69402fafbc44d9295edad2e3c4738996b" +dependencies = [ + "bstr", + "filetime", + "gix-diff", + "gix-dir", + "gix-features", + "gix-filter", + "gix-fs", + "gix-hash", + "gix-index", + "gix-object", + "gix-path", + "gix-pathspec", + "gix-worktree", + "portable-atomic", + "thiserror 2.0.18", +] + +[[package]] +name = "gix-submodule" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce5c3929c5e6821f651d35e8420f72fea3cfafe9fc1e928a61e718b462c72a5" +dependencies = [ + "bstr", + "gix-config", + "gix-path", + "gix-pathspec", + "gix-refspec", + "gix-url", + "thiserror 2.0.18", +] + +[[package]] +name = "gix-tempfile" +version = "21.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d22227f6b203f511ff451c33c89899e87e4f571fc596b06f68e6e613a6508528" +dependencies = [ + "dashmap", + "gix-fs", + "libc", + "parking_lot", + "tempfile", +] + +[[package]] +name = "gix-trace" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f69a13643b8437d4ca6845e08143e847a36ca82903eed13303475d0ae8b162e0" + +[[package]] +name = "gix-transport" +version = "0.55.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a521e39c6235ce63ed6c001e2dd79818c830b82c3b7b59247ee7b229c39ec9bb" +dependencies = [ + "bstr", + "gix-command", + "gix-features", + "gix-packetline", + "gix-quote", + "gix-sec", + "gix-url", + "thiserror 2.0.18", +] + +[[package]] +name = "gix-traverse" +version = "0.55.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "963dc2afcdb611092aa587c3f9365e749ac0a0892ff27662dbc75f26c953fbec" +dependencies = [ + "bitflags 2.10.0", + "gix-commitgraph", + "gix-date", + "gix-hash", + "gix-hashtable", + "gix-object", + "gix-revwalk", + "smallvec", + "thiserror 2.0.18", +] + +[[package]] +name = "gix-url" +version = "0.35.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d28e8af3d42581190da884f013caf254d2fd4d6ab102408f08d21bfa11de6c8d" +dependencies = [ + "bstr", + "gix-path", + "percent-encoding", + "thiserror 2.0.18", +] + +[[package]] +name = "gix-utils" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "befcdbdfb1238d2854591f760a48711bed85e72d80a10e8f2f93f656746ef7c5" +dependencies = [ + "bstr", + "fastrand", + "unicode-normalization", +] + +[[package]] +name = "gix-validate" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec1eff98d91941f47766367cba1be746bab662bad761d9891ae6f7882f7840b" +dependencies = [ + "bstr", +] + +[[package]] +name = "gix-worktree" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6bd5830cbc43c9c00918b826467d2afad685b195cb82329cde2b2d116d2c578" +dependencies = [ + "bstr", + "gix-attributes", + "gix-fs", + "gix-glob", + "gix-hash", + "gix-ignore", + "gix-index", + "gix-object", + "gix-path", + "gix-validate", +] + +[[package]] +name = "gix-worktree-state" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "644a1681f96e1be43c2a8384337d9d220e7624f50db54beda70997052aebf707" +dependencies = [ + "bstr", + "gix-features", + "gix-filter", + "gix-fs", + "gix-index", + "gix-object", + "gix-path", + "gix-worktree", + "io-close", + "thiserror 2.0.18", +] + +[[package]] +name = "gix-worktree-stream" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24e3fb70a1f650a5cec7d5b8d10d6d6fe86daf3cf15bde08ba0c70988a2932c3" +dependencies = [ + "gix-attributes", + "gix-error", + "gix-features", + "gix-filter", + "gix-fs", + "gix-hash", + "gix-object", + "gix-path", + "gix-traverse", + "parking_lot", +] + [[package]] name = "glib" version = "0.21.5" @@ -5231,6 +6136,15 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -5302,6 +6216,16 @@ dependencies = [ "http 1.4.0", ] +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32", + "stable_deref_trait", +] + [[package]] name = "heck" version = "0.4.1" @@ -5877,6 +6801,25 @@ dependencies = [ "quick-error", ] +[[package]] +name = "imara-diff" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17d34b7d42178945f775e84bc4c36dde7c1c6cdfea656d3354d009056f2bb3d2" +dependencies = [ + "hashbrown 0.15.5", +] + +[[package]] +name = "imara-diff" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f01d462f766df78ab820dd06f5eb700233c51f0f4c2e846520eaf4ba6aa5c5c" +dependencies = [ + "hashbrown 0.15.5", + "memchr", +] + [[package]] name = "impl-more" version = "0.1.9" @@ -6023,6 +6966,16 @@ dependencies = [ "rustversion", ] +[[package]] +name = "io-close" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cadcf447f06744f8ce713d2d6239bb5bde2c357a452397a9ed90c625da390bc" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "io_tee" version = "0.1.1" @@ -6130,28 +7083,45 @@ checksum = "84de9d95a6d2547d9b77ee3f25fa0ee32e3c3a6484d47a55adebc0439c077992" [[package]] name = "jiff" -version = "0.2.18" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e67e8da4c49d6d9909fe03361f9b620f58898859f5c7aded68351e85e71ecf50" +checksum = "1a3546dc96b6d42c5f24902af9e2538e82e39ad350b0c766eb3fbf2d8f3d8359" dependencies = [ "jiff-static", + "jiff-tzdb-platform", "log", "portable-atomic", "portable-atomic-util", "serde_core", + "windows-sys 0.61.2", ] [[package]] name = "jiff-static" -version = "0.2.18" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0c84ee7f197eca9a86c6fd6cb771e55eb991632f15f2bc3ca6ec838929e6e78" +checksum = "2a8c8b344124222efd714b73bb41f8b5120b27a7cc1c75593a6ff768d9d05aa4" dependencies = [ "proc-macro2", "quote", "syn 2.0.114", ] +[[package]] +name = "jiff-tzdb" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c900ef84826f1338a557697dc8fc601df9ca9af4ac137c7fb61d4c6f2dfd3076" + +[[package]] +name = "jiff-tzdb-platform" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8" +dependencies = [ + "jiff-tzdb", +] + [[package]] name = "jni" version = "0.21.1" @@ -6247,6 +7217,15 @@ dependencies = [ "libc", ] +[[package]] +name = "kstring" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "558bf9508a558512042d3095138b1f7b8fe90c5467d94f9f1da28b3731c5dbd1" +dependencies = [ + "static_assertions", +] + [[package]] name = "lalrpop" version = "0.19.12" @@ -6426,9 +7405,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" @@ -6615,6 +7594,17 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3eede3bdf92f3b4f9dc04072a9ce5ab557d5ec9038773bf9ffcd5588b3cc05b" +[[package]] +name = "maybe-async" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + [[package]] name = "mcp_test_support" version = "0.0.0" @@ -6657,6 +7647,15 @@ version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +[[package]] +name = "memmap2" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3" +dependencies = [ + "libc", +] + [[package]] name = "memoffset" version = "0.6.5" @@ -6872,6 +7871,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "nonempty" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9737e026353e5cd0736f98eddae28665118eb6f6600902a7f50db585621fecb6" + [[package]] name = "normalize-line-endings" version = "0.3.0" @@ -7864,7 +8869,7 @@ dependencies = [ "concurrent-queue", "hermit-abi", "pin-project-lite", - "rustix 1.1.3", + "rustix 1.1.4", "windows-sys 0.61.2", ] @@ -8051,6 +9056,15 @@ dependencies = [ "windows 0.62.2", ] +[[package]] +name = "prodash" +version = "31.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "962200e2d7d551451297d9fdce85138374019ada198e30ea9ede38034e27604c" +dependencies = [ + "parking_lot", +] + [[package]] name = "proptest" version = "1.9.0" @@ -9115,14 +10129,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.10.0", "errno", "libc", - "linux-raw-sys 0.11.0", + "linux-raw-sys 0.12.1", "windows-sys 0.61.2", ] @@ -9803,6 +10817,16 @@ dependencies = [ "digest", ] +[[package]] +name = "sha1-checked" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89f599ac0c323ebb1c6082821a54962b839832b03984598375bff3975b804423" +dependencies = [ + "digest", + "sha1", +] + [[package]] name = "sha1_smol" version = "1.0.1" @@ -10574,14 +11598,14 @@ checksum = "df7f62577c25e07834649fc3b39fafdc597c0a3527dc1c60129201ccfcbaa50c" [[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", ] @@ -10644,7 +11668,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0" dependencies = [ - "rustix 1.1.3", + "rustix 1.1.4", "windows-sys 0.60.2", ] @@ -11499,6 +12523,12 @@ version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" +[[package]] +name = "unicode-bom" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eec5d1121208364f6793f7d2e222bf75a915c19557537745b195b253dd64217" + [[package]] name = "unicode-ident" version = "1.0.22" @@ -11859,7 +12889,7 @@ checksum = "fee64194ccd96bf648f42a65a7e589547096dfa702f7cadef84347b66ad164f9" dependencies = [ "cc", "downcast-rs", - "rustix 1.1.3", + "rustix 1.1.4", "smallvec", "wayland-sys", ] @@ -11871,7 +12901,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8e6faa537fbb6c186cb9f1d41f2f811a4120d1b57ec61f50da451a0c5122bec" dependencies = [ "bitflags 2.10.0", - "rustix 1.1.3", + "rustix 1.1.4", "wayland-backend", "wayland-scanner", ] @@ -12037,7 +13067,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3fabb953106c3c8eea8306e4393700d7657561cb43122571b172bbfb7c7ba1d" dependencies = [ "env_home", - "rustix 1.1.3", + "rustix 1.1.4", "winsafe", ] @@ -12702,7 +13732,7 @@ dependencies = [ "libc", "log", "os_pipe", - "rustix 1.1.3", + "rustix 1.1.4", "thiserror 2.0.18", "tree_magic_mini", "wayland-backend", @@ -12724,7 +13754,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", ] @@ -13038,6 +14068,12 @@ dependencies = [ "zstd 0.13.3", ] +[[package]] +name = "zlib-rs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be3d40e40a133f9c916ee3f9f4fa2d9d63435b5fbe1bfc6d9dae0aa0ada1513" + [[package]] name = "zmij" version = "1.0.19" diff --git a/codex-rs/Cargo.toml b/codex-rs/Cargo.toml index b83674e591..75e54abfba 100644 --- a/codex-rs/Cargo.toml +++ b/codex-rs/Cargo.toml @@ -244,6 +244,7 @@ env_logger = "0.11.9" eventsource-stream = "0.2.3" futures = { version = "0.3", default-features = false } gethostname = "1.1.0" +gix = { version = "0.81.0", default-features = false, features = ["sha1"] } glob = "0.3" globset = "0.4" hmac = "0.12.1" diff --git a/codex-rs/analytics/src/analytics_client_tests.rs b/codex-rs/analytics/src/analytics_client_tests.rs index bf97da4284..15f456ef3f 100644 --- a/codex-rs/analytics/src/analytics_client_tests.rs +++ b/codex-rs/analytics/src/analytics_client_tests.rs @@ -65,6 +65,7 @@ use codex_app_server_protocol::InitializeCapabilities; use codex_app_server_protocol::InitializeParams; use codex_app_server_protocol::JSONRPCErrorError; use codex_app_server_protocol::NonSteerableTurnKind; +use codex_app_server_protocol::PermissionProfile as AppServerPermissionProfile; use codex_app_server_protocol::RequestId; use codex_app_server_protocol::SandboxPolicy as AppServerSandboxPolicy; use codex_app_server_protocol::ServerNotification; @@ -91,6 +92,7 @@ use codex_plugin::PluginTelemetryMetadata; use codex_protocol::approvals::NetworkApprovalProtocol; use codex_protocol::config_types::ApprovalsReviewer; use codex_protocol::config_types::ModeKind; +use codex_protocol::models::PermissionProfile as CorePermissionProfile; use codex_protocol::protocol::AskForApproval; use codex_protocol::protocol::HookEventName; use codex_protocol::protocol::HookRunStatus; @@ -152,11 +154,20 @@ fn sample_thread_start_response(thread_id: &str, ephemeral: bool, model: &str) - approval_policy: AppServerAskForApproval::OnFailure, approvals_reviewer: AppServerApprovalsReviewer::User, sandbox: AppServerSandboxPolicy::DangerFullAccess, + permission_profile: sample_permission_profile(), reasoning_effort: None, }, } } +fn sample_permission_profile() -> AppServerPermissionProfile { + CorePermissionProfile::from_legacy_sandbox_policy( + &SandboxPolicy::DangerFullAccess, + &test_path_buf("/tmp"), + ) + .into() +} + fn sample_app_server_client_metadata() -> CodexAppServerClientMetadata { CodexAppServerClientMetadata { product_client_id: DEFAULT_ORIGINATOR.to_string(), @@ -203,6 +214,7 @@ fn sample_thread_resume_response_with_source( approval_policy: AppServerAskForApproval::OnFailure, approvals_reviewer: AppServerApprovalsReviewer::User, sandbox: AppServerSandboxPolicy::DangerFullAccess, + permission_profile: sample_permission_profile(), reasoning_effort: None, }, } diff --git a/codex-rs/app-server-protocol/schema/json/ClientRequest.json b/codex-rs/app-server-protocol/schema/json/ClientRequest.json index 43871d74a0..e5243a1126 100644 --- a/codex-rs/app-server-protocol/schema/json/ClientRequest.json +++ b/codex-rs/app-server-protocol/schema/json/ClientRequest.json @@ -12,6 +12,17 @@ ], "type": "string" }, + "AdditionalNetworkPermissions": { + "properties": { + "enabled": { + "type": [ + "boolean", + "null" + ] + } + }, + "type": "object" + }, "ApprovalsReviewer": { "description": "Configures who approval requests are routed to for review. Examples include sandbox escapes, blocked network access, MCP approval prompts, and ARC escalations. Defaults to `user`. `guardian_subagent` uses a carefully prompted subagent to gather relevant context and apply a risk-based decision framework before approving or denying the request.", "enum": [ @@ -217,6 +228,17 @@ "null" ] }, + "permissionProfile": { + "anyOf": [ + { + "$ref": "#/definitions/PermissionProfile" + }, + { + "type": "null" + } + ], + "description": "Optional full permissions profile for this command.\n\nDefaults to the user's configured permissions when omitted. Cannot be combined with `sandboxPolicy`." + }, "processId": { "description": "Optional client-supplied, connection-scoped process id.\n\nRequired for `tty`, `streamStdin`, `streamStdoutStderr`, and follow-up `command/exec/write`, `command/exec/resize`, and `command/exec/terminate` calls. When omitted, buffered execution gets an internal id that is not exposed to the client.", "type": [ @@ -233,7 +255,7 @@ "type": "null" } ], - "description": "Optional sandbox policy for this command.\n\nUses the same shape as thread/turn execution sandbox configuration and defaults to the user's configured policy when omitted." + "description": "Optional sandbox policy for this command.\n\nUses the same shape as thread/turn execution sandbox configuration and defaults to the user's configured policy when omitted. Cannot be combined with `permissionProfile`." }, "size": { "anyOf": [ @@ -521,6 +543,200 @@ } ] }, + "DeviceKeyCreateParams": { + "description": "Create a controller-local device key with a random key id.", + "properties": { + "accountUserId": { + "type": "string" + }, + "clientId": { + "type": "string" + }, + "protectionPolicy": { + "anyOf": [ + { + "$ref": "#/definitions/DeviceKeyProtectionPolicy" + }, + { + "type": "null" + } + ], + "description": "Defaults to `hardware_only` when omitted." + } + }, + "required": [ + "accountUserId", + "clientId" + ], + "type": "object" + }, + "DeviceKeyProtectionPolicy": { + "description": "Protection policy for creating or loading a controller-local device key.", + "enum": [ + "hardware_only", + "allow_os_protected_nonextractable" + ], + "type": "string" + }, + "DeviceKeyPublicParams": { + "description": "Fetch a controller-local device key public key by id.", + "properties": { + "keyId": { + "type": "string" + } + }, + "required": [ + "keyId" + ], + "type": "object" + }, + "DeviceKeySignParams": { + "description": "Sign an accepted structured payload with a controller-local device key.", + "properties": { + "keyId": { + "type": "string" + }, + "payload": { + "$ref": "#/definitions/DeviceKeySignPayload" + } + }, + "required": [ + "keyId", + "payload" + ], + "type": "object" + }, + "DeviceKeySignPayload": { + "description": "Structured payloads accepted by `device/key/sign`.", + "oneOf": [ + { + "description": "Payload bound to one remote-control controller websocket `/client` connection challenge.", + "properties": { + "accountUserId": { + "type": "string" + }, + "audience": { + "$ref": "#/definitions/RemoteControlClientConnectionAudience" + }, + "clientId": { + "type": "string" + }, + "nonce": { + "type": "string" + }, + "scopes": { + "description": "Must contain exactly `remote_control_controller_websocket`.", + "items": { + "type": "string" + }, + "type": "array" + }, + "sessionId": { + "description": "Backend-issued websocket session id that this proof authorizes.", + "type": "string" + }, + "targetOrigin": { + "description": "Origin of the backend endpoint that issued the challenge and will verify this proof.", + "type": "string" + }, + "targetPath": { + "description": "Websocket route path that this proof authorizes.", + "type": "string" + }, + "tokenExpiresAt": { + "description": "Remote-control token expiration as Unix seconds.", + "format": "int64", + "type": "integer" + }, + "tokenSha256Base64url": { + "description": "SHA-256 of the controller-scoped remote-control token, encoded as unpadded base64url.", + "type": "string" + }, + "type": { + "enum": [ + "remoteControlClientConnection" + ], + "title": "RemoteControlClientConnectionDeviceKeySignPayloadType", + "type": "string" + } + }, + "required": [ + "accountUserId", + "audience", + "clientId", + "nonce", + "scopes", + "sessionId", + "targetOrigin", + "targetPath", + "tokenExpiresAt", + "tokenSha256Base64url", + "type" + ], + "title": "RemoteControlClientConnectionDeviceKeySignPayload", + "type": "object" + }, + { + "description": "Payload bound to a remote-control client `/client/enroll` ownership challenge.", + "properties": { + "accountUserId": { + "type": "string" + }, + "audience": { + "$ref": "#/definitions/RemoteControlClientEnrollmentAudience" + }, + "challengeExpiresAt": { + "description": "Enrollment challenge expiration as Unix seconds.", + "format": "int64", + "type": "integer" + }, + "challengeId": { + "description": "Backend-issued enrollment challenge id that this proof authorizes.", + "type": "string" + }, + "clientId": { + "type": "string" + }, + "deviceIdentitySha256Base64url": { + "description": "SHA-256 of the requested device identity operation, encoded as unpadded base64url.", + "type": "string" + }, + "nonce": { + "type": "string" + }, + "targetOrigin": { + "description": "Origin of the backend endpoint that issued the challenge and will verify this proof.", + "type": "string" + }, + "targetPath": { + "description": "HTTP route path that this proof authorizes.", + "type": "string" + }, + "type": { + "enum": [ + "remoteControlClientEnrollment" + ], + "title": "RemoteControlClientEnrollmentDeviceKeySignPayloadType", + "type": "string" + } + }, + "required": [ + "accountUserId", + "audience", + "challengeExpiresAt", + "challengeId", + "clientId", + "deviceIdentitySha256Base64url", + "nonce", + "targetOrigin", + "targetPath", + "type" + ], + "title": "RemoteControlClientEnrollmentDeviceKeySignPayload", + "type": "object" + } + ] + }, "DynamicToolSpec": { "properties": { "deferLoading": { @@ -703,6 +919,217 @@ ], "type": "object" }, + "FileSystemAccessMode": { + "enum": [ + "read", + "write", + "none" + ], + "type": "string" + }, + "FileSystemPath": { + "oneOf": [ + { + "properties": { + "path": { + "$ref": "#/definitions/AbsolutePathBuf" + }, + "type": { + "enum": [ + "path" + ], + "title": "PathFileSystemPathType", + "type": "string" + } + }, + "required": [ + "path", + "type" + ], + "title": "PathFileSystemPath", + "type": "object" + }, + { + "properties": { + "pattern": { + "type": "string" + }, + "type": { + "enum": [ + "glob_pattern" + ], + "title": "GlobPatternFileSystemPathType", + "type": "string" + } + }, + "required": [ + "pattern", + "type" + ], + "title": "GlobPatternFileSystemPath", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "special" + ], + "title": "SpecialFileSystemPathType", + "type": "string" + }, + "value": { + "$ref": "#/definitions/FileSystemSpecialPath" + } + }, + "required": [ + "type", + "value" + ], + "title": "SpecialFileSystemPath", + "type": "object" + } + ] + }, + "FileSystemSandboxEntry": { + "properties": { + "access": { + "$ref": "#/definitions/FileSystemAccessMode" + }, + "path": { + "$ref": "#/definitions/FileSystemPath" + } + }, + "required": [ + "access", + "path" + ], + "type": "object" + }, + "FileSystemSpecialPath": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "root" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "RootFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "minimal" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "MinimalFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "current_working_directory" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "CurrentWorkingDirectoryFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "project_roots" + ], + "type": "string" + }, + "subpath": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "kind" + ], + "title": "KindFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "tmpdir" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "TmpdirFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "slash_tmp" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "SlashTmpFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "unknown" + ], + "type": "string" + }, + "path": { + "type": "string" + }, + "subpath": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "kind", + "path" + ], + "type": "object" + } + ] + }, "FsCopyParams": { "description": "Copy a file or directory tree on the host filesystem.", "properties": { @@ -1463,6 +1890,53 @@ ], "type": "string" }, + "PermissionProfile": { + "properties": { + "fileSystem": { + "anyOf": [ + { + "$ref": "#/definitions/PermissionProfileFileSystemPermissions" + }, + { + "type": "null" + } + ] + }, + "network": { + "anyOf": [ + { + "$ref": "#/definitions/AdditionalNetworkPermissions" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" + }, + "PermissionProfileFileSystemPermissions": { + "properties": { + "entries": { + "items": { + "$ref": "#/definitions/FileSystemSandboxEntry" + }, + "type": "array" + }, + "globScanMaxDepth": { + "format": "uint", + "minimum": 1.0, + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "entries" + ], + "type": "object" + }, "Personality": { "enum": [ "none", @@ -1747,6 +2221,20 @@ } ] }, + "RemoteControlClientConnectionAudience": { + "description": "Audience for a remote-control client connection device-key proof.", + "enum": [ + "remote_control_client_websocket" + ], + "type": "string" + }, + "RemoteControlClientEnrollmentAudience": { + "description": "Audience for a remote-control client enrollment device-key proof.", + "enum": [ + "remote_control_client_enrollment" + ], + "type": "string" + }, "RequestId": { "anyOf": [ { @@ -2821,6 +3309,17 @@ "null" ] }, + "permissionProfile": { + "anyOf": [ + { + "$ref": "#/definitions/PermissionProfile" + }, + { + "type": "null" + } + ], + "description": "Full permissions override for the forked thread. Cannot be combined with `sandbox`." + }, "sandbox": { "anyOf": [ { @@ -3192,6 +3691,17 @@ "null" ] }, + "permissionProfile": { + "anyOf": [ + { + "$ref": "#/definitions/PermissionProfile" + }, + { + "type": "null" + } + ], + "description": "Full permissions override for the resumed thread. Cannot be combined with `sandbox`." + }, "personality": { "anyOf": [ { @@ -3375,6 +3885,17 @@ "null" ] }, + "permissionProfile": { + "anyOf": [ + { + "$ref": "#/definitions/PermissionProfile" + }, + { + "type": "null" + } + ], + "description": "Full permissions override for this thread. Cannot be combined with `sandbox`." + }, "personality": { "anyOf": [ { @@ -3571,6 +4092,17 @@ "outputSchema": { "description": "Optional JSON Schema used to constrain the final assistant message for this turn." }, + "permissionProfile": { + "anyOf": [ + { + "$ref": "#/definitions/PermissionProfile" + }, + { + "type": "null" + } + ], + "description": "Override the full permissions profile for this turn and subsequent turns. Cannot be combined with `sandboxPolicy`." + }, "personality": { "anyOf": [ { @@ -4360,6 +4892,78 @@ "title": "App/listRequest", "type": "object" }, + { + "properties": { + "id": { + "$ref": "#/definitions/RequestId" + }, + "method": { + "enum": [ + "device/key/create" + ], + "title": "Device/key/createRequestMethod", + "type": "string" + }, + "params": { + "$ref": "#/definitions/DeviceKeyCreateParams" + } + }, + "required": [ + "id", + "method", + "params" + ], + "title": "Device/key/createRequest", + "type": "object" + }, + { + "properties": { + "id": { + "$ref": "#/definitions/RequestId" + }, + "method": { + "enum": [ + "device/key/public" + ], + "title": "Device/key/publicRequestMethod", + "type": "string" + }, + "params": { + "$ref": "#/definitions/DeviceKeyPublicParams" + } + }, + "required": [ + "id", + "method", + "params" + ], + "title": "Device/key/publicRequest", + "type": "object" + }, + { + "properties": { + "id": { + "$ref": "#/definitions/RequestId" + }, + "method": { + "enum": [ + "device/key/sign" + ], + "title": "Device/key/signRequestMethod", + "type": "string" + }, + "params": { + "$ref": "#/definitions/DeviceKeySignParams" + } + }, + "required": [ + "id", + "method", + "params" + ], + "title": "Device/key/signRequest", + "type": "object" + }, { "properties": { "id": { diff --git a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json index 612a3b7f7e..9202ac7a05 100644 --- a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json +++ b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json @@ -737,6 +737,78 @@ "title": "App/listRequest", "type": "object" }, + { + "properties": { + "id": { + "$ref": "#/definitions/v2/RequestId" + }, + "method": { + "enum": [ + "device/key/create" + ], + "title": "Device/key/createRequestMethod", + "type": "string" + }, + "params": { + "$ref": "#/definitions/v2/DeviceKeyCreateParams" + } + }, + "required": [ + "id", + "method", + "params" + ], + "title": "Device/key/createRequest", + "type": "object" + }, + { + "properties": { + "id": { + "$ref": "#/definitions/v2/RequestId" + }, + "method": { + "enum": [ + "device/key/public" + ], + "title": "Device/key/publicRequestMethod", + "type": "string" + }, + "params": { + "$ref": "#/definitions/v2/DeviceKeyPublicParams" + } + }, + "required": [ + "id", + "method", + "params" + ], + "title": "Device/key/publicRequest", + "type": "object" + }, + { + "properties": { + "id": { + "$ref": "#/definitions/v2/RequestId" + }, + "method": { + "enum": [ + "device/key/sign" + ], + "title": "Device/key/signRequestMethod", + "type": "string" + }, + "params": { + "$ref": "#/definitions/v2/DeviceKeySignParams" + } + }, + "required": [ + "id", + "method", + "params" + ], + "title": "Device/key/signRequest", + "type": "object" + }, { "properties": { "id": { @@ -6301,6 +6373,17 @@ "null" ] }, + "permissionProfile": { + "anyOf": [ + { + "$ref": "#/definitions/v2/PermissionProfile" + }, + { + "type": "null" + } + ], + "description": "Optional full permissions profile for this command.\n\nDefaults to the user's configured permissions when omitted. Cannot be combined with `sandboxPolicy`." + }, "processId": { "description": "Optional client-supplied, connection-scoped process id.\n\nRequired for `tty`, `streamStdin`, `streamStdoutStderr`, and follow-up `command/exec/write`, `command/exec/resize`, and `command/exec/terminate` calls. When omitted, buffered execution gets an internal id that is not exposed to the client.", "type": [ @@ -6317,7 +6400,7 @@ "type": "null" } ], - "description": "Optional sandbox policy for this command.\n\nUses the same shape as thread/turn execution sandbox configuration and defaults to the user's configured policy when omitted." + "description": "Optional sandbox policy for this command.\n\nUses the same shape as thread/turn execution sandbox configuration and defaults to the user's configured policy when omitted. Cannot be combined with `permissionProfile`." }, "size": { "anyOf": [ @@ -7328,6 +7411,300 @@ "title": "DeprecationNoticeNotification", "type": "object" }, + "DeviceKeyAlgorithm": { + "description": "Device-key algorithm reported at enrollment and signing boundaries.", + "enum": [ + "ecdsa_p256_sha256" + ], + "type": "string" + }, + "DeviceKeyCreateParams": { + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Create a controller-local device key with a random key id.", + "properties": { + "accountUserId": { + "type": "string" + }, + "clientId": { + "type": "string" + }, + "protectionPolicy": { + "anyOf": [ + { + "$ref": "#/definitions/v2/DeviceKeyProtectionPolicy" + }, + { + "type": "null" + } + ], + "description": "Defaults to `hardware_only` when omitted." + } + }, + "required": [ + "accountUserId", + "clientId" + ], + "title": "DeviceKeyCreateParams", + "type": "object" + }, + "DeviceKeyCreateResponse": { + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Device-key metadata and public key returned by create/public APIs.", + "properties": { + "algorithm": { + "$ref": "#/definitions/v2/DeviceKeyAlgorithm" + }, + "keyId": { + "type": "string" + }, + "protectionClass": { + "$ref": "#/definitions/v2/DeviceKeyProtectionClass" + }, + "publicKeySpkiDerBase64": { + "description": "SubjectPublicKeyInfo DER encoded as base64.", + "type": "string" + } + }, + "required": [ + "algorithm", + "keyId", + "protectionClass", + "publicKeySpkiDerBase64" + ], + "title": "DeviceKeyCreateResponse", + "type": "object" + }, + "DeviceKeyProtectionClass": { + "description": "Platform protection class for a controller-local device key.", + "enum": [ + "hardware_secure_enclave", + "hardware_tpm", + "os_protected_nonextractable" + ], + "type": "string" + }, + "DeviceKeyProtectionPolicy": { + "description": "Protection policy for creating or loading a controller-local device key.", + "enum": [ + "hardware_only", + "allow_os_protected_nonextractable" + ], + "type": "string" + }, + "DeviceKeyPublicParams": { + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Fetch a controller-local device key public key by id.", + "properties": { + "keyId": { + "type": "string" + } + }, + "required": [ + "keyId" + ], + "title": "DeviceKeyPublicParams", + "type": "object" + }, + "DeviceKeyPublicResponse": { + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Device-key public metadata returned by `device/key/public`.", + "properties": { + "algorithm": { + "$ref": "#/definitions/v2/DeviceKeyAlgorithm" + }, + "keyId": { + "type": "string" + }, + "protectionClass": { + "$ref": "#/definitions/v2/DeviceKeyProtectionClass" + }, + "publicKeySpkiDerBase64": { + "description": "SubjectPublicKeyInfo DER encoded as base64.", + "type": "string" + } + }, + "required": [ + "algorithm", + "keyId", + "protectionClass", + "publicKeySpkiDerBase64" + ], + "title": "DeviceKeyPublicResponse", + "type": "object" + }, + "DeviceKeySignParams": { + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Sign an accepted structured payload with a controller-local device key.", + "properties": { + "keyId": { + "type": "string" + }, + "payload": { + "$ref": "#/definitions/v2/DeviceKeySignPayload" + } + }, + "required": [ + "keyId", + "payload" + ], + "title": "DeviceKeySignParams", + "type": "object" + }, + "DeviceKeySignPayload": { + "description": "Structured payloads accepted by `device/key/sign`.", + "oneOf": [ + { + "description": "Payload bound to one remote-control controller websocket `/client` connection challenge.", + "properties": { + "accountUserId": { + "type": "string" + }, + "audience": { + "$ref": "#/definitions/v2/RemoteControlClientConnectionAudience" + }, + "clientId": { + "type": "string" + }, + "nonce": { + "type": "string" + }, + "scopes": { + "description": "Must contain exactly `remote_control_controller_websocket`.", + "items": { + "type": "string" + }, + "type": "array" + }, + "sessionId": { + "description": "Backend-issued websocket session id that this proof authorizes.", + "type": "string" + }, + "targetOrigin": { + "description": "Origin of the backend endpoint that issued the challenge and will verify this proof.", + "type": "string" + }, + "targetPath": { + "description": "Websocket route path that this proof authorizes.", + "type": "string" + }, + "tokenExpiresAt": { + "description": "Remote-control token expiration as Unix seconds.", + "format": "int64", + "type": "integer" + }, + "tokenSha256Base64url": { + "description": "SHA-256 of the controller-scoped remote-control token, encoded as unpadded base64url.", + "type": "string" + }, + "type": { + "enum": [ + "remoteControlClientConnection" + ], + "title": "RemoteControlClientConnectionDeviceKeySignPayloadType", + "type": "string" + } + }, + "required": [ + "accountUserId", + "audience", + "clientId", + "nonce", + "scopes", + "sessionId", + "targetOrigin", + "targetPath", + "tokenExpiresAt", + "tokenSha256Base64url", + "type" + ], + "title": "RemoteControlClientConnectionDeviceKeySignPayload", + "type": "object" + }, + { + "description": "Payload bound to a remote-control client `/client/enroll` ownership challenge.", + "properties": { + "accountUserId": { + "type": "string" + }, + "audience": { + "$ref": "#/definitions/v2/RemoteControlClientEnrollmentAudience" + }, + "challengeExpiresAt": { + "description": "Enrollment challenge expiration as Unix seconds.", + "format": "int64", + "type": "integer" + }, + "challengeId": { + "description": "Backend-issued enrollment challenge id that this proof authorizes.", + "type": "string" + }, + "clientId": { + "type": "string" + }, + "deviceIdentitySha256Base64url": { + "description": "SHA-256 of the requested device identity operation, encoded as unpadded base64url.", + "type": "string" + }, + "nonce": { + "type": "string" + }, + "targetOrigin": { + "description": "Origin of the backend endpoint that issued the challenge and will verify this proof.", + "type": "string" + }, + "targetPath": { + "description": "HTTP route path that this proof authorizes.", + "type": "string" + }, + "type": { + "enum": [ + "remoteControlClientEnrollment" + ], + "title": "RemoteControlClientEnrollmentDeviceKeySignPayloadType", + "type": "string" + } + }, + "required": [ + "accountUserId", + "audience", + "challengeExpiresAt", + "challengeId", + "clientId", + "deviceIdentitySha256Base64url", + "nonce", + "targetOrigin", + "targetPath", + "type" + ], + "title": "RemoteControlClientEnrollmentDeviceKeySignPayload", + "type": "object" + } + ] + }, + "DeviceKeySignResponse": { + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "ASN.1 DER signature returned by `device/key/sign`.", + "properties": { + "algorithm": { + "$ref": "#/definitions/v2/DeviceKeyAlgorithm" + }, + "signatureDerBase64": { + "description": "ECDSA signature DER encoded as base64.", + "type": "string" + }, + "signedPayloadBase64": { + "description": "Exact bytes signed by the device key, encoded as base64. Verifiers must verify this byte string directly and must not reserialize `payload`.", + "type": "string" + } + }, + "required": [ + "algorithm", + "signatureDerBase64", + "signedPayloadBase64" + ], + "title": "DeviceKeySignResponse", + "type": "object" + }, "DynamicToolCallOutputContentItem": { "oneOf": [ { @@ -10523,6 +10900,53 @@ } ] }, + "PermissionProfile": { + "properties": { + "fileSystem": { + "anyOf": [ + { + "$ref": "#/definitions/v2/PermissionProfileFileSystemPermissions" + }, + { + "type": "null" + } + ] + }, + "network": { + "anyOf": [ + { + "$ref": "#/definitions/v2/AdditionalNetworkPermissions" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" + }, + "PermissionProfileFileSystemPermissions": { + "properties": { + "entries": { + "items": { + "$ref": "#/definitions/v2/FileSystemSandboxEntry" + }, + "type": "array" + }, + "globScanMaxDepth": { + "format": "uint", + "minimum": 1.0, + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "entries" + ], + "type": "object" + }, "Personality": { "enum": [ "none", @@ -11646,6 +12070,20 @@ "title": "ReasoningTextDeltaNotification", "type": "object" }, + "RemoteControlClientConnectionAudience": { + "description": "Audience for a remote-control client connection device-key proof.", + "enum": [ + "remote_control_client_websocket" + ], + "type": "string" + }, + "RemoteControlClientEnrollmentAudience": { + "description": "Audience for a remote-control client enrollment device-key proof.", + "enum": [ + "remote_control_client_enrollment" + ], + "type": "string" + }, "RequestId": { "anyOf": [ { @@ -13600,6 +14038,17 @@ "null" ] }, + "permissionProfile": { + "anyOf": [ + { + "$ref": "#/definitions/v2/PermissionProfile" + }, + { + "type": "null" + } + ], + "description": "Full permissions override for the forked thread. Cannot be combined with `sandbox`." + }, "sandbox": { "anyOf": [ { @@ -13668,6 +14117,9 @@ "modelProvider": { "type": "string" }, + "permissionProfile": { + "$ref": "#/definitions/v2/PermissionProfile" + }, "reasoningEffort": { "anyOf": [ { @@ -13701,6 +14153,7 @@ "cwd", "model", "modelProvider", + "permissionProfile", "sandbox", "thread" ], @@ -14980,6 +15433,17 @@ "null" ] }, + "permissionProfile": { + "anyOf": [ + { + "$ref": "#/definitions/v2/PermissionProfile" + }, + { + "type": "null" + } + ], + "description": "Full permissions override for the resumed thread. Cannot be combined with `sandbox`." + }, "personality": { "anyOf": [ { @@ -15058,6 +15522,9 @@ "modelProvider": { "type": "string" }, + "permissionProfile": { + "$ref": "#/definitions/v2/PermissionProfile" + }, "reasoningEffort": { "anyOf": [ { @@ -15091,6 +15558,7 @@ "cwd", "model", "modelProvider", + "permissionProfile", "sandbox", "thread" ], @@ -15269,6 +15737,17 @@ "null" ] }, + "permissionProfile": { + "anyOf": [ + { + "$ref": "#/definitions/v2/PermissionProfile" + }, + { + "type": "null" + } + ], + "description": "Full permissions override for this thread. Cannot be combined with `sandbox`." + }, "personality": { "anyOf": [ { @@ -15357,6 +15836,9 @@ "modelProvider": { "type": "string" }, + "permissionProfile": { + "$ref": "#/definitions/v2/PermissionProfile" + }, "reasoningEffort": { "anyOf": [ { @@ -15390,6 +15872,7 @@ "cwd", "model", "modelProvider", + "permissionProfile", "sandbox", "thread" ], @@ -16042,6 +16525,17 @@ "outputSchema": { "description": "Optional JSON Schema used to constrain the final assistant message for this turn." }, + "permissionProfile": { + "anyOf": [ + { + "$ref": "#/definitions/v2/PermissionProfile" + }, + { + "type": "null" + } + ], + "description": "Override the full permissions profile for this turn and subsequent turns. Cannot be combined with `sandboxPolicy`." + }, "personality": { "anyOf": [ { diff --git a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json index 4ff918e642..22173db493 100644 --- a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json +++ b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json @@ -1418,6 +1418,78 @@ "title": "App/listRequest", "type": "object" }, + { + "properties": { + "id": { + "$ref": "#/definitions/RequestId" + }, + "method": { + "enum": [ + "device/key/create" + ], + "title": "Device/key/createRequestMethod", + "type": "string" + }, + "params": { + "$ref": "#/definitions/DeviceKeyCreateParams" + } + }, + "required": [ + "id", + "method", + "params" + ], + "title": "Device/key/createRequest", + "type": "object" + }, + { + "properties": { + "id": { + "$ref": "#/definitions/RequestId" + }, + "method": { + "enum": [ + "device/key/public" + ], + "title": "Device/key/publicRequestMethod", + "type": "string" + }, + "params": { + "$ref": "#/definitions/DeviceKeyPublicParams" + } + }, + "required": [ + "id", + "method", + "params" + ], + "title": "Device/key/publicRequest", + "type": "object" + }, + { + "properties": { + "id": { + "$ref": "#/definitions/RequestId" + }, + "method": { + "enum": [ + "device/key/sign" + ], + "title": "Device/key/signRequestMethod", + "type": "string" + }, + "params": { + "$ref": "#/definitions/DeviceKeySignParams" + } + }, + "required": [ + "id", + "method", + "params" + ], + "title": "Device/key/signRequest", + "type": "object" + }, { "properties": { "id": { @@ -2908,6 +2980,17 @@ "null" ] }, + "permissionProfile": { + "anyOf": [ + { + "$ref": "#/definitions/PermissionProfile" + }, + { + "type": "null" + } + ], + "description": "Optional full permissions profile for this command.\n\nDefaults to the user's configured permissions when omitted. Cannot be combined with `sandboxPolicy`." + }, "processId": { "description": "Optional client-supplied, connection-scoped process id.\n\nRequired for `tty`, `streamStdin`, `streamStdoutStderr`, and follow-up `command/exec/write`, `command/exec/resize`, and `command/exec/terminate` calls. When omitted, buffered execution gets an internal id that is not exposed to the client.", "type": [ @@ -2924,7 +3007,7 @@ "type": "null" } ], - "description": "Optional sandbox policy for this command.\n\nUses the same shape as thread/turn execution sandbox configuration and defaults to the user's configured policy when omitted." + "description": "Optional sandbox policy for this command.\n\nUses the same shape as thread/turn execution sandbox configuration and defaults to the user's configured policy when omitted. Cannot be combined with `permissionProfile`." }, "size": { "anyOf": [ @@ -3935,6 +4018,300 @@ "title": "DeprecationNoticeNotification", "type": "object" }, + "DeviceKeyAlgorithm": { + "description": "Device-key algorithm reported at enrollment and signing boundaries.", + "enum": [ + "ecdsa_p256_sha256" + ], + "type": "string" + }, + "DeviceKeyCreateParams": { + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Create a controller-local device key with a random key id.", + "properties": { + "accountUserId": { + "type": "string" + }, + "clientId": { + "type": "string" + }, + "protectionPolicy": { + "anyOf": [ + { + "$ref": "#/definitions/DeviceKeyProtectionPolicy" + }, + { + "type": "null" + } + ], + "description": "Defaults to `hardware_only` when omitted." + } + }, + "required": [ + "accountUserId", + "clientId" + ], + "title": "DeviceKeyCreateParams", + "type": "object" + }, + "DeviceKeyCreateResponse": { + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Device-key metadata and public key returned by create/public APIs.", + "properties": { + "algorithm": { + "$ref": "#/definitions/DeviceKeyAlgorithm" + }, + "keyId": { + "type": "string" + }, + "protectionClass": { + "$ref": "#/definitions/DeviceKeyProtectionClass" + }, + "publicKeySpkiDerBase64": { + "description": "SubjectPublicKeyInfo DER encoded as base64.", + "type": "string" + } + }, + "required": [ + "algorithm", + "keyId", + "protectionClass", + "publicKeySpkiDerBase64" + ], + "title": "DeviceKeyCreateResponse", + "type": "object" + }, + "DeviceKeyProtectionClass": { + "description": "Platform protection class for a controller-local device key.", + "enum": [ + "hardware_secure_enclave", + "hardware_tpm", + "os_protected_nonextractable" + ], + "type": "string" + }, + "DeviceKeyProtectionPolicy": { + "description": "Protection policy for creating or loading a controller-local device key.", + "enum": [ + "hardware_only", + "allow_os_protected_nonextractable" + ], + "type": "string" + }, + "DeviceKeyPublicParams": { + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Fetch a controller-local device key public key by id.", + "properties": { + "keyId": { + "type": "string" + } + }, + "required": [ + "keyId" + ], + "title": "DeviceKeyPublicParams", + "type": "object" + }, + "DeviceKeyPublicResponse": { + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Device-key public metadata returned by `device/key/public`.", + "properties": { + "algorithm": { + "$ref": "#/definitions/DeviceKeyAlgorithm" + }, + "keyId": { + "type": "string" + }, + "protectionClass": { + "$ref": "#/definitions/DeviceKeyProtectionClass" + }, + "publicKeySpkiDerBase64": { + "description": "SubjectPublicKeyInfo DER encoded as base64.", + "type": "string" + } + }, + "required": [ + "algorithm", + "keyId", + "protectionClass", + "publicKeySpkiDerBase64" + ], + "title": "DeviceKeyPublicResponse", + "type": "object" + }, + "DeviceKeySignParams": { + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Sign an accepted structured payload with a controller-local device key.", + "properties": { + "keyId": { + "type": "string" + }, + "payload": { + "$ref": "#/definitions/DeviceKeySignPayload" + } + }, + "required": [ + "keyId", + "payload" + ], + "title": "DeviceKeySignParams", + "type": "object" + }, + "DeviceKeySignPayload": { + "description": "Structured payloads accepted by `device/key/sign`.", + "oneOf": [ + { + "description": "Payload bound to one remote-control controller websocket `/client` connection challenge.", + "properties": { + "accountUserId": { + "type": "string" + }, + "audience": { + "$ref": "#/definitions/RemoteControlClientConnectionAudience" + }, + "clientId": { + "type": "string" + }, + "nonce": { + "type": "string" + }, + "scopes": { + "description": "Must contain exactly `remote_control_controller_websocket`.", + "items": { + "type": "string" + }, + "type": "array" + }, + "sessionId": { + "description": "Backend-issued websocket session id that this proof authorizes.", + "type": "string" + }, + "targetOrigin": { + "description": "Origin of the backend endpoint that issued the challenge and will verify this proof.", + "type": "string" + }, + "targetPath": { + "description": "Websocket route path that this proof authorizes.", + "type": "string" + }, + "tokenExpiresAt": { + "description": "Remote-control token expiration as Unix seconds.", + "format": "int64", + "type": "integer" + }, + "tokenSha256Base64url": { + "description": "SHA-256 of the controller-scoped remote-control token, encoded as unpadded base64url.", + "type": "string" + }, + "type": { + "enum": [ + "remoteControlClientConnection" + ], + "title": "RemoteControlClientConnectionDeviceKeySignPayloadType", + "type": "string" + } + }, + "required": [ + "accountUserId", + "audience", + "clientId", + "nonce", + "scopes", + "sessionId", + "targetOrigin", + "targetPath", + "tokenExpiresAt", + "tokenSha256Base64url", + "type" + ], + "title": "RemoteControlClientConnectionDeviceKeySignPayload", + "type": "object" + }, + { + "description": "Payload bound to a remote-control client `/client/enroll` ownership challenge.", + "properties": { + "accountUserId": { + "type": "string" + }, + "audience": { + "$ref": "#/definitions/RemoteControlClientEnrollmentAudience" + }, + "challengeExpiresAt": { + "description": "Enrollment challenge expiration as Unix seconds.", + "format": "int64", + "type": "integer" + }, + "challengeId": { + "description": "Backend-issued enrollment challenge id that this proof authorizes.", + "type": "string" + }, + "clientId": { + "type": "string" + }, + "deviceIdentitySha256Base64url": { + "description": "SHA-256 of the requested device identity operation, encoded as unpadded base64url.", + "type": "string" + }, + "nonce": { + "type": "string" + }, + "targetOrigin": { + "description": "Origin of the backend endpoint that issued the challenge and will verify this proof.", + "type": "string" + }, + "targetPath": { + "description": "HTTP route path that this proof authorizes.", + "type": "string" + }, + "type": { + "enum": [ + "remoteControlClientEnrollment" + ], + "title": "RemoteControlClientEnrollmentDeviceKeySignPayloadType", + "type": "string" + } + }, + "required": [ + "accountUserId", + "audience", + "challengeExpiresAt", + "challengeId", + "clientId", + "deviceIdentitySha256Base64url", + "nonce", + "targetOrigin", + "targetPath", + "type" + ], + "title": "RemoteControlClientEnrollmentDeviceKeySignPayload", + "type": "object" + } + ] + }, + "DeviceKeySignResponse": { + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "ASN.1 DER signature returned by `device/key/sign`.", + "properties": { + "algorithm": { + "$ref": "#/definitions/DeviceKeyAlgorithm" + }, + "signatureDerBase64": { + "description": "ECDSA signature DER encoded as base64.", + "type": "string" + }, + "signedPayloadBase64": { + "description": "Exact bytes signed by the device key, encoded as base64. Verifiers must verify this byte string directly and must not reserialize `payload`.", + "type": "string" + } + }, + "required": [ + "algorithm", + "signatureDerBase64", + "signedPayloadBase64" + ], + "title": "DeviceKeySignResponse", + "type": "object" + }, "DynamicToolCallOutputContentItem": { "oneOf": [ { @@ -7285,6 +7662,53 @@ } ] }, + "PermissionProfile": { + "properties": { + "fileSystem": { + "anyOf": [ + { + "$ref": "#/definitions/PermissionProfileFileSystemPermissions" + }, + { + "type": "null" + } + ] + }, + "network": { + "anyOf": [ + { + "$ref": "#/definitions/AdditionalNetworkPermissions" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" + }, + "PermissionProfileFileSystemPermissions": { + "properties": { + "entries": { + "items": { + "$ref": "#/definitions/FileSystemSandboxEntry" + }, + "type": "array" + }, + "globScanMaxDepth": { + "format": "uint", + "minimum": 1.0, + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "entries" + ], + "type": "object" + }, "Personality": { "enum": [ "none", @@ -8408,6 +8832,20 @@ "title": "ReasoningTextDeltaNotification", "type": "object" }, + "RemoteControlClientConnectionAudience": { + "description": "Audience for a remote-control client connection device-key proof.", + "enum": [ + "remote_control_client_websocket" + ], + "type": "string" + }, + "RemoteControlClientEnrollmentAudience": { + "description": "Audience for a remote-control client enrollment device-key proof.", + "enum": [ + "remote_control_client_enrollment" + ], + "type": "string" + }, "RequestId": { "anyOf": [ { @@ -11494,6 +11932,17 @@ "null" ] }, + "permissionProfile": { + "anyOf": [ + { + "$ref": "#/definitions/PermissionProfile" + }, + { + "type": "null" + } + ], + "description": "Full permissions override for the forked thread. Cannot be combined with `sandbox`." + }, "sandbox": { "anyOf": [ { @@ -11562,6 +12011,9 @@ "modelProvider": { "type": "string" }, + "permissionProfile": { + "$ref": "#/definitions/PermissionProfile" + }, "reasoningEffort": { "anyOf": [ { @@ -11595,6 +12047,7 @@ "cwd", "model", "modelProvider", + "permissionProfile", "sandbox", "thread" ], @@ -12874,6 +13327,17 @@ "null" ] }, + "permissionProfile": { + "anyOf": [ + { + "$ref": "#/definitions/PermissionProfile" + }, + { + "type": "null" + } + ], + "description": "Full permissions override for the resumed thread. Cannot be combined with `sandbox`." + }, "personality": { "anyOf": [ { @@ -12952,6 +13416,9 @@ "modelProvider": { "type": "string" }, + "permissionProfile": { + "$ref": "#/definitions/PermissionProfile" + }, "reasoningEffort": { "anyOf": [ { @@ -12985,6 +13452,7 @@ "cwd", "model", "modelProvider", + "permissionProfile", "sandbox", "thread" ], @@ -13163,6 +13631,17 @@ "null" ] }, + "permissionProfile": { + "anyOf": [ + { + "$ref": "#/definitions/PermissionProfile" + }, + { + "type": "null" + } + ], + "description": "Full permissions override for this thread. Cannot be combined with `sandbox`." + }, "personality": { "anyOf": [ { @@ -13251,6 +13730,9 @@ "modelProvider": { "type": "string" }, + "permissionProfile": { + "$ref": "#/definitions/PermissionProfile" + }, "reasoningEffort": { "anyOf": [ { @@ -13284,6 +13766,7 @@ "cwd", "model", "modelProvider", + "permissionProfile", "sandbox", "thread" ], @@ -13936,6 +14419,17 @@ "outputSchema": { "description": "Optional JSON Schema used to constrain the final assistant message for this turn." }, + "permissionProfile": { + "anyOf": [ + { + "$ref": "#/definitions/PermissionProfile" + }, + { + "type": "null" + } + ], + "description": "Override the full permissions profile for this turn and subsequent turns. Cannot be combined with `sandboxPolicy`." + }, "personality": { "anyOf": [ { diff --git a/codex-rs/app-server-protocol/schema/json/v2/CommandExecParams.json b/codex-rs/app-server-protocol/schema/json/v2/CommandExecParams.json index 986ec4cc1e..2198aad5bc 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/CommandExecParams.json +++ b/codex-rs/app-server-protocol/schema/json/v2/CommandExecParams.json @@ -5,6 +5,17 @@ "description": "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.", "type": "string" }, + "AdditionalNetworkPermissions": { + "properties": { + "enabled": { + "type": [ + "boolean", + "null" + ] + } + }, + "type": "object" + }, "CommandExecTerminalSize": { "description": "PTY size in character cells for `command/exec` PTY sessions.", "properties": { @@ -27,6 +38,217 @@ ], "type": "object" }, + "FileSystemAccessMode": { + "enum": [ + "read", + "write", + "none" + ], + "type": "string" + }, + "FileSystemPath": { + "oneOf": [ + { + "properties": { + "path": { + "$ref": "#/definitions/AbsolutePathBuf" + }, + "type": { + "enum": [ + "path" + ], + "title": "PathFileSystemPathType", + "type": "string" + } + }, + "required": [ + "path", + "type" + ], + "title": "PathFileSystemPath", + "type": "object" + }, + { + "properties": { + "pattern": { + "type": "string" + }, + "type": { + "enum": [ + "glob_pattern" + ], + "title": "GlobPatternFileSystemPathType", + "type": "string" + } + }, + "required": [ + "pattern", + "type" + ], + "title": "GlobPatternFileSystemPath", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "special" + ], + "title": "SpecialFileSystemPathType", + "type": "string" + }, + "value": { + "$ref": "#/definitions/FileSystemSpecialPath" + } + }, + "required": [ + "type", + "value" + ], + "title": "SpecialFileSystemPath", + "type": "object" + } + ] + }, + "FileSystemSandboxEntry": { + "properties": { + "access": { + "$ref": "#/definitions/FileSystemAccessMode" + }, + "path": { + "$ref": "#/definitions/FileSystemPath" + } + }, + "required": [ + "access", + "path" + ], + "type": "object" + }, + "FileSystemSpecialPath": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "root" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "RootFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "minimal" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "MinimalFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "current_working_directory" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "CurrentWorkingDirectoryFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "project_roots" + ], + "type": "string" + }, + "subpath": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "kind" + ], + "title": "KindFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "tmpdir" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "TmpdirFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "slash_tmp" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "SlashTmpFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "unknown" + ], + "type": "string" + }, + "path": { + "type": "string" + }, + "subpath": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "kind", + "path" + ], + "type": "object" + } + ] + }, "NetworkAccess": { "enum": [ "restricted", @@ -34,6 +256,53 @@ ], "type": "string" }, + "PermissionProfile": { + "properties": { + "fileSystem": { + "anyOf": [ + { + "$ref": "#/definitions/PermissionProfileFileSystemPermissions" + }, + { + "type": "null" + } + ] + }, + "network": { + "anyOf": [ + { + "$ref": "#/definitions/AdditionalNetworkPermissions" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" + }, + "PermissionProfileFileSystemPermissions": { + "properties": { + "entries": { + "items": { + "$ref": "#/definitions/FileSystemSandboxEntry" + }, + "type": "array" + }, + "globScanMaxDepth": { + "format": "uint", + "minimum": 1.0, + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "entries" + ], + "type": "object" + }, "ReadOnlyAccess": { "oneOf": [ { @@ -247,6 +516,17 @@ "null" ] }, + "permissionProfile": { + "anyOf": [ + { + "$ref": "#/definitions/PermissionProfile" + }, + { + "type": "null" + } + ], + "description": "Optional full permissions profile for this command.\n\nDefaults to the user's configured permissions when omitted. Cannot be combined with `sandboxPolicy`." + }, "processId": { "description": "Optional client-supplied, connection-scoped process id.\n\nRequired for `tty`, `streamStdin`, `streamStdoutStderr`, and follow-up `command/exec/write`, `command/exec/resize`, and `command/exec/terminate` calls. When omitted, buffered execution gets an internal id that is not exposed to the client.", "type": [ @@ -263,7 +543,7 @@ "type": "null" } ], - "description": "Optional sandbox policy for this command.\n\nUses the same shape as thread/turn execution sandbox configuration and defaults to the user's configured policy when omitted." + "description": "Optional sandbox policy for this command.\n\nUses the same shape as thread/turn execution sandbox configuration and defaults to the user's configured policy when omitted. Cannot be combined with `permissionProfile`." }, "size": { "anyOf": [ diff --git a/codex-rs/app-server-protocol/schema/json/v2/DeviceKeyCreateParams.json b/codex-rs/app-server-protocol/schema/json/v2/DeviceKeyCreateParams.json new file mode 100644 index 0000000000..fe2c0f0895 --- /dev/null +++ b/codex-rs/app-server-protocol/schema/json/v2/DeviceKeyCreateParams.json @@ -0,0 +1,39 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "definitions": { + "DeviceKeyProtectionPolicy": { + "description": "Protection policy for creating or loading a controller-local device key.", + "enum": [ + "hardware_only", + "allow_os_protected_nonextractable" + ], + "type": "string" + } + }, + "description": "Create a controller-local device key with a random key id.", + "properties": { + "accountUserId": { + "type": "string" + }, + "clientId": { + "type": "string" + }, + "protectionPolicy": { + "anyOf": [ + { + "$ref": "#/definitions/DeviceKeyProtectionPolicy" + }, + { + "type": "null" + } + ], + "description": "Defaults to `hardware_only` when omitted." + } + }, + "required": [ + "accountUserId", + "clientId" + ], + "title": "DeviceKeyCreateParams", + "type": "object" +} \ No newline at end of file diff --git a/codex-rs/app-server-protocol/schema/json/v2/DeviceKeyCreateResponse.json b/codex-rs/app-server-protocol/schema/json/v2/DeviceKeyCreateResponse.json new file mode 100644 index 0000000000..12072588a9 --- /dev/null +++ b/codex-rs/app-server-protocol/schema/json/v2/DeviceKeyCreateResponse.json @@ -0,0 +1,45 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "definitions": { + "DeviceKeyAlgorithm": { + "description": "Device-key algorithm reported at enrollment and signing boundaries.", + "enum": [ + "ecdsa_p256_sha256" + ], + "type": "string" + }, + "DeviceKeyProtectionClass": { + "description": "Platform protection class for a controller-local device key.", + "enum": [ + "hardware_secure_enclave", + "hardware_tpm", + "os_protected_nonextractable" + ], + "type": "string" + } + }, + "description": "Device-key metadata and public key returned by create/public APIs.", + "properties": { + "algorithm": { + "$ref": "#/definitions/DeviceKeyAlgorithm" + }, + "keyId": { + "type": "string" + }, + "protectionClass": { + "$ref": "#/definitions/DeviceKeyProtectionClass" + }, + "publicKeySpkiDerBase64": { + "description": "SubjectPublicKeyInfo DER encoded as base64.", + "type": "string" + } + }, + "required": [ + "algorithm", + "keyId", + "protectionClass", + "publicKeySpkiDerBase64" + ], + "title": "DeviceKeyCreateResponse", + "type": "object" +} \ No newline at end of file diff --git a/codex-rs/app-server-protocol/schema/json/v2/DeviceKeyPublicParams.json b/codex-rs/app-server-protocol/schema/json/v2/DeviceKeyPublicParams.json new file mode 100644 index 0000000000..37cc5fbe2c --- /dev/null +++ b/codex-rs/app-server-protocol/schema/json/v2/DeviceKeyPublicParams.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Fetch a controller-local device key public key by id.", + "properties": { + "keyId": { + "type": "string" + } + }, + "required": [ + "keyId" + ], + "title": "DeviceKeyPublicParams", + "type": "object" +} \ No newline at end of file diff --git a/codex-rs/app-server-protocol/schema/json/v2/DeviceKeyPublicResponse.json b/codex-rs/app-server-protocol/schema/json/v2/DeviceKeyPublicResponse.json new file mode 100644 index 0000000000..39f98b7623 --- /dev/null +++ b/codex-rs/app-server-protocol/schema/json/v2/DeviceKeyPublicResponse.json @@ -0,0 +1,45 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "definitions": { + "DeviceKeyAlgorithm": { + "description": "Device-key algorithm reported at enrollment and signing boundaries.", + "enum": [ + "ecdsa_p256_sha256" + ], + "type": "string" + }, + "DeviceKeyProtectionClass": { + "description": "Platform protection class for a controller-local device key.", + "enum": [ + "hardware_secure_enclave", + "hardware_tpm", + "os_protected_nonextractable" + ], + "type": "string" + } + }, + "description": "Device-key public metadata returned by `device/key/public`.", + "properties": { + "algorithm": { + "$ref": "#/definitions/DeviceKeyAlgorithm" + }, + "keyId": { + "type": "string" + }, + "protectionClass": { + "$ref": "#/definitions/DeviceKeyProtectionClass" + }, + "publicKeySpkiDerBase64": { + "description": "SubjectPublicKeyInfo DER encoded as base64.", + "type": "string" + } + }, + "required": [ + "algorithm", + "keyId", + "protectionClass", + "publicKeySpkiDerBase64" + ], + "title": "DeviceKeyPublicResponse", + "type": "object" +} \ No newline at end of file diff --git a/codex-rs/app-server-protocol/schema/json/v2/DeviceKeySignParams.json b/codex-rs/app-server-protocol/schema/json/v2/DeviceKeySignParams.json new file mode 100644 index 0000000000..054765b297 --- /dev/null +++ b/codex-rs/app-server-protocol/schema/json/v2/DeviceKeySignParams.json @@ -0,0 +1,165 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "definitions": { + "DeviceKeySignPayload": { + "description": "Structured payloads accepted by `device/key/sign`.", + "oneOf": [ + { + "description": "Payload bound to one remote-control controller websocket `/client` connection challenge.", + "properties": { + "accountUserId": { + "type": "string" + }, + "audience": { + "$ref": "#/definitions/RemoteControlClientConnectionAudience" + }, + "clientId": { + "type": "string" + }, + "nonce": { + "type": "string" + }, + "scopes": { + "description": "Must contain exactly `remote_control_controller_websocket`.", + "items": { + "type": "string" + }, + "type": "array" + }, + "sessionId": { + "description": "Backend-issued websocket session id that this proof authorizes.", + "type": "string" + }, + "targetOrigin": { + "description": "Origin of the backend endpoint that issued the challenge and will verify this proof.", + "type": "string" + }, + "targetPath": { + "description": "Websocket route path that this proof authorizes.", + "type": "string" + }, + "tokenExpiresAt": { + "description": "Remote-control token expiration as Unix seconds.", + "format": "int64", + "type": "integer" + }, + "tokenSha256Base64url": { + "description": "SHA-256 of the controller-scoped remote-control token, encoded as unpadded base64url.", + "type": "string" + }, + "type": { + "enum": [ + "remoteControlClientConnection" + ], + "title": "RemoteControlClientConnectionDeviceKeySignPayloadType", + "type": "string" + } + }, + "required": [ + "accountUserId", + "audience", + "clientId", + "nonce", + "scopes", + "sessionId", + "targetOrigin", + "targetPath", + "tokenExpiresAt", + "tokenSha256Base64url", + "type" + ], + "title": "RemoteControlClientConnectionDeviceKeySignPayload", + "type": "object" + }, + { + "description": "Payload bound to a remote-control client `/client/enroll` ownership challenge.", + "properties": { + "accountUserId": { + "type": "string" + }, + "audience": { + "$ref": "#/definitions/RemoteControlClientEnrollmentAudience" + }, + "challengeExpiresAt": { + "description": "Enrollment challenge expiration as Unix seconds.", + "format": "int64", + "type": "integer" + }, + "challengeId": { + "description": "Backend-issued enrollment challenge id that this proof authorizes.", + "type": "string" + }, + "clientId": { + "type": "string" + }, + "deviceIdentitySha256Base64url": { + "description": "SHA-256 of the requested device identity operation, encoded as unpadded base64url.", + "type": "string" + }, + "nonce": { + "type": "string" + }, + "targetOrigin": { + "description": "Origin of the backend endpoint that issued the challenge and will verify this proof.", + "type": "string" + }, + "targetPath": { + "description": "HTTP route path that this proof authorizes.", + "type": "string" + }, + "type": { + "enum": [ + "remoteControlClientEnrollment" + ], + "title": "RemoteControlClientEnrollmentDeviceKeySignPayloadType", + "type": "string" + } + }, + "required": [ + "accountUserId", + "audience", + "challengeExpiresAt", + "challengeId", + "clientId", + "deviceIdentitySha256Base64url", + "nonce", + "targetOrigin", + "targetPath", + "type" + ], + "title": "RemoteControlClientEnrollmentDeviceKeySignPayload", + "type": "object" + } + ] + }, + "RemoteControlClientConnectionAudience": { + "description": "Audience for a remote-control client connection device-key proof.", + "enum": [ + "remote_control_client_websocket" + ], + "type": "string" + }, + "RemoteControlClientEnrollmentAudience": { + "description": "Audience for a remote-control client enrollment device-key proof.", + "enum": [ + "remote_control_client_enrollment" + ], + "type": "string" + } + }, + "description": "Sign an accepted structured payload with a controller-local device key.", + "properties": { + "keyId": { + "type": "string" + }, + "payload": { + "$ref": "#/definitions/DeviceKeySignPayload" + } + }, + "required": [ + "keyId", + "payload" + ], + "title": "DeviceKeySignParams", + "type": "object" +} \ No newline at end of file diff --git a/codex-rs/app-server-protocol/schema/json/v2/DeviceKeySignResponse.json b/codex-rs/app-server-protocol/schema/json/v2/DeviceKeySignResponse.json new file mode 100644 index 0000000000..83fec90330 --- /dev/null +++ b/codex-rs/app-server-protocol/schema/json/v2/DeviceKeySignResponse.json @@ -0,0 +1,33 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "definitions": { + "DeviceKeyAlgorithm": { + "description": "Device-key algorithm reported at enrollment and signing boundaries.", + "enum": [ + "ecdsa_p256_sha256" + ], + "type": "string" + } + }, + "description": "ASN.1 DER signature returned by `device/key/sign`.", + "properties": { + "algorithm": { + "$ref": "#/definitions/DeviceKeyAlgorithm" + }, + "signatureDerBase64": { + "description": "ECDSA signature DER encoded as base64.", + "type": "string" + }, + "signedPayloadBase64": { + "description": "Exact bytes signed by the device key, encoded as base64. Verifiers must verify this byte string directly and must not reserialize `payload`.", + "type": "string" + } + }, + "required": [ + "algorithm", + "signatureDerBase64", + "signedPayloadBase64" + ], + "title": "DeviceKeySignResponse", + "type": "object" +} \ No newline at end of file diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadForkParams.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadForkParams.json index a8fa95e2e9..38201f3a3d 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadForkParams.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadForkParams.json @@ -1,6 +1,21 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "definitions": { + "AbsolutePathBuf": { + "description": "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.", + "type": "string" + }, + "AdditionalNetworkPermissions": { + "properties": { + "enabled": { + "type": [ + "boolean", + "null" + ] + } + }, + "type": "object" + }, "ApprovalsReviewer": { "description": "Configures who approval requests are routed to for review. Examples include sandbox escapes, blocked network access, MCP approval prompts, and ARC escalations. Defaults to `user`. `guardian_subagent` uses a carefully prompted subagent to gather relevant context and apply a risk-based decision framework before approving or denying the request.", "enum": [ @@ -59,6 +74,264 @@ } ] }, + "FileSystemAccessMode": { + "enum": [ + "read", + "write", + "none" + ], + "type": "string" + }, + "FileSystemPath": { + "oneOf": [ + { + "properties": { + "path": { + "$ref": "#/definitions/AbsolutePathBuf" + }, + "type": { + "enum": [ + "path" + ], + "title": "PathFileSystemPathType", + "type": "string" + } + }, + "required": [ + "path", + "type" + ], + "title": "PathFileSystemPath", + "type": "object" + }, + { + "properties": { + "pattern": { + "type": "string" + }, + "type": { + "enum": [ + "glob_pattern" + ], + "title": "GlobPatternFileSystemPathType", + "type": "string" + } + }, + "required": [ + "pattern", + "type" + ], + "title": "GlobPatternFileSystemPath", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "special" + ], + "title": "SpecialFileSystemPathType", + "type": "string" + }, + "value": { + "$ref": "#/definitions/FileSystemSpecialPath" + } + }, + "required": [ + "type", + "value" + ], + "title": "SpecialFileSystemPath", + "type": "object" + } + ] + }, + "FileSystemSandboxEntry": { + "properties": { + "access": { + "$ref": "#/definitions/FileSystemAccessMode" + }, + "path": { + "$ref": "#/definitions/FileSystemPath" + } + }, + "required": [ + "access", + "path" + ], + "type": "object" + }, + "FileSystemSpecialPath": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "root" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "RootFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "minimal" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "MinimalFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "current_working_directory" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "CurrentWorkingDirectoryFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "project_roots" + ], + "type": "string" + }, + "subpath": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "kind" + ], + "title": "KindFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "tmpdir" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "TmpdirFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "slash_tmp" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "SlashTmpFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "unknown" + ], + "type": "string" + }, + "path": { + "type": "string" + }, + "subpath": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "kind", + "path" + ], + "type": "object" + } + ] + }, + "PermissionProfile": { + "properties": { + "fileSystem": { + "anyOf": [ + { + "$ref": "#/definitions/PermissionProfileFileSystemPermissions" + }, + { + "type": "null" + } + ] + }, + "network": { + "anyOf": [ + { + "$ref": "#/definitions/AdditionalNetworkPermissions" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" + }, + "PermissionProfileFileSystemPermissions": { + "properties": { + "entries": { + "items": { + "$ref": "#/definitions/FileSystemSandboxEntry" + }, + "type": "array" + }, + "globScanMaxDepth": { + "format": "uint", + "minimum": 1.0, + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "entries" + ], + "type": "object" + }, "SandboxMode": { "enum": [ "read-only", @@ -139,6 +412,17 @@ "null" ] }, + "permissionProfile": { + "anyOf": [ + { + "$ref": "#/definitions/PermissionProfile" + }, + { + "type": "null" + } + ], + "description": "Full permissions override for the forked thread. Cannot be combined with `sandbox`." + }, "sandbox": { "anyOf": [ { diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadForkResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadForkResponse.json index a01f7bee71..b79f7ffea8 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadForkResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadForkResponse.json @@ -5,6 +5,17 @@ "description": "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.", "type": "string" }, + "AdditionalNetworkPermissions": { + "properties": { + "enabled": { + "type": [ + "boolean", + "null" + ] + } + }, + "type": "object" + }, "AgentPath": { "type": "string" }, @@ -448,6 +459,217 @@ ], "type": "string" }, + "FileSystemAccessMode": { + "enum": [ + "read", + "write", + "none" + ], + "type": "string" + }, + "FileSystemPath": { + "oneOf": [ + { + "properties": { + "path": { + "$ref": "#/definitions/AbsolutePathBuf" + }, + "type": { + "enum": [ + "path" + ], + "title": "PathFileSystemPathType", + "type": "string" + } + }, + "required": [ + "path", + "type" + ], + "title": "PathFileSystemPath", + "type": "object" + }, + { + "properties": { + "pattern": { + "type": "string" + }, + "type": { + "enum": [ + "glob_pattern" + ], + "title": "GlobPatternFileSystemPathType", + "type": "string" + } + }, + "required": [ + "pattern", + "type" + ], + "title": "GlobPatternFileSystemPath", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "special" + ], + "title": "SpecialFileSystemPathType", + "type": "string" + }, + "value": { + "$ref": "#/definitions/FileSystemSpecialPath" + } + }, + "required": [ + "type", + "value" + ], + "title": "SpecialFileSystemPath", + "type": "object" + } + ] + }, + "FileSystemSandboxEntry": { + "properties": { + "access": { + "$ref": "#/definitions/FileSystemAccessMode" + }, + "path": { + "$ref": "#/definitions/FileSystemPath" + } + }, + "required": [ + "access", + "path" + ], + "type": "object" + }, + "FileSystemSpecialPath": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "root" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "RootFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "minimal" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "MinimalFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "current_working_directory" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "CurrentWorkingDirectoryFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "project_roots" + ], + "type": "string" + }, + "subpath": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "kind" + ], + "title": "KindFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "tmpdir" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "TmpdirFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "slash_tmp" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "SlashTmpFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "unknown" + ], + "type": "string" + }, + "path": { + "type": "string" + }, + "subpath": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "kind", + "path" + ], + "type": "object" + } + ] + }, "FileUpdateChange": { "properties": { "diff": { @@ -686,6 +908,53 @@ } ] }, + "PermissionProfile": { + "properties": { + "fileSystem": { + "anyOf": [ + { + "$ref": "#/definitions/PermissionProfileFileSystemPermissions" + }, + { + "type": "null" + } + ] + }, + "network": { + "anyOf": [ + { + "$ref": "#/definitions/AdditionalNetworkPermissions" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" + }, + "PermissionProfileFileSystemPermissions": { + "properties": { + "entries": { + "items": { + "$ref": "#/definitions/FileSystemSandboxEntry" + }, + "type": "array" + }, + "globScanMaxDepth": { + "format": "uint", + "minimum": 1.0, + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "entries" + ], + "type": "object" + }, "ReadOnlyAccess": { "oneOf": [ { @@ -2225,6 +2494,9 @@ "modelProvider": { "type": "string" }, + "permissionProfile": { + "$ref": "#/definitions/PermissionProfile" + }, "reasoningEffort": { "anyOf": [ { @@ -2258,6 +2530,7 @@ "cwd", "model", "modelProvider", + "permissionProfile", "sandbox", "thread" ], diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeParams.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeParams.json index 35a9e5b2a8..e71155242c 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeParams.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeParams.json @@ -1,6 +1,21 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "definitions": { + "AbsolutePathBuf": { + "description": "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.", + "type": "string" + }, + "AdditionalNetworkPermissions": { + "properties": { + "enabled": { + "type": [ + "boolean", + "null" + ] + } + }, + "type": "object" + }, "ApprovalsReviewer": { "description": "Configures who approval requests are routed to for review. Examples include sandbox escapes, blocked network access, MCP approval prompts, and ARC escalations. Defaults to `user`. `guardian_subagent` uses a carefully prompted subagent to gather relevant context and apply a risk-based decision framework before approving or denying the request.", "enum": [ @@ -133,6 +148,217 @@ } ] }, + "FileSystemAccessMode": { + "enum": [ + "read", + "write", + "none" + ], + "type": "string" + }, + "FileSystemPath": { + "oneOf": [ + { + "properties": { + "path": { + "$ref": "#/definitions/AbsolutePathBuf" + }, + "type": { + "enum": [ + "path" + ], + "title": "PathFileSystemPathType", + "type": "string" + } + }, + "required": [ + "path", + "type" + ], + "title": "PathFileSystemPath", + "type": "object" + }, + { + "properties": { + "pattern": { + "type": "string" + }, + "type": { + "enum": [ + "glob_pattern" + ], + "title": "GlobPatternFileSystemPathType", + "type": "string" + } + }, + "required": [ + "pattern", + "type" + ], + "title": "GlobPatternFileSystemPath", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "special" + ], + "title": "SpecialFileSystemPathType", + "type": "string" + }, + "value": { + "$ref": "#/definitions/FileSystemSpecialPath" + } + }, + "required": [ + "type", + "value" + ], + "title": "SpecialFileSystemPath", + "type": "object" + } + ] + }, + "FileSystemSandboxEntry": { + "properties": { + "access": { + "$ref": "#/definitions/FileSystemAccessMode" + }, + "path": { + "$ref": "#/definitions/FileSystemPath" + } + }, + "required": [ + "access", + "path" + ], + "type": "object" + }, + "FileSystemSpecialPath": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "root" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "RootFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "minimal" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "MinimalFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "current_working_directory" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "CurrentWorkingDirectoryFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "project_roots" + ], + "type": "string" + }, + "subpath": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "kind" + ], + "title": "KindFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "tmpdir" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "TmpdirFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "slash_tmp" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "SlashTmpFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "unknown" + ], + "type": "string" + }, + "path": { + "type": "string" + }, + "subpath": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "kind", + "path" + ], + "type": "object" + } + ] + }, "FunctionCallOutputBody": { "anyOf": [ { @@ -325,6 +551,53 @@ } ] }, + "PermissionProfile": { + "properties": { + "fileSystem": { + "anyOf": [ + { + "$ref": "#/definitions/PermissionProfileFileSystemPermissions" + }, + { + "type": "null" + } + ] + }, + "network": { + "anyOf": [ + { + "$ref": "#/definitions/AdditionalNetworkPermissions" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" + }, + "PermissionProfileFileSystemPermissions": { + "properties": { + "entries": { + "items": { + "$ref": "#/definitions/FileSystemSandboxEntry" + }, + "type": "array" + }, + "globScanMaxDepth": { + "format": "uint", + "minimum": 1.0, + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "entries" + ], + "type": "object" + }, "Personality": { "enum": [ "none", @@ -1052,6 +1325,17 @@ "null" ] }, + "permissionProfile": { + "anyOf": [ + { + "$ref": "#/definitions/PermissionProfile" + }, + { + "type": "null" + } + ], + "description": "Full permissions override for the resumed thread. Cannot be combined with `sandbox`." + }, "personality": { "anyOf": [ { diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeResponse.json index 6d504c6004..e274c10dec 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeResponse.json @@ -5,6 +5,17 @@ "description": "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.", "type": "string" }, + "AdditionalNetworkPermissions": { + "properties": { + "enabled": { + "type": [ + "boolean", + "null" + ] + } + }, + "type": "object" + }, "AgentPath": { "type": "string" }, @@ -448,6 +459,217 @@ ], "type": "string" }, + "FileSystemAccessMode": { + "enum": [ + "read", + "write", + "none" + ], + "type": "string" + }, + "FileSystemPath": { + "oneOf": [ + { + "properties": { + "path": { + "$ref": "#/definitions/AbsolutePathBuf" + }, + "type": { + "enum": [ + "path" + ], + "title": "PathFileSystemPathType", + "type": "string" + } + }, + "required": [ + "path", + "type" + ], + "title": "PathFileSystemPath", + "type": "object" + }, + { + "properties": { + "pattern": { + "type": "string" + }, + "type": { + "enum": [ + "glob_pattern" + ], + "title": "GlobPatternFileSystemPathType", + "type": "string" + } + }, + "required": [ + "pattern", + "type" + ], + "title": "GlobPatternFileSystemPath", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "special" + ], + "title": "SpecialFileSystemPathType", + "type": "string" + }, + "value": { + "$ref": "#/definitions/FileSystemSpecialPath" + } + }, + "required": [ + "type", + "value" + ], + "title": "SpecialFileSystemPath", + "type": "object" + } + ] + }, + "FileSystemSandboxEntry": { + "properties": { + "access": { + "$ref": "#/definitions/FileSystemAccessMode" + }, + "path": { + "$ref": "#/definitions/FileSystemPath" + } + }, + "required": [ + "access", + "path" + ], + "type": "object" + }, + "FileSystemSpecialPath": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "root" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "RootFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "minimal" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "MinimalFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "current_working_directory" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "CurrentWorkingDirectoryFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "project_roots" + ], + "type": "string" + }, + "subpath": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "kind" + ], + "title": "KindFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "tmpdir" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "TmpdirFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "slash_tmp" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "SlashTmpFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "unknown" + ], + "type": "string" + }, + "path": { + "type": "string" + }, + "subpath": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "kind", + "path" + ], + "type": "object" + } + ] + }, "FileUpdateChange": { "properties": { "diff": { @@ -686,6 +908,53 @@ } ] }, + "PermissionProfile": { + "properties": { + "fileSystem": { + "anyOf": [ + { + "$ref": "#/definitions/PermissionProfileFileSystemPermissions" + }, + { + "type": "null" + } + ] + }, + "network": { + "anyOf": [ + { + "$ref": "#/definitions/AdditionalNetworkPermissions" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" + }, + "PermissionProfileFileSystemPermissions": { + "properties": { + "entries": { + "items": { + "$ref": "#/definitions/FileSystemSandboxEntry" + }, + "type": "array" + }, + "globScanMaxDepth": { + "format": "uint", + "minimum": 1.0, + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "entries" + ], + "type": "object" + }, "ReadOnlyAccess": { "oneOf": [ { @@ -2225,6 +2494,9 @@ "modelProvider": { "type": "string" }, + "permissionProfile": { + "$ref": "#/definitions/PermissionProfile" + }, "reasoningEffort": { "anyOf": [ { @@ -2258,6 +2530,7 @@ "cwd", "model", "modelProvider", + "permissionProfile", "sandbox", "thread" ], diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadStartParams.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadStartParams.json index 9b1cba6d1a..27c8b40fc5 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadStartParams.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadStartParams.json @@ -1,6 +1,21 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "definitions": { + "AbsolutePathBuf": { + "description": "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.", + "type": "string" + }, + "AdditionalNetworkPermissions": { + "properties": { + "enabled": { + "type": [ + "boolean", + "null" + ] + } + }, + "type": "object" + }, "ApprovalsReviewer": { "description": "Configures who approval requests are routed to for review. Examples include sandbox escapes, blocked network access, MCP approval prompts, and ARC escalations. Defaults to `user`. `guardian_subagent` uses a carefully prompted subagent to gather relevant context and apply a risk-based decision framework before approving or denying the request.", "enum": [ @@ -85,6 +100,264 @@ ], "type": "object" }, + "FileSystemAccessMode": { + "enum": [ + "read", + "write", + "none" + ], + "type": "string" + }, + "FileSystemPath": { + "oneOf": [ + { + "properties": { + "path": { + "$ref": "#/definitions/AbsolutePathBuf" + }, + "type": { + "enum": [ + "path" + ], + "title": "PathFileSystemPathType", + "type": "string" + } + }, + "required": [ + "path", + "type" + ], + "title": "PathFileSystemPath", + "type": "object" + }, + { + "properties": { + "pattern": { + "type": "string" + }, + "type": { + "enum": [ + "glob_pattern" + ], + "title": "GlobPatternFileSystemPathType", + "type": "string" + } + }, + "required": [ + "pattern", + "type" + ], + "title": "GlobPatternFileSystemPath", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "special" + ], + "title": "SpecialFileSystemPathType", + "type": "string" + }, + "value": { + "$ref": "#/definitions/FileSystemSpecialPath" + } + }, + "required": [ + "type", + "value" + ], + "title": "SpecialFileSystemPath", + "type": "object" + } + ] + }, + "FileSystemSandboxEntry": { + "properties": { + "access": { + "$ref": "#/definitions/FileSystemAccessMode" + }, + "path": { + "$ref": "#/definitions/FileSystemPath" + } + }, + "required": [ + "access", + "path" + ], + "type": "object" + }, + "FileSystemSpecialPath": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "root" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "RootFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "minimal" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "MinimalFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "current_working_directory" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "CurrentWorkingDirectoryFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "project_roots" + ], + "type": "string" + }, + "subpath": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "kind" + ], + "title": "KindFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "tmpdir" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "TmpdirFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "slash_tmp" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "SlashTmpFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "unknown" + ], + "type": "string" + }, + "path": { + "type": "string" + }, + "subpath": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "kind", + "path" + ], + "type": "object" + } + ] + }, + "PermissionProfile": { + "properties": { + "fileSystem": { + "anyOf": [ + { + "$ref": "#/definitions/PermissionProfileFileSystemPermissions" + }, + { + "type": "null" + } + ] + }, + "network": { + "anyOf": [ + { + "$ref": "#/definitions/AdditionalNetworkPermissions" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" + }, + "PermissionProfileFileSystemPermissions": { + "properties": { + "entries": { + "items": { + "$ref": "#/definitions/FileSystemSandboxEntry" + }, + "type": "array" + }, + "globScanMaxDepth": { + "format": "uint", + "minimum": 1.0, + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "entries" + ], + "type": "object" + }, "Personality": { "enum": [ "none", @@ -181,6 +454,17 @@ "null" ] }, + "permissionProfile": { + "anyOf": [ + { + "$ref": "#/definitions/PermissionProfile" + }, + { + "type": "null" + } + ], + "description": "Full permissions override for this thread. Cannot be combined with `sandbox`." + }, "personality": { "anyOf": [ { diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadStartResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadStartResponse.json index 0d0ff5d9dc..7518dea3da 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadStartResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadStartResponse.json @@ -5,6 +5,17 @@ "description": "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.", "type": "string" }, + "AdditionalNetworkPermissions": { + "properties": { + "enabled": { + "type": [ + "boolean", + "null" + ] + } + }, + "type": "object" + }, "AgentPath": { "type": "string" }, @@ -448,6 +459,217 @@ ], "type": "string" }, + "FileSystemAccessMode": { + "enum": [ + "read", + "write", + "none" + ], + "type": "string" + }, + "FileSystemPath": { + "oneOf": [ + { + "properties": { + "path": { + "$ref": "#/definitions/AbsolutePathBuf" + }, + "type": { + "enum": [ + "path" + ], + "title": "PathFileSystemPathType", + "type": "string" + } + }, + "required": [ + "path", + "type" + ], + "title": "PathFileSystemPath", + "type": "object" + }, + { + "properties": { + "pattern": { + "type": "string" + }, + "type": { + "enum": [ + "glob_pattern" + ], + "title": "GlobPatternFileSystemPathType", + "type": "string" + } + }, + "required": [ + "pattern", + "type" + ], + "title": "GlobPatternFileSystemPath", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "special" + ], + "title": "SpecialFileSystemPathType", + "type": "string" + }, + "value": { + "$ref": "#/definitions/FileSystemSpecialPath" + } + }, + "required": [ + "type", + "value" + ], + "title": "SpecialFileSystemPath", + "type": "object" + } + ] + }, + "FileSystemSandboxEntry": { + "properties": { + "access": { + "$ref": "#/definitions/FileSystemAccessMode" + }, + "path": { + "$ref": "#/definitions/FileSystemPath" + } + }, + "required": [ + "access", + "path" + ], + "type": "object" + }, + "FileSystemSpecialPath": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "root" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "RootFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "minimal" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "MinimalFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "current_working_directory" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "CurrentWorkingDirectoryFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "project_roots" + ], + "type": "string" + }, + "subpath": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "kind" + ], + "title": "KindFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "tmpdir" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "TmpdirFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "slash_tmp" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "SlashTmpFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "unknown" + ], + "type": "string" + }, + "path": { + "type": "string" + }, + "subpath": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "kind", + "path" + ], + "type": "object" + } + ] + }, "FileUpdateChange": { "properties": { "diff": { @@ -686,6 +908,53 @@ } ] }, + "PermissionProfile": { + "properties": { + "fileSystem": { + "anyOf": [ + { + "$ref": "#/definitions/PermissionProfileFileSystemPermissions" + }, + { + "type": "null" + } + ] + }, + "network": { + "anyOf": [ + { + "$ref": "#/definitions/AdditionalNetworkPermissions" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" + }, + "PermissionProfileFileSystemPermissions": { + "properties": { + "entries": { + "items": { + "$ref": "#/definitions/FileSystemSandboxEntry" + }, + "type": "array" + }, + "globScanMaxDepth": { + "format": "uint", + "minimum": 1.0, + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "entries" + ], + "type": "object" + }, "ReadOnlyAccess": { "oneOf": [ { @@ -2225,6 +2494,9 @@ "modelProvider": { "type": "string" }, + "permissionProfile": { + "$ref": "#/definitions/PermissionProfile" + }, "reasoningEffort": { "anyOf": [ { @@ -2258,6 +2530,7 @@ "cwd", "model", "modelProvider", + "permissionProfile", "sandbox", "thread" ], diff --git a/codex-rs/app-server-protocol/schema/json/v2/TurnStartParams.json b/codex-rs/app-server-protocol/schema/json/v2/TurnStartParams.json index cad1d8b5bc..e9481f18d9 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/TurnStartParams.json +++ b/codex-rs/app-server-protocol/schema/json/v2/TurnStartParams.json @@ -5,6 +5,17 @@ "description": "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.", "type": "string" }, + "AdditionalNetworkPermissions": { + "properties": { + "enabled": { + "type": [ + "boolean", + "null" + ] + } + }, + "type": "object" + }, "ApprovalsReviewer": { "description": "Configures who approval requests are routed to for review. Examples include sandbox escapes, blocked network access, MCP approval prompts, and ARC escalations. Defaults to `user`. `guardian_subagent` uses a carefully prompted subagent to gather relevant context and apply a risk-based decision framework before approving or denying the request.", "enum": [ @@ -98,6 +109,217 @@ ], "type": "object" }, + "FileSystemAccessMode": { + "enum": [ + "read", + "write", + "none" + ], + "type": "string" + }, + "FileSystemPath": { + "oneOf": [ + { + "properties": { + "path": { + "$ref": "#/definitions/AbsolutePathBuf" + }, + "type": { + "enum": [ + "path" + ], + "title": "PathFileSystemPathType", + "type": "string" + } + }, + "required": [ + "path", + "type" + ], + "title": "PathFileSystemPath", + "type": "object" + }, + { + "properties": { + "pattern": { + "type": "string" + }, + "type": { + "enum": [ + "glob_pattern" + ], + "title": "GlobPatternFileSystemPathType", + "type": "string" + } + }, + "required": [ + "pattern", + "type" + ], + "title": "GlobPatternFileSystemPath", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "special" + ], + "title": "SpecialFileSystemPathType", + "type": "string" + }, + "value": { + "$ref": "#/definitions/FileSystemSpecialPath" + } + }, + "required": [ + "type", + "value" + ], + "title": "SpecialFileSystemPath", + "type": "object" + } + ] + }, + "FileSystemSandboxEntry": { + "properties": { + "access": { + "$ref": "#/definitions/FileSystemAccessMode" + }, + "path": { + "$ref": "#/definitions/FileSystemPath" + } + }, + "required": [ + "access", + "path" + ], + "type": "object" + }, + "FileSystemSpecialPath": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "root" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "RootFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "minimal" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "MinimalFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "current_working_directory" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "CurrentWorkingDirectoryFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "project_roots" + ], + "type": "string" + }, + "subpath": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "kind" + ], + "title": "KindFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "tmpdir" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "TmpdirFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "slash_tmp" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "SlashTmpFileSystemSpecialPath", + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "unknown" + ], + "type": "string" + }, + "path": { + "type": "string" + }, + "subpath": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "kind", + "path" + ], + "type": "object" + } + ] + }, "ModeKind": { "description": "Initial collaboration mode to use when the TUI starts.", "enum": [ @@ -113,6 +335,53 @@ ], "type": "string" }, + "PermissionProfile": { + "properties": { + "fileSystem": { + "anyOf": [ + { + "$ref": "#/definitions/PermissionProfileFileSystemPermissions" + }, + { + "type": "null" + } + ] + }, + "network": { + "anyOf": [ + { + "$ref": "#/definitions/AdditionalNetworkPermissions" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" + }, + "PermissionProfileFileSystemPermissions": { + "properties": { + "entries": { + "items": { + "$ref": "#/definitions/FileSystemSandboxEntry" + }, + "type": "array" + }, + "globScanMaxDepth": { + "format": "uint", + "minimum": 1.0, + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "entries" + ], + "type": "object" + }, "Personality": { "enum": [ "none", @@ -555,6 +824,17 @@ "outputSchema": { "description": "Optional JSON Schema used to constrain the final assistant message for this turn." }, + "permissionProfile": { + "anyOf": [ + { + "$ref": "#/definitions/PermissionProfile" + }, + { + "type": "null" + } + ], + "description": "Override the full permissions profile for this turn and subsequent turns. Cannot be combined with `sandboxPolicy`." + }, "personality": { "anyOf": [ { diff --git a/codex-rs/app-server-protocol/schema/typescript/ClientRequest.ts b/codex-rs/app-server-protocol/schema/typescript/ClientRequest.ts index c26ff9161f..fdb934ed53 100644 --- a/codex-rs/app-server-protocol/schema/typescript/ClientRequest.ts +++ b/codex-rs/app-server-protocol/schema/typescript/ClientRequest.ts @@ -16,6 +16,9 @@ import type { CommandExecWriteParams } from "./v2/CommandExecWriteParams"; import type { ConfigBatchWriteParams } from "./v2/ConfigBatchWriteParams"; import type { ConfigReadParams } from "./v2/ConfigReadParams"; import type { ConfigValueWriteParams } from "./v2/ConfigValueWriteParams"; +import type { DeviceKeyCreateParams } from "./v2/DeviceKeyCreateParams"; +import type { DeviceKeyPublicParams } from "./v2/DeviceKeyPublicParams"; +import type { DeviceKeySignParams } from "./v2/DeviceKeySignParams"; import type { ExperimentalFeatureEnablementSetParams } from "./v2/ExperimentalFeatureEnablementSetParams"; import type { ExperimentalFeatureListParams } from "./v2/ExperimentalFeatureListParams"; import type { ExternalAgentConfigDetectParams } from "./v2/ExternalAgentConfigDetectParams"; @@ -71,4 +74,4 @@ import type { WindowsSandboxSetupStartParams } from "./v2/WindowsSandboxSetupSta /** * Request from the client to the server. */ -export type ClientRequest ={ "method": "initialize", id: RequestId, params: InitializeParams, } | { "method": "thread/start", id: RequestId, params: ThreadStartParams, } | { "method": "thread/resume", id: RequestId, params: ThreadResumeParams, } | { "method": "thread/fork", id: RequestId, params: ThreadForkParams, } | { "method": "thread/archive", id: RequestId, params: ThreadArchiveParams, } | { "method": "thread/unsubscribe", id: RequestId, params: ThreadUnsubscribeParams, } | { "method": "thread/name/set", id: RequestId, params: ThreadSetNameParams, } | { "method": "thread/metadata/update", id: RequestId, params: ThreadMetadataUpdateParams, } | { "method": "thread/unarchive", id: RequestId, params: ThreadUnarchiveParams, } | { "method": "thread/compact/start", id: RequestId, params: ThreadCompactStartParams, } | { "method": "thread/shellCommand", id: RequestId, params: ThreadShellCommandParams, } | { "method": "thread/rollback", id: RequestId, params: ThreadRollbackParams, } | { "method": "thread/list", id: RequestId, params: ThreadListParams, } | { "method": "thread/loaded/list", id: RequestId, params: ThreadLoadedListParams, } | { "method": "thread/read", id: RequestId, params: ThreadReadParams, } | { "method": "thread/turns/list", id: RequestId, params: ThreadTurnsListParams, } | { "method": "thread/inject_items", id: RequestId, params: ThreadInjectItemsParams, } | { "method": "skills/list", id: RequestId, params: SkillsListParams, } | { "method": "marketplace/add", id: RequestId, params: MarketplaceAddParams, } | { "method": "marketplace/remove", id: RequestId, params: MarketplaceRemoveParams, } | { "method": "plugin/list", id: RequestId, params: PluginListParams, } | { "method": "plugin/read", id: RequestId, params: PluginReadParams, } | { "method": "app/list", id: RequestId, params: AppsListParams, } | { "method": "fs/readFile", id: RequestId, params: FsReadFileParams, } | { "method": "fs/writeFile", id: RequestId, params: FsWriteFileParams, } | { "method": "fs/createDirectory", id: RequestId, params: FsCreateDirectoryParams, } | { "method": "fs/getMetadata", id: RequestId, params: FsGetMetadataParams, } | { "method": "fs/readDirectory", id: RequestId, params: FsReadDirectoryParams, } | { "method": "fs/remove", id: RequestId, params: FsRemoveParams, } | { "method": "fs/copy", id: RequestId, params: FsCopyParams, } | { "method": "fs/watch", id: RequestId, params: FsWatchParams, } | { "method": "fs/unwatch", id: RequestId, params: FsUnwatchParams, } | { "method": "skills/config/write", id: RequestId, params: SkillsConfigWriteParams, } | { "method": "plugin/install", id: RequestId, params: PluginInstallParams, } | { "method": "plugin/uninstall", id: RequestId, params: PluginUninstallParams, } | { "method": "turn/start", id: RequestId, params: TurnStartParams, } | { "method": "turn/steer", id: RequestId, params: TurnSteerParams, } | { "method": "turn/interrupt", id: RequestId, params: TurnInterruptParams, } | { "method": "review/start", id: RequestId, params: ReviewStartParams, } | { "method": "model/list", id: RequestId, params: ModelListParams, } | { "method": "experimentalFeature/list", id: RequestId, params: ExperimentalFeatureListParams, } | { "method": "experimentalFeature/enablement/set", id: RequestId, params: ExperimentalFeatureEnablementSetParams, } | { "method": "mcpServer/oauth/login", id: RequestId, params: McpServerOauthLoginParams, } | { "method": "config/mcpServer/reload", id: RequestId, params: undefined, } | { "method": "mcpServerStatus/list", id: RequestId, params: ListMcpServerStatusParams, } | { "method": "mcpServer/resource/read", id: RequestId, params: McpResourceReadParams, } | { "method": "mcpServer/tool/call", id: RequestId, params: McpServerToolCallParams, } | { "method": "windowsSandbox/setupStart", id: RequestId, params: WindowsSandboxSetupStartParams, } | { "method": "account/login/start", id: RequestId, params: LoginAccountParams, } | { "method": "account/login/cancel", id: RequestId, params: CancelLoginAccountParams, } | { "method": "account/logout", id: RequestId, params: undefined, } | { "method": "account/rateLimits/read", id: RequestId, params: undefined, } | { "method": "account/sendAddCreditsNudgeEmail", id: RequestId, params: SendAddCreditsNudgeEmailParams, } | { "method": "feedback/upload", id: RequestId, params: FeedbackUploadParams, } | { "method": "command/exec", id: RequestId, params: CommandExecParams, } | { "method": "command/exec/write", id: RequestId, params: CommandExecWriteParams, } | { "method": "command/exec/terminate", id: RequestId, params: CommandExecTerminateParams, } | { "method": "command/exec/resize", id: RequestId, params: CommandExecResizeParams, } | { "method": "config/read", id: RequestId, params: ConfigReadParams, } | { "method": "externalAgentConfig/detect", id: RequestId, params: ExternalAgentConfigDetectParams, } | { "method": "externalAgentConfig/import", id: RequestId, params: ExternalAgentConfigImportParams, } | { "method": "config/value/write", id: RequestId, params: ConfigValueWriteParams, } | { "method": "config/batchWrite", id: RequestId, params: ConfigBatchWriteParams, } | { "method": "configRequirements/read", id: RequestId, params: undefined, } | { "method": "account/read", id: RequestId, params: GetAccountParams, } | { "method": "getConversationSummary", id: RequestId, params: GetConversationSummaryParams, } | { "method": "gitDiffToRemote", id: RequestId, params: GitDiffToRemoteParams, } | { "method": "getAuthStatus", id: RequestId, params: GetAuthStatusParams, } | { "method": "fuzzyFileSearch", id: RequestId, params: FuzzyFileSearchParams, }; +export type ClientRequest ={ "method": "initialize", id: RequestId, params: InitializeParams, } | { "method": "thread/start", id: RequestId, params: ThreadStartParams, } | { "method": "thread/resume", id: RequestId, params: ThreadResumeParams, } | { "method": "thread/fork", id: RequestId, params: ThreadForkParams, } | { "method": "thread/archive", id: RequestId, params: ThreadArchiveParams, } | { "method": "thread/unsubscribe", id: RequestId, params: ThreadUnsubscribeParams, } | { "method": "thread/name/set", id: RequestId, params: ThreadSetNameParams, } | { "method": "thread/metadata/update", id: RequestId, params: ThreadMetadataUpdateParams, } | { "method": "thread/unarchive", id: RequestId, params: ThreadUnarchiveParams, } | { "method": "thread/compact/start", id: RequestId, params: ThreadCompactStartParams, } | { "method": "thread/shellCommand", id: RequestId, params: ThreadShellCommandParams, } | { "method": "thread/rollback", id: RequestId, params: ThreadRollbackParams, } | { "method": "thread/list", id: RequestId, params: ThreadListParams, } | { "method": "thread/loaded/list", id: RequestId, params: ThreadLoadedListParams, } | { "method": "thread/read", id: RequestId, params: ThreadReadParams, } | { "method": "thread/turns/list", id: RequestId, params: ThreadTurnsListParams, } | { "method": "thread/inject_items", id: RequestId, params: ThreadInjectItemsParams, } | { "method": "skills/list", id: RequestId, params: SkillsListParams, } | { "method": "marketplace/add", id: RequestId, params: MarketplaceAddParams, } | { "method": "marketplace/remove", id: RequestId, params: MarketplaceRemoveParams, } | { "method": "plugin/list", id: RequestId, params: PluginListParams, } | { "method": "plugin/read", id: RequestId, params: PluginReadParams, } | { "method": "app/list", id: RequestId, params: AppsListParams, } | { "method": "device/key/create", id: RequestId, params: DeviceKeyCreateParams, } | { "method": "device/key/public", id: RequestId, params: DeviceKeyPublicParams, } | { "method": "device/key/sign", id: RequestId, params: DeviceKeySignParams, } | { "method": "fs/readFile", id: RequestId, params: FsReadFileParams, } | { "method": "fs/writeFile", id: RequestId, params: FsWriteFileParams, } | { "method": "fs/createDirectory", id: RequestId, params: FsCreateDirectoryParams, } | { "method": "fs/getMetadata", id: RequestId, params: FsGetMetadataParams, } | { "method": "fs/readDirectory", id: RequestId, params: FsReadDirectoryParams, } | { "method": "fs/remove", id: RequestId, params: FsRemoveParams, } | { "method": "fs/copy", id: RequestId, params: FsCopyParams, } | { "method": "fs/watch", id: RequestId, params: FsWatchParams, } | { "method": "fs/unwatch", id: RequestId, params: FsUnwatchParams, } | { "method": "skills/config/write", id: RequestId, params: SkillsConfigWriteParams, } | { "method": "plugin/install", id: RequestId, params: PluginInstallParams, } | { "method": "plugin/uninstall", id: RequestId, params: PluginUninstallParams, } | { "method": "turn/start", id: RequestId, params: TurnStartParams, } | { "method": "turn/steer", id: RequestId, params: TurnSteerParams, } | { "method": "turn/interrupt", id: RequestId, params: TurnInterruptParams, } | { "method": "review/start", id: RequestId, params: ReviewStartParams, } | { "method": "model/list", id: RequestId, params: ModelListParams, } | { "method": "experimentalFeature/list", id: RequestId, params: ExperimentalFeatureListParams, } | { "method": "experimentalFeature/enablement/set", id: RequestId, params: ExperimentalFeatureEnablementSetParams, } | { "method": "mcpServer/oauth/login", id: RequestId, params: McpServerOauthLoginParams, } | { "method": "config/mcpServer/reload", id: RequestId, params: undefined, } | { "method": "mcpServerStatus/list", id: RequestId, params: ListMcpServerStatusParams, } | { "method": "mcpServer/resource/read", id: RequestId, params: McpResourceReadParams, } | { "method": "mcpServer/tool/call", id: RequestId, params: McpServerToolCallParams, } | { "method": "windowsSandbox/setupStart", id: RequestId, params: WindowsSandboxSetupStartParams, } | { "method": "account/login/start", id: RequestId, params: LoginAccountParams, } | { "method": "account/login/cancel", id: RequestId, params: CancelLoginAccountParams, } | { "method": "account/logout", id: RequestId, params: undefined, } | { "method": "account/rateLimits/read", id: RequestId, params: undefined, } | { "method": "account/sendAddCreditsNudgeEmail", id: RequestId, params: SendAddCreditsNudgeEmailParams, } | { "method": "feedback/upload", id: RequestId, params: FeedbackUploadParams, } | { "method": "command/exec", id: RequestId, params: CommandExecParams, } | { "method": "command/exec/write", id: RequestId, params: CommandExecWriteParams, } | { "method": "command/exec/terminate", id: RequestId, params: CommandExecTerminateParams, } | { "method": "command/exec/resize", id: RequestId, params: CommandExecResizeParams, } | { "method": "config/read", id: RequestId, params: ConfigReadParams, } | { "method": "externalAgentConfig/detect", id: RequestId, params: ExternalAgentConfigDetectParams, } | { "method": "externalAgentConfig/import", id: RequestId, params: ExternalAgentConfigImportParams, } | { "method": "config/value/write", id: RequestId, params: ConfigValueWriteParams, } | { "method": "config/batchWrite", id: RequestId, params: ConfigBatchWriteParams, } | { "method": "configRequirements/read", id: RequestId, params: undefined, } | { "method": "account/read", id: RequestId, params: GetAccountParams, } | { "method": "getConversationSummary", id: RequestId, params: GetConversationSummaryParams, } | { "method": "gitDiffToRemote", id: RequestId, params: GitDiffToRemoteParams, } | { "method": "getAuthStatus", id: RequestId, params: GetAuthStatusParams, } | { "method": "fuzzyFileSearch", id: RequestId, params: FuzzyFileSearchParams, }; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/CommandExecParams.ts b/codex-rs/app-server-protocol/schema/typescript/v2/CommandExecParams.ts index 097cfdfecc..659974feaf 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/CommandExecParams.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/CommandExecParams.ts @@ -2,6 +2,7 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { CommandExecTerminalSize } from "./CommandExecTerminalSize"; +import type { PermissionProfile } from "./PermissionProfile"; import type { SandboxPolicy } from "./SandboxPolicy"; /** @@ -92,6 +93,14 @@ size?: CommandExecTerminalSize | null, * Optional sandbox policy for this command. * * Uses the same shape as thread/turn execution sandbox configuration and - * defaults to the user's configured policy when omitted. + * defaults to the user's configured policy when omitted. Cannot be + * combined with `permissionProfile`. */ -sandboxPolicy?: SandboxPolicy | null, }; +sandboxPolicy?: SandboxPolicy | null, +/** + * Optional full permissions profile for this command. + * + * Defaults to the user's configured permissions when omitted. Cannot be + * combined with `sandboxPolicy`. + */ +permissionProfile?: PermissionProfile | null, }; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/DeviceKeyAlgorithm.ts b/codex-rs/app-server-protocol/schema/typescript/v2/DeviceKeyAlgorithm.ts new file mode 100644 index 0000000000..6809c41eb5 --- /dev/null +++ b/codex-rs/app-server-protocol/schema/typescript/v2/DeviceKeyAlgorithm.ts @@ -0,0 +1,8 @@ +// GENERATED CODE! DO NOT MODIFY BY HAND! + +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +/** + * Device-key algorithm reported at enrollment and signing boundaries. + */ +export type DeviceKeyAlgorithm = "ecdsa_p256_sha256"; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/DeviceKeyCreateParams.ts b/codex-rs/app-server-protocol/schema/typescript/v2/DeviceKeyCreateParams.ts new file mode 100644 index 0000000000..7ffd9b5fa3 --- /dev/null +++ b/codex-rs/app-server-protocol/schema/typescript/v2/DeviceKeyCreateParams.ts @@ -0,0 +1,13 @@ +// GENERATED CODE! DO NOT MODIFY BY HAND! + +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { DeviceKeyProtectionPolicy } from "./DeviceKeyProtectionPolicy"; + +/** + * Create a controller-local device key with a random key id. + */ +export type DeviceKeyCreateParams = { +/** + * Defaults to `hardware_only` when omitted. + */ +protectionPolicy?: DeviceKeyProtectionPolicy | null, accountUserId: string, clientId: string, }; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/DeviceKeyCreateResponse.ts b/codex-rs/app-server-protocol/schema/typescript/v2/DeviceKeyCreateResponse.ts new file mode 100644 index 0000000000..6ace37934a --- /dev/null +++ b/codex-rs/app-server-protocol/schema/typescript/v2/DeviceKeyCreateResponse.ts @@ -0,0 +1,14 @@ +// GENERATED CODE! DO NOT MODIFY BY HAND! + +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { DeviceKeyAlgorithm } from "./DeviceKeyAlgorithm"; +import type { DeviceKeyProtectionClass } from "./DeviceKeyProtectionClass"; + +/** + * Device-key metadata and public key returned by create/public APIs. + */ +export type DeviceKeyCreateResponse = { keyId: string, +/** + * SubjectPublicKeyInfo DER encoded as base64. + */ +publicKeySpkiDerBase64: string, algorithm: DeviceKeyAlgorithm, protectionClass: DeviceKeyProtectionClass, }; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/DeviceKeyProtectionClass.ts b/codex-rs/app-server-protocol/schema/typescript/v2/DeviceKeyProtectionClass.ts new file mode 100644 index 0000000000..ba7ff311ad --- /dev/null +++ b/codex-rs/app-server-protocol/schema/typescript/v2/DeviceKeyProtectionClass.ts @@ -0,0 +1,8 @@ +// GENERATED CODE! DO NOT MODIFY BY HAND! + +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +/** + * Platform protection class for a controller-local device key. + */ +export type DeviceKeyProtectionClass = "hardware_secure_enclave" | "hardware_tpm" | "os_protected_nonextractable"; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/DeviceKeyProtectionPolicy.ts b/codex-rs/app-server-protocol/schema/typescript/v2/DeviceKeyProtectionPolicy.ts new file mode 100644 index 0000000000..66fceafb51 --- /dev/null +++ b/codex-rs/app-server-protocol/schema/typescript/v2/DeviceKeyProtectionPolicy.ts @@ -0,0 +1,8 @@ +// GENERATED CODE! DO NOT MODIFY BY HAND! + +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +/** + * Protection policy for creating or loading a controller-local device key. + */ +export type DeviceKeyProtectionPolicy = "hardware_only" | "allow_os_protected_nonextractable"; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/DeviceKeyPublicParams.ts b/codex-rs/app-server-protocol/schema/typescript/v2/DeviceKeyPublicParams.ts new file mode 100644 index 0000000000..5a5b77899d --- /dev/null +++ b/codex-rs/app-server-protocol/schema/typescript/v2/DeviceKeyPublicParams.ts @@ -0,0 +1,8 @@ +// GENERATED CODE! DO NOT MODIFY BY HAND! + +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +/** + * Fetch a controller-local device key public key by id. + */ +export type DeviceKeyPublicParams = { keyId: string, }; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/DeviceKeyPublicResponse.ts b/codex-rs/app-server-protocol/schema/typescript/v2/DeviceKeyPublicResponse.ts new file mode 100644 index 0000000000..9967c0936e --- /dev/null +++ b/codex-rs/app-server-protocol/schema/typescript/v2/DeviceKeyPublicResponse.ts @@ -0,0 +1,14 @@ +// GENERATED CODE! DO NOT MODIFY BY HAND! + +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { DeviceKeyAlgorithm } from "./DeviceKeyAlgorithm"; +import type { DeviceKeyProtectionClass } from "./DeviceKeyProtectionClass"; + +/** + * Device-key public metadata returned by `device/key/public`. + */ +export type DeviceKeyPublicResponse = { keyId: string, +/** + * SubjectPublicKeyInfo DER encoded as base64. + */ +publicKeySpkiDerBase64: string, algorithm: DeviceKeyAlgorithm, protectionClass: DeviceKeyProtectionClass, }; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/DeviceKeySignParams.ts b/codex-rs/app-server-protocol/schema/typescript/v2/DeviceKeySignParams.ts new file mode 100644 index 0000000000..0886e45d93 --- /dev/null +++ b/codex-rs/app-server-protocol/schema/typescript/v2/DeviceKeySignParams.ts @@ -0,0 +1,9 @@ +// GENERATED CODE! DO NOT MODIFY BY HAND! + +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { DeviceKeySignPayload } from "./DeviceKeySignPayload"; + +/** + * Sign an accepted structured payload with a controller-local device key. + */ +export type DeviceKeySignParams = { keyId: string, payload: DeviceKeySignPayload, }; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/DeviceKeySignPayload.ts b/codex-rs/app-server-protocol/schema/typescript/v2/DeviceKeySignPayload.ts new file mode 100644 index 0000000000..8596445490 --- /dev/null +++ b/codex-rs/app-server-protocol/schema/typescript/v2/DeviceKeySignPayload.ts @@ -0,0 +1,54 @@ +// GENERATED CODE! DO NOT MODIFY BY HAND! + +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { RemoteControlClientConnectionAudience } from "./RemoteControlClientConnectionAudience"; +import type { RemoteControlClientEnrollmentAudience } from "./RemoteControlClientEnrollmentAudience"; + +/** + * Structured payloads accepted by `device/key/sign`. + */ +export type DeviceKeySignPayload = { "type": "remoteControlClientConnection", nonce: string, audience: RemoteControlClientConnectionAudience, +/** + * Backend-issued websocket session id that this proof authorizes. + */ +sessionId: string, +/** + * Origin of the backend endpoint that issued the challenge and will verify this proof. + */ +targetOrigin: string, +/** + * Websocket route path that this proof authorizes. + */ +targetPath: string, accountUserId: string, clientId: string, +/** + * Remote-control token expiration as Unix seconds. + */ +tokenExpiresAt: number, +/** + * SHA-256 of the controller-scoped remote-control token, encoded as unpadded base64url. + */ +tokenSha256Base64url: string, +/** + * Must contain exactly `remote_control_controller_websocket`. + */ +scopes: Array, } | { "type": "remoteControlClientEnrollment", nonce: string, audience: RemoteControlClientEnrollmentAudience, +/** + * Backend-issued enrollment challenge id that this proof authorizes. + */ +challengeId: string, +/** + * Origin of the backend endpoint that issued the challenge and will verify this proof. + */ +targetOrigin: string, +/** + * HTTP route path that this proof authorizes. + */ +targetPath: string, accountUserId: string, clientId: string, +/** + * SHA-256 of the requested device identity operation, encoded as unpadded base64url. + */ +deviceIdentitySha256Base64url: string, +/** + * Enrollment challenge expiration as Unix seconds. + */ +challengeExpiresAt: number, }; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/DeviceKeySignResponse.ts b/codex-rs/app-server-protocol/schema/typescript/v2/DeviceKeySignResponse.ts new file mode 100644 index 0000000000..cf77fae27f --- /dev/null +++ b/codex-rs/app-server-protocol/schema/typescript/v2/DeviceKeySignResponse.ts @@ -0,0 +1,18 @@ +// GENERATED CODE! DO NOT MODIFY BY HAND! + +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { DeviceKeyAlgorithm } from "./DeviceKeyAlgorithm"; + +/** + * ASN.1 DER signature returned by `device/key/sign`. + */ +export type DeviceKeySignResponse = { +/** + * ECDSA signature DER encoded as base64. + */ +signatureDerBase64: string, +/** + * Exact bytes signed by the device key, encoded as base64. Verifiers must verify this byte + * string directly and must not reserialize `payload`. + */ +signedPayloadBase64: string, algorithm: DeviceKeyAlgorithm, }; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/PermissionProfile.ts b/codex-rs/app-server-protocol/schema/typescript/v2/PermissionProfile.ts new file mode 100644 index 0000000000..603f607720 --- /dev/null +++ b/codex-rs/app-server-protocol/schema/typescript/v2/PermissionProfile.ts @@ -0,0 +1,7 @@ +// GENERATED CODE! DO NOT MODIFY BY HAND! + +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { AdditionalNetworkPermissions } from "./AdditionalNetworkPermissions"; +import type { PermissionProfileFileSystemPermissions } from "./PermissionProfileFileSystemPermissions"; + +export type PermissionProfile = { network: AdditionalNetworkPermissions | null, fileSystem: PermissionProfileFileSystemPermissions | null, }; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/PermissionProfileFileSystemPermissions.ts b/codex-rs/app-server-protocol/schema/typescript/v2/PermissionProfileFileSystemPermissions.ts new file mode 100644 index 0000000000..204a42764c --- /dev/null +++ b/codex-rs/app-server-protocol/schema/typescript/v2/PermissionProfileFileSystemPermissions.ts @@ -0,0 +1,6 @@ +// GENERATED CODE! DO NOT MODIFY BY HAND! + +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { FileSystemSandboxEntry } from "./FileSystemSandboxEntry"; + +export type PermissionProfileFileSystemPermissions = { entries: Array, globScanMaxDepth?: number, }; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/RemoteControlClientConnectionAudience.ts b/codex-rs/app-server-protocol/schema/typescript/v2/RemoteControlClientConnectionAudience.ts new file mode 100644 index 0000000000..e4d41ff4c2 --- /dev/null +++ b/codex-rs/app-server-protocol/schema/typescript/v2/RemoteControlClientConnectionAudience.ts @@ -0,0 +1,8 @@ +// GENERATED CODE! DO NOT MODIFY BY HAND! + +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +/** + * Audience for a remote-control client connection device-key proof. + */ +export type RemoteControlClientConnectionAudience = "remote_control_client_websocket"; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/RemoteControlClientEnrollmentAudience.ts b/codex-rs/app-server-protocol/schema/typescript/v2/RemoteControlClientEnrollmentAudience.ts new file mode 100644 index 0000000000..b65fb3d11b --- /dev/null +++ b/codex-rs/app-server-protocol/schema/typescript/v2/RemoteControlClientEnrollmentAudience.ts @@ -0,0 +1,8 @@ +// GENERATED CODE! DO NOT MODIFY BY HAND! + +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +/** + * Audience for a remote-control client enrollment device-key proof. + */ +export type RemoteControlClientEnrollmentAudience = "remote_control_client_enrollment"; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/ThreadForkParams.ts b/codex-rs/app-server-protocol/schema/typescript/v2/ThreadForkParams.ts index a7ba311803..bd73b3c3c3 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/ThreadForkParams.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/ThreadForkParams.ts @@ -5,6 +5,7 @@ import type { ServiceTier } from "../ServiceTier"; import type { JsonValue } from "../serde_json/JsonValue"; import type { ApprovalsReviewer } from "./ApprovalsReviewer"; import type { AskForApproval } from "./AskForApproval"; +import type { PermissionProfile } from "./PermissionProfile"; import type { SandboxMode } from "./SandboxMode"; /** @@ -27,7 +28,11 @@ model?: string | null, modelProvider?: string | null, serviceTier?: ServiceTier * Override where approval requests are routed for review on this thread * and subsequent turns. */ -approvalsReviewer?: ApprovalsReviewer | null, sandbox?: SandboxMode | null, config?: { [key in string]?: JsonValue } | null, baseInstructions?: string | null, developerInstructions?: string | null, ephemeral?: boolean, /** +approvalsReviewer?: ApprovalsReviewer | null, sandbox?: SandboxMode | null, /** + * Full permissions override for the forked thread. Cannot be combined + * with `sandbox`. + */ +permissionProfile?: PermissionProfile | null, config?: { [key in string]?: JsonValue } | null, baseInstructions?: string | null, developerInstructions?: string | null, ephemeral?: boolean, /** * If true, persist additional rollout EventMsg variants required to * reconstruct a richer thread history on subsequent resume/fork/read. */ diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/ThreadForkResponse.ts b/codex-rs/app-server-protocol/schema/typescript/v2/ThreadForkResponse.ts index 470e98c9b8..add13b6f28 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/ThreadForkResponse.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/ThreadForkResponse.ts @@ -6,6 +6,7 @@ import type { ReasoningEffort } from "../ReasoningEffort"; import type { ServiceTier } from "../ServiceTier"; import type { ApprovalsReviewer } from "./ApprovalsReviewer"; import type { AskForApproval } from "./AskForApproval"; +import type { PermissionProfile } from "./PermissionProfile"; import type { SandboxPolicy } from "./SandboxPolicy"; import type { Thread } from "./Thread"; @@ -17,4 +18,4 @@ instructionSources: Array, approvalPolicy: AskForApproval, /** * Reviewer currently used for approval requests on this thread. */ -approvalsReviewer: ApprovalsReviewer, sandbox: SandboxPolicy, reasoningEffort: ReasoningEffort | null, }; +approvalsReviewer: ApprovalsReviewer, sandbox: SandboxPolicy, permissionProfile: PermissionProfile, reasoningEffort: ReasoningEffort | null, }; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/ThreadResumeParams.ts b/codex-rs/app-server-protocol/schema/typescript/v2/ThreadResumeParams.ts index 770344de8e..d245efe4a2 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/ThreadResumeParams.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/ThreadResumeParams.ts @@ -7,6 +7,7 @@ import type { ServiceTier } from "../ServiceTier"; import type { JsonValue } from "../serde_json/JsonValue"; import type { ApprovalsReviewer } from "./ApprovalsReviewer"; import type { AskForApproval } from "./AskForApproval"; +import type { PermissionProfile } from "./PermissionProfile"; import type { SandboxMode } from "./SandboxMode"; /** @@ -36,7 +37,11 @@ model?: string | null, modelProvider?: string | null, serviceTier?: ServiceTier * Override where approval requests are routed for review on this thread * and subsequent turns. */ -approvalsReviewer?: ApprovalsReviewer | null, sandbox?: SandboxMode | null, config?: { [key in string]?: JsonValue } | null, baseInstructions?: string | null, developerInstructions?: string | null, personality?: Personality | null, /** +approvalsReviewer?: ApprovalsReviewer | null, sandbox?: SandboxMode | null, /** + * Full permissions override for the resumed thread. Cannot be combined + * with `sandbox`. + */ +permissionProfile?: PermissionProfile | null, config?: { [key in string]?: JsonValue } | null, baseInstructions?: string | null, developerInstructions?: string | null, personality?: Personality | null, /** * If true, persist additional rollout EventMsg variants required to * reconstruct a richer thread history on subsequent resume/fork/read. */ diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/ThreadResumeResponse.ts b/codex-rs/app-server-protocol/schema/typescript/v2/ThreadResumeResponse.ts index 177add8350..cf73f3997c 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/ThreadResumeResponse.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/ThreadResumeResponse.ts @@ -6,6 +6,7 @@ import type { ReasoningEffort } from "../ReasoningEffort"; import type { ServiceTier } from "../ServiceTier"; import type { ApprovalsReviewer } from "./ApprovalsReviewer"; import type { AskForApproval } from "./AskForApproval"; +import type { PermissionProfile } from "./PermissionProfile"; import type { SandboxPolicy } from "./SandboxPolicy"; import type { Thread } from "./Thread"; @@ -17,4 +18,4 @@ instructionSources: Array, approvalPolicy: AskForApproval, /** * Reviewer currently used for approval requests on this thread. */ -approvalsReviewer: ApprovalsReviewer, sandbox: SandboxPolicy, reasoningEffort: ReasoningEffort | null, }; +approvalsReviewer: ApprovalsReviewer, sandbox: SandboxPolicy, permissionProfile: PermissionProfile, reasoningEffort: ReasoningEffort | null, }; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/ThreadStartParams.ts b/codex-rs/app-server-protocol/schema/typescript/v2/ThreadStartParams.ts index 904487e81c..8b9dafec9f 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/ThreadStartParams.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/ThreadStartParams.ts @@ -6,6 +6,7 @@ import type { ServiceTier } from "../ServiceTier"; import type { JsonValue } from "../serde_json/JsonValue"; import type { ApprovalsReviewer } from "./ApprovalsReviewer"; import type { AskForApproval } from "./AskForApproval"; +import type { PermissionProfile } from "./PermissionProfile"; import type { SandboxMode } from "./SandboxMode"; import type { ThreadStartSource } from "./ThreadStartSource"; @@ -13,7 +14,11 @@ export type ThreadStartParams = {model?: string | null, modelProvider?: string | * Override where approval requests are routed for review on this thread * and subsequent turns. */ -approvalsReviewer?: ApprovalsReviewer | null, sandbox?: SandboxMode | null, config?: { [key in string]?: JsonValue } | null, serviceName?: string | null, baseInstructions?: string | null, developerInstructions?: string | null, personality?: Personality | null, ephemeral?: boolean | null, sessionStartSource?: ThreadStartSource | null, /** +approvalsReviewer?: ApprovalsReviewer | null, sandbox?: SandboxMode | null, /** + * Full permissions override for this thread. Cannot be combined with + * `sandbox`. + */ +permissionProfile?: PermissionProfile | null, config?: { [key in string]?: JsonValue } | null, serviceName?: string | null, baseInstructions?: string | null, developerInstructions?: string | null, personality?: Personality | null, ephemeral?: boolean | null, sessionStartSource?: ThreadStartSource | null, /** * If true, opt into emitting raw Responses API items on the event stream. * This is for internal use only (e.g. Codex Cloud). */ diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/ThreadStartResponse.ts b/codex-rs/app-server-protocol/schema/typescript/v2/ThreadStartResponse.ts index fd84a41ae8..3885f61a34 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/ThreadStartResponse.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/ThreadStartResponse.ts @@ -6,6 +6,7 @@ import type { ReasoningEffort } from "../ReasoningEffort"; import type { ServiceTier } from "../ServiceTier"; import type { ApprovalsReviewer } from "./ApprovalsReviewer"; import type { AskForApproval } from "./AskForApproval"; +import type { PermissionProfile } from "./PermissionProfile"; import type { SandboxPolicy } from "./SandboxPolicy"; import type { Thread } from "./Thread"; @@ -17,4 +18,4 @@ instructionSources: Array, approvalPolicy: AskForApproval, /** * Reviewer currently used for approval requests on this thread. */ -approvalsReviewer: ApprovalsReviewer, sandbox: SandboxPolicy, reasoningEffort: ReasoningEffort | null, }; +approvalsReviewer: ApprovalsReviewer, sandbox: SandboxPolicy, permissionProfile: PermissionProfile, reasoningEffort: ReasoningEffort | null, }; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/TurnStartParams.ts b/codex-rs/app-server-protocol/schema/typescript/v2/TurnStartParams.ts index 8f57a5e68b..3d12e6001c 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/TurnStartParams.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/TurnStartParams.ts @@ -9,6 +9,7 @@ import type { ServiceTier } from "../ServiceTier"; import type { JsonValue } from "../serde_json/JsonValue"; import type { ApprovalsReviewer } from "./ApprovalsReviewer"; import type { AskForApproval } from "./AskForApproval"; +import type { PermissionProfile } from "./PermissionProfile"; import type { SandboxPolicy } from "./SandboxPolicy"; import type { UserInput } from "./UserInput"; @@ -26,6 +27,10 @@ approvalsReviewer?: ApprovalsReviewer | null, /** * Override the sandbox policy for this turn and subsequent turns. */ sandboxPolicy?: SandboxPolicy | null, /** + * Override the full permissions profile for this turn and subsequent + * turns. Cannot be combined with `sandboxPolicy`. + */ +permissionProfile?: PermissionProfile | null, /** * Override the model for this turn and subsequent turns. */ model?: string | null, /** diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/index.ts b/codex-rs/app-server-protocol/schema/typescript/v2/index.ts index e37759112a..8f081464cc 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/index.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/index.ts @@ -74,6 +74,16 @@ export type { ConfigWriteResponse } from "./ConfigWriteResponse"; export type { ContextCompactedNotification } from "./ContextCompactedNotification"; export type { CreditsSnapshot } from "./CreditsSnapshot"; export type { DeprecationNoticeNotification } from "./DeprecationNoticeNotification"; +export type { DeviceKeyAlgorithm } from "./DeviceKeyAlgorithm"; +export type { DeviceKeyCreateParams } from "./DeviceKeyCreateParams"; +export type { DeviceKeyCreateResponse } from "./DeviceKeyCreateResponse"; +export type { DeviceKeyProtectionClass } from "./DeviceKeyProtectionClass"; +export type { DeviceKeyProtectionPolicy } from "./DeviceKeyProtectionPolicy"; +export type { DeviceKeyPublicParams } from "./DeviceKeyPublicParams"; +export type { DeviceKeyPublicResponse } from "./DeviceKeyPublicResponse"; +export type { DeviceKeySignParams } from "./DeviceKeySignParams"; +export type { DeviceKeySignPayload } from "./DeviceKeySignPayload"; +export type { DeviceKeySignResponse } from "./DeviceKeySignResponse"; export type { DynamicToolCallOutputContentItem } from "./DynamicToolCallOutputContentItem"; export type { DynamicToolCallParams } from "./DynamicToolCallParams"; export type { DynamicToolCallResponse } from "./DynamicToolCallResponse"; @@ -230,6 +240,8 @@ export type { OverriddenMetadata } from "./OverriddenMetadata"; export type { PatchApplyStatus } from "./PatchApplyStatus"; export type { PatchChangeKind } from "./PatchChangeKind"; export type { PermissionGrantScope } from "./PermissionGrantScope"; +export type { PermissionProfile } from "./PermissionProfile"; +export type { PermissionProfileFileSystemPermissions } from "./PermissionProfileFileSystemPermissions"; export type { PermissionsRequestApprovalParams } from "./PermissionsRequestApprovalParams"; export type { PermissionsRequestApprovalResponse } from "./PermissionsRequestApprovalResponse"; export type { PlanDeltaNotification } from "./PlanDeltaNotification"; @@ -259,6 +271,8 @@ export type { ReasoningEffortOption } from "./ReasoningEffortOption"; export type { ReasoningSummaryPartAddedNotification } from "./ReasoningSummaryPartAddedNotification"; export type { ReasoningSummaryTextDeltaNotification } from "./ReasoningSummaryTextDeltaNotification"; export type { ReasoningTextDeltaNotification } from "./ReasoningTextDeltaNotification"; +export type { RemoteControlClientConnectionAudience } from "./RemoteControlClientConnectionAudience"; +export type { RemoteControlClientEnrollmentAudience } from "./RemoteControlClientEnrollmentAudience"; export type { RequestPermissionProfile } from "./RequestPermissionProfile"; export type { ResidencyRequirement } from "./ResidencyRequirement"; export type { ReviewDelivery } from "./ReviewDelivery"; diff --git a/codex-rs/app-server-protocol/src/protocol/common.rs b/codex-rs/app-server-protocol/src/protocol/common.rs index aa3ff8331c..9e2635b4ea 100644 --- a/codex-rs/app-server-protocol/src/protocol/common.rs +++ b/codex-rs/app-server-protocol/src/protocol/common.rs @@ -360,6 +360,18 @@ client_request_definitions! { params: v2::AppsListParams, response: v2::AppsListResponse, }, + DeviceKeyCreate => "device/key/create" { + params: v2::DeviceKeyCreateParams, + response: v2::DeviceKeyCreateResponse, + }, + DeviceKeyPublic => "device/key/public" { + params: v2::DeviceKeyPublicParams, + response: v2::DeviceKeyPublicResponse, + }, + DeviceKeySign => "device/key/sign" { + params: v2::DeviceKeySignParams, + response: v2::DeviceKeySignResponse, + }, FsReadFile => "fs/readFile" { params: v2::FsReadFileParams, response: v2::FsReadFileResponse, @@ -1448,6 +1460,12 @@ mod tests { approval_policy: v2::AskForApproval::OnFailure, approvals_reviewer: v2::ApprovalsReviewer::User, sandbox: v2::SandboxPolicy::DangerFullAccess, + permission_profile: + codex_protocol::models::PermissionProfile::from_legacy_sandbox_policy( + &codex_protocol::protocol::SandboxPolicy::DangerFullAccess, + std::path::Path::new("/tmp"), + ) + .into(), reasoning_effort: None, }, }; @@ -1490,6 +1508,24 @@ mod tests { "sandbox": { "type": "dangerFullAccess" }, + "permissionProfile": { + "network": { + "enabled": true, + }, + "fileSystem": { + "entries": [ + { + "path": { + "type": "special", + "value": { + "kind": "root", + }, + }, + "access": "write", + }, + ], + }, + }, "reasoningEffort": null } }), diff --git a/codex-rs/app-server-protocol/src/protocol/mappers.rs b/codex-rs/app-server-protocol/src/protocol/mappers.rs index 93f12691be..dae91e650f 100644 --- a/codex-rs/app-server-protocol/src/protocol/mappers.rs +++ b/codex-rs/app-server-protocol/src/protocol/mappers.rs @@ -18,6 +18,7 @@ impl From for v2::CommandExecParams { env: None, size: None, sandbox_policy: value.sandbox_policy.map(std::convert::Into::into), + permission_profile: None, } } } diff --git a/codex-rs/app-server-protocol/src/protocol/v2.rs b/codex-rs/app-server-protocol/src/protocol/v2.rs index 87a039471c..e092521045 100644 --- a/codex-rs/app-server-protocol/src/protocol/v2.rs +++ b/codex-rs/app-server-protocol/src/protocol/v2.rs @@ -1383,6 +1383,70 @@ impl From for CoreFileSystemSandboxEntry { } } +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] +#[serde(rename_all = "camelCase")] +#[ts(export_to = "v2/")] +pub struct PermissionProfileFileSystemPermissions { + pub entries: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + #[ts(optional)] + pub glob_scan_max_depth: Option, +} + +impl From for PermissionProfileFileSystemPermissions { + fn from(value: CoreFileSystemPermissions) -> Self { + Self { + entries: value + .entries + .into_iter() + .map(FileSystemSandboxEntry::from) + .collect(), + glob_scan_max_depth: value.glob_scan_max_depth, + } + } +} + +impl From for CoreFileSystemPermissions { + fn from(value: PermissionProfileFileSystemPermissions) -> Self { + Self { + entries: value + .entries + .into_iter() + .map(CoreFileSystemSandboxEntry::from) + .collect(), + glob_scan_max_depth: value.glob_scan_max_depth, + } + } +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] +#[serde(rename_all = "camelCase")] +#[ts(export_to = "v2/")] +pub struct PermissionProfile { + pub network: Option, + pub file_system: Option, +} + +impl From for PermissionProfile { + fn from(value: CorePermissionProfile) -> Self { + Self { + network: value.network.map(AdditionalNetworkPermissions::from), + file_system: value + .file_system + .map(PermissionProfileFileSystemPermissions::from), + } + } +} + +impl From for CorePermissionProfile { + fn from(value: PermissionProfile) -> Self { + Self { + network: value.network.map(CoreNetworkPermissions::from), + file_system: value.file_system.map(CoreFileSystemPermissions::from), + } + } +} + #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] @@ -2494,6 +2558,164 @@ pub struct FeedbackUploadResponse { pub thread_id: String, } +/// Device-key algorithm reported at enrollment and signing boundaries. +#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)] +#[serde(rename_all = "snake_case")] +#[ts(rename_all = "snake_case", export_to = "v2/")] +pub enum DeviceKeyAlgorithm { + EcdsaP256Sha256, +} + +/// Platform protection class for a controller-local device key. +#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)] +#[serde(rename_all = "snake_case")] +#[ts(rename_all = "snake_case", export_to = "v2/")] +pub enum DeviceKeyProtectionClass { + HardwareSecureEnclave, + HardwareTpm, + OsProtectedNonextractable, +} + +/// Protection policy for creating or loading a controller-local device key. +#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)] +#[serde(rename_all = "snake_case")] +#[ts(rename_all = "snake_case", export_to = "v2/")] +pub enum DeviceKeyProtectionPolicy { + HardwareOnly, + AllowOsProtectedNonextractable, +} + +/// Create a controller-local device key with a random key id. +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] +#[serde(rename_all = "camelCase")] +#[ts(export_to = "v2/")] +pub struct DeviceKeyCreateParams { + /// Defaults to `hardware_only` when omitted. + #[ts(optional = nullable)] + pub protection_policy: Option, + pub account_user_id: String, + pub client_id: String, +} + +/// Device-key metadata and public key returned by create/public APIs. +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] +#[serde(rename_all = "camelCase")] +#[ts(export_to = "v2/")] +pub struct DeviceKeyCreateResponse { + pub key_id: String, + /// SubjectPublicKeyInfo DER encoded as base64. + pub public_key_spki_der_base64: String, + pub algorithm: DeviceKeyAlgorithm, + pub protection_class: DeviceKeyProtectionClass, +} + +/// Fetch a controller-local device key public key by id. +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] +#[serde(rename_all = "camelCase")] +#[ts(export_to = "v2/")] +pub struct DeviceKeyPublicParams { + pub key_id: String, +} + +/// Device-key public metadata returned by `device/key/public`. +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] +#[serde(rename_all = "camelCase")] +#[ts(export_to = "v2/")] +pub struct DeviceKeyPublicResponse { + pub key_id: String, + /// SubjectPublicKeyInfo DER encoded as base64. + pub public_key_spki_der_base64: String, + pub algorithm: DeviceKeyAlgorithm, + pub protection_class: DeviceKeyProtectionClass, +} + +/// Audience for a remote-control client connection device-key proof. +#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)] +#[serde(rename_all = "snake_case")] +#[ts(rename_all = "snake_case", export_to = "v2/")] +pub enum RemoteControlClientConnectionAudience { + RemoteControlClientWebsocket, +} + +/// Audience for a remote-control client enrollment device-key proof. +#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)] +#[serde(rename_all = "snake_case")] +#[ts(rename_all = "snake_case", export_to = "v2/")] +pub enum RemoteControlClientEnrollmentAudience { + RemoteControlClientEnrollment, +} + +/// Structured payloads accepted by `device/key/sign`. +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] +#[serde(tag = "type", rename_all = "camelCase")] +#[ts(tag = "type", export_to = "v2/")] +pub enum DeviceKeySignPayload { + /// Payload bound to one remote-control controller websocket `/client` connection challenge. + #[serde(rename_all = "camelCase")] + #[ts(rename_all = "camelCase")] + RemoteControlClientConnection { + nonce: String, + audience: RemoteControlClientConnectionAudience, + /// Backend-issued websocket session id that this proof authorizes. + session_id: String, + /// Origin of the backend endpoint that issued the challenge and will verify this proof. + target_origin: String, + /// Websocket route path that this proof authorizes. + target_path: String, + account_user_id: String, + client_id: String, + /// Remote-control token expiration as Unix seconds. + #[ts(type = "number")] + token_expires_at: i64, + /// SHA-256 of the controller-scoped remote-control token, encoded as unpadded base64url. + token_sha256_base64url: String, + /// Must contain exactly `remote_control_controller_websocket`. + scopes: Vec, + }, + /// Payload bound to a remote-control client `/client/enroll` ownership challenge. + #[serde(rename_all = "camelCase")] + #[ts(rename_all = "camelCase")] + RemoteControlClientEnrollment { + nonce: String, + audience: RemoteControlClientEnrollmentAudience, + /// Backend-issued enrollment challenge id that this proof authorizes. + challenge_id: String, + /// Origin of the backend endpoint that issued the challenge and will verify this proof. + target_origin: String, + /// HTTP route path that this proof authorizes. + target_path: String, + account_user_id: String, + client_id: String, + /// SHA-256 of the requested device identity operation, encoded as unpadded base64url. + device_identity_sha256_base64url: String, + /// Enrollment challenge expiration as Unix seconds. + #[ts(type = "number")] + challenge_expires_at: i64, + }, +} + +/// Sign an accepted structured payload with a controller-local device key. +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] +#[serde(rename_all = "camelCase")] +#[ts(export_to = "v2/")] +pub struct DeviceKeySignParams { + pub key_id: String, + pub payload: DeviceKeySignPayload, +} + +/// ASN.1 DER signature returned by `device/key/sign`. +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] +#[serde(rename_all = "camelCase")] +#[ts(export_to = "v2/")] +pub struct DeviceKeySignResponse { + /// ECDSA signature DER encoded as base64. + pub signature_der_base64: String, + /// Exact bytes signed by the device key, encoded as base64. Verifiers must verify this byte + /// string directly and must not reserialize `payload`. + pub signed_payload_base64: String, + pub algorithm: DeviceKeyAlgorithm, +} + /// Read a file from the host filesystem. #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] @@ -2781,9 +3003,16 @@ pub struct CommandExecParams { /// Optional sandbox policy for this command. /// /// Uses the same shape as thread/turn execution sandbox configuration and - /// defaults to the user's configured policy when omitted. + /// defaults to the user's configured policy when omitted. Cannot be + /// combined with `permissionProfile`. #[ts(optional = nullable)] pub sandbox_policy: Option, + /// Optional full permissions profile for this command. + /// + /// Defaults to the user's configured permissions when omitted. Cannot be + /// combined with `sandboxPolicy`. + #[ts(optional = nullable)] + pub permission_profile: Option, } /// Final buffered result for `command/exec`. @@ -2902,6 +3131,10 @@ pub struct ThreadStartParams { pub approvals_reviewer: Option, #[ts(optional = nullable)] pub sandbox: Option, + /// Full permissions override for this thread. Cannot be combined with + /// `sandbox`. + #[ts(optional = nullable)] + pub permission_profile: Option, #[ts(optional = nullable)] pub config: Option>, #[ts(optional = nullable)] @@ -2970,6 +3203,7 @@ pub struct ThreadStartResponse { /// Reviewer currently used for approval requests on this thread. pub approvals_reviewer: ApprovalsReviewer, pub sandbox: SandboxPolicy, + pub permission_profile: PermissionProfile, pub reasoning_effort: Option, } @@ -3027,6 +3261,10 @@ pub struct ThreadResumeParams { pub approvals_reviewer: Option, #[ts(optional = nullable)] pub sandbox: Option, + /// Full permissions override for the resumed thread. Cannot be combined + /// with `sandbox`. + #[ts(optional = nullable)] + pub permission_profile: Option, #[ts(optional = nullable)] pub config: Option>, #[ts(optional = nullable)] @@ -3059,6 +3297,7 @@ pub struct ThreadResumeResponse { /// Reviewer currently used for approval requests on this thread. pub approvals_reviewer: ApprovalsReviewer, pub sandbox: SandboxPolicy, + pub permission_profile: PermissionProfile, pub reasoning_effort: Option, } @@ -3107,6 +3346,10 @@ pub struct ThreadForkParams { pub approvals_reviewer: Option, #[ts(optional = nullable)] pub sandbox: Option, + /// Full permissions override for the forked thread. Cannot be combined + /// with `sandbox`. + #[ts(optional = nullable)] + pub permission_profile: Option, #[ts(optional = nullable)] pub config: Option>, #[ts(optional = nullable)] @@ -3139,6 +3382,7 @@ pub struct ThreadForkResponse { /// Reviewer currently used for approval requests on this thread. pub approvals_reviewer: ApprovalsReviewer, pub sandbox: SandboxPolicy, + pub permission_profile: PermissionProfile, pub reasoning_effort: Option, } @@ -4509,6 +4753,10 @@ pub struct TurnStartParams { /// Override the sandbox policy for this turn and subsequent turns. #[ts(optional = nullable)] pub sandbox_policy: Option, + /// Override the full permissions profile for this turn and subsequent + /// turns. Cannot be combined with `sandboxPolicy`. + #[ts(optional = nullable)] + pub permission_profile: Option, /// Override the model for this turn and subsequent turns. #[ts(optional = nullable)] pub model: Option, @@ -7249,6 +7497,47 @@ mod tests { .expect_err("zero glob scan depth should fail deserialization"); } + #[test] + fn permission_profile_file_system_permissions_preserves_glob_scan_depth() { + let core_permissions = CoreFileSystemPermissions { + entries: vec![CoreFileSystemSandboxEntry { + path: CoreFileSystemPath::GlobPattern { + pattern: "**/*.env".to_string(), + }, + access: CoreFileSystemAccessMode::None, + }], + glob_scan_max_depth: NonZeroUsize::new(2), + }; + + let permissions = PermissionProfileFileSystemPermissions::from(core_permissions.clone()); + + assert_eq!( + permissions, + PermissionProfileFileSystemPermissions { + entries: vec![FileSystemSandboxEntry { + path: FileSystemPath::GlobPattern { + pattern: "**/*.env".to_string(), + }, + access: FileSystemAccessMode::None, + }], + glob_scan_max_depth: NonZeroUsize::new(2), + } + ); + assert_eq!( + CoreFileSystemPermissions::from(permissions), + core_permissions + ); + } + + #[test] + fn permission_profile_file_system_permissions_rejects_zero_glob_scan_depth() { + serde_json::from_value::(json!({ + "entries": [], + "globScanMaxDepth": 0, + })) + .expect_err("zero glob scan depth should fail deserialization"); + } + #[test] fn permissions_request_approval_response_uses_granted_permission_profile_without_macos() { let read_only_path = if cfg!(windows) { @@ -7390,6 +7679,181 @@ mod tests { assert_eq!(decoded, params); } + #[test] + fn device_key_create_params_round_trip_uses_protection_policy() { + let params = DeviceKeyCreateParams { + protection_policy: None, + account_user_id: "account-user-1".to_string(), + client_id: "cli_123".to_string(), + }; + + let value = serde_json::to_value(¶ms).expect("serialize device/key/create params"); + assert_eq!( + value, + json!({ + "accountUserId": "account-user-1", + "clientId": "cli_123", + "protectionPolicy": null, + }) + ); + + let decoded = serde_json::from_value::(value) + .expect("deserialize device/key/create params"); + assert_eq!(decoded, params); + + let params = DeviceKeyCreateParams { + protection_policy: Some(DeviceKeyProtectionPolicy::AllowOsProtectedNonextractable), + account_user_id: "account-user-1".to_string(), + client_id: "cli_123".to_string(), + }; + let value = serde_json::to_value(¶ms) + .expect("serialize device/key/create params with protection policy"); + assert_eq!( + value, + json!({ + "accountUserId": "account-user-1", + "clientId": "cli_123", + "protectionPolicy": "allow_os_protected_nonextractable", + }) + ); + } + + #[test] + fn device_key_create_response_round_trips_protection_class() { + let response = DeviceKeyCreateResponse { + key_id: "dk_123".to_string(), + public_key_spki_der_base64: "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE".to_string(), + algorithm: DeviceKeyAlgorithm::EcdsaP256Sha256, + protection_class: DeviceKeyProtectionClass::OsProtectedNonextractable, + }; + + let value = serde_json::to_value(&response).expect("serialize device/key/create response"); + assert_eq!( + value, + json!({ + "keyId": "dk_123", + "publicKeySpkiDerBase64": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE", + "algorithm": "ecdsa_p256_sha256", + "protectionClass": "os_protected_nonextractable", + }) + ); + + let decoded = serde_json::from_value::(value) + .expect("deserialize device/key/create response"); + assert_eq!(decoded, response); + } + + #[test] + fn device_key_sign_params_round_trip_uses_accepted_payload_enum() { + let params = DeviceKeySignParams { + key_id: "dk_123".to_string(), + payload: DeviceKeySignPayload::RemoteControlClientConnection { + nonce: "nonce-1".to_string(), + audience: RemoteControlClientConnectionAudience::RemoteControlClientWebsocket, + session_id: "wssess_123".to_string(), + target_origin: "https://chatgpt.com".to_string(), + target_path: "/api/codex/remote/control/client".to_string(), + account_user_id: "account-user-1".to_string(), + client_id: "cli_123".to_string(), + token_sha256_base64url: "47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU".to_string(), + token_expires_at: 1_700_000_000, + scopes: vec!["remote_control_controller_websocket".to_string()], + }, + }; + + let value = serde_json::to_value(¶ms).expect("serialize device/key/sign params"); + assert_eq!( + value, + json!({ + "keyId": "dk_123", + "payload": { + "type": "remoteControlClientConnection", + "nonce": "nonce-1", + "audience": "remote_control_client_websocket", + "sessionId": "wssess_123", + "targetOrigin": "https://chatgpt.com", + "targetPath": "/api/codex/remote/control/client", + "accountUserId": "account-user-1", + "clientId": "cli_123", + "tokenSha256Base64url": "47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU", + "tokenExpiresAt": 1_700_000_000, + "scopes": ["remote_control_controller_websocket"], + }, + }) + ); + + let decoded = serde_json::from_value::(value) + .expect("deserialize device/key/sign params"); + assert_eq!(decoded, params); + } + + #[test] + fn device_key_sign_params_round_trip_uses_enrollment_payload() { + let params = DeviceKeySignParams { + key_id: "dk_123".to_string(), + payload: DeviceKeySignPayload::RemoteControlClientEnrollment { + nonce: "nonce-1".to_string(), + audience: RemoteControlClientEnrollmentAudience::RemoteControlClientEnrollment, + challenge_id: "rch_123".to_string(), + target_origin: "https://chatgpt.com".to_string(), + target_path: "/wham/remote/control/client/enroll".to_string(), + account_user_id: "account-user-1".to_string(), + client_id: "cli_123".to_string(), + device_identity_sha256_base64url: "47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU" + .to_string(), + challenge_expires_at: 1_700_000_000, + }, + }; + + let value = serde_json::to_value(¶ms) + .expect("serialize device/key/sign params with enrollment payload"); + assert_eq!( + value, + json!({ + "keyId": "dk_123", + "payload": { + "type": "remoteControlClientEnrollment", + "nonce": "nonce-1", + "audience": "remote_control_client_enrollment", + "challengeId": "rch_123", + "targetOrigin": "https://chatgpt.com", + "targetPath": "/wham/remote/control/client/enroll", + "accountUserId": "account-user-1", + "clientId": "cli_123", + "deviceIdentitySha256Base64url": "47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU", + "challengeExpiresAt": 1_700_000_000, + }, + }) + ); + + let decoded = serde_json::from_value::(value) + .expect("deserialize device/key/sign params with enrollment payload"); + assert_eq!(decoded, params); + } + + #[test] + fn device_key_sign_response_returns_signed_payload_bytes() { + let response = DeviceKeySignResponse { + signature_der_base64: "MEUCIQD".to_string(), + signed_payload_base64: "eyJkb21haW4iOiJjb2RleA".to_string(), + algorithm: DeviceKeyAlgorithm::EcdsaP256Sha256, + }; + + let value = serde_json::to_value(&response).expect("serialize device/key/sign response"); + assert_eq!( + value, + json!({ + "signatureDerBase64": "MEUCIQD", + "signedPayloadBase64": "eyJkb21haW4iOiJjb2RleA", + "algorithm": "ecdsa_p256_sha256", + }) + ); + + let decoded = serde_json::from_value::(value) + .expect("deserialize device/key/sign response"); + assert_eq!(decoded, response); + } + #[test] fn fs_create_directory_params_round_trip_with_default_recursive() { let params = FsCreateDirectoryParams { @@ -7541,6 +8005,7 @@ mod tests { env: None, size: None, sandbox_policy: None, + permission_profile: None, } ); } @@ -7561,6 +8026,7 @@ mod tests { env: None, size: None, sandbox_policy: None, + permission_profile: None, }; let value = serde_json::to_value(¶ms).expect("serialize command/exec params"); @@ -7575,6 +8041,7 @@ mod tests { "env": null, "size": null, "sandboxPolicy": null, + "permissionProfile": null, "outputBytesCap": null, }) ); @@ -7600,6 +8067,7 @@ mod tests { env: None, size: None, sandbox_policy: None, + permission_profile: None, }; let value = serde_json::to_value(¶ms).expect("serialize command/exec params"); @@ -7616,6 +8084,7 @@ mod tests { "env": null, "size": null, "sandboxPolicy": null, + "permissionProfile": null, }) ); @@ -7644,6 +8113,7 @@ mod tests { ])), size: None, sandbox_policy: None, + permission_profile: None, }; let value = serde_json::to_value(¶ms).expect("serialize command/exec params"); @@ -7662,6 +8132,7 @@ mod tests { }, "size": null, "sandboxPolicy": null, + "permissionProfile": null, }) ); @@ -7731,6 +8202,7 @@ mod tests { cols: 120, }), sandbox_policy: None, + permission_profile: None, }; let value = serde_json::to_value(¶ms).expect("serialize command/exec params"); @@ -7749,6 +8221,7 @@ mod tests { "cols": 120, }, "sandboxPolicy": null, + "permissionProfile": null, }) ); @@ -9391,6 +9864,20 @@ mod tests { "approvalPolicy": "on-failure", "approvalsReviewer": "user", "sandbox": { "type": "dangerFullAccess" }, + "permissionProfile": { + "network": { "enabled": true }, + "fileSystem": { + "entries": [ + { + "path": { + "type": "special", + "value": { "kind": "root" } + }, + "access": "write" + } + ] + } + }, "reasoningEffort": null }); @@ -9430,6 +9917,7 @@ mod tests { approval_policy: None, approvals_reviewer: None, sandbox_policy: None, + permission_profile: None, model: None, service_tier: None, effort: None, diff --git a/codex-rs/app-server/Cargo.toml b/codex-rs/app-server/Cargo.toml index f354539640..ea49058e6c 100644 --- a/codex-rs/app-server/Cargo.toml +++ b/codex-rs/app-server/Cargo.toml @@ -72,8 +72,10 @@ serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } sha2 = { workspace = true } tempfile = { workspace = true } +thiserror = { workspace = true } time = { workspace = true } toml = { workspace = true } +toml_edit = { workspace = true } tokio = { workspace = true, features = [ "io-std", "macros", diff --git a/codex-rs/app-server/README.md b/codex-rs/app-server/README.md index 86221ec801..5cc2e47278 100644 --- a/codex-rs/app-server/README.md +++ b/codex-rs/app-server/README.md @@ -82,7 +82,7 @@ Use the thread APIs to create, list, or archive conversations. Drive a conversat - Initialize once per connection: Immediately after opening a transport connection, send an `initialize` request with your client metadata, then emit an `initialized` notification. Any other request on that connection before this handshake gets rejected. - Start (or resume) a thread: Call `thread/start` to open a fresh conversation. The response returns the thread object and you’ll also get a `thread/started` notification. If you’re continuing an existing conversation, call `thread/resume` with its ID instead. If you want to branch from an existing conversation, call `thread/fork` to create a new thread id with copied history. Like `thread/start`, `thread/fork` also accepts `ephemeral: true` for an in-memory temporary thread. The returned `thread.ephemeral` flag tells you whether the session is intentionally in-memory only; when it is `true`, `thread.path` is `null`. -- Begin a turn: To send user input, call `turn/start` with the target `threadId` and the user's input. Optional fields let you override model, cwd, sandbox policy, approval policy, approvals reviewer, etc. This immediately returns the new turn object. The app-server emits `turn/started` when that turn actually begins running. +- Begin a turn: To send user input, call `turn/start` with the target `threadId` and the user's input. Optional fields let you override model, cwd, sandbox policy or `permissionProfile`, approval policy, approvals reviewer, etc. This immediately returns the new turn object. The app-server emits `turn/started` when that turn actually begins running. - Stream events: After `turn/start`, keep reading JSON-RPC notifications on stdout. You’ll see `item/started`, `item/completed`, deltas like `item/agentMessage/delta`, tool progress, etc. These represent streaming model output plus any side effects (commands, tool calls, reasoning notes). - Finish the turn: When the model is done (or the turn is interrupted via making the `turn/interrupt` call), the server sends `turn/completed` with the final turn state and token usage. @@ -136,9 +136,9 @@ Example with notification opt-out: ## API Overview -- `thread/start` — create a new thread; emits `thread/started` (including the current `thread.status`) and auto-subscribes you to turn/item events for that thread. When the request includes a `cwd` and the resolved sandbox is `workspace-write` or full access, app-server also marks that project as trusted in the user `config.toml`. Pass `sessionStartSource: "clear"` when starting a replacement thread after clearing the current session so `SessionStart` hooks receive `source: "clear"` instead of the default `"startup"`. -- `thread/resume` — reopen an existing thread by id so subsequent `turn/start` calls append to it. -- `thread/fork` — fork an existing thread into a new thread id by copying the stored history; if the source thread is currently mid-turn, the fork records the same interruption marker as `turn/interrupt` instead of inheriting an unmarked partial turn suffix. The returned `thread.forkedFromId` points at the source thread when known. Accepts `ephemeral: true` for an in-memory temporary fork, emits `thread/started` (including the current `thread.status`), and auto-subscribes you to turn/item events for the new thread. +- `thread/start` — create a new thread; emits `thread/started` (including the current `thread.status`) and auto-subscribes you to turn/item events for that thread. When the request includes a `cwd` and the resolved sandbox is `workspace-write` or full access, app-server also marks that project as trusted in the user `config.toml`. Pass `sessionStartSource: "clear"` when starting a replacement thread after clearing the current session so `SessionStart` hooks receive `source: "clear"` instead of the default `"startup"`. For permissions, prefer `permissionProfile`; the legacy `sandbox` shorthand is still accepted but cannot be combined with `permissionProfile`. +- `thread/resume` — reopen an existing thread by id so subsequent `turn/start` calls append to it. Accepts the same permission override rules as `thread/start`. +- `thread/fork` — fork an existing thread into a new thread id by copying the stored history; if the source thread is currently mid-turn, the fork records the same interruption marker as `turn/interrupt` instead of inheriting an unmarked partial turn suffix. The returned `thread.forkedFromId` points at the source thread when known. Accepts `ephemeral: true` for an in-memory temporary fork, emits `thread/started` (including the current `thread.status`), and auto-subscribes you to turn/item events for the new thread. Accepts the same permission override rules as `thread/start`. - `thread/list` — page through stored rollouts; supports cursor-based pagination and optional `modelProviders`, `sourceKinds`, `archived`, `cwd`, and `searchTerm` filters. Each returned `thread` includes `status` (`ThreadStatus`), defaulting to `notLoaded` when the thread is not currently loaded. - `thread/loaded/list` — list the thread ids currently loaded in memory. - `thread/read` — read a stored thread by id without resuming it; optionally include turns via `includeTurns`. The returned `thread` includes `status` (`ThreadStatus`), defaulting to `notLoaded` when the thread is not currently loaded. @@ -155,7 +155,7 @@ Example with notification opt-out: - `thread/shellCommand` — run a user-initiated `!` shell command against a thread; this runs unsandboxed with full access rather than inheriting the thread sandbox policy. Returns `{}` immediately while progress streams through standard turn/item notifications and any active turn receives the formatted output in its message stream. - `thread/backgroundTerminals/clean` — terminate all running background terminals for a thread (experimental; requires `capabilities.experimentalApi`); returns `{}` when the cleanup request is accepted. - `thread/rollback` — drop the last N turns from the agent’s in-memory context and persist a rollback marker in the rollout so future resumes see the pruned history; returns the updated `thread` (with `turns` populated) on success. -- `turn/start` — add user input to a thread and begin Codex generation; responds with the initial `turn` object and streams `turn/started`, `item/*`, and `turn/completed` notifications. For `collaborationMode`, `settings.developer_instructions: null` means "use built-in instructions for the selected mode". +- `turn/start` — add user input to a thread and begin Codex generation; responds with the initial `turn` object and streams `turn/started`, `item/*`, and `turn/completed` notifications. Prefer `permissionProfile` for permission overrides; the legacy `sandboxPolicy` field is still accepted but cannot be combined with `permissionProfile`. For `collaborationMode`, `settings.developer_instructions: null` means "use built-in instructions for the selected mode". - `thread/inject_items` — append raw Responses API items to a loaded thread’s model-visible history without starting a user turn; returns `{}` on success. - `turn/steer` — add user input to an already in-flight regular turn without starting a new turn; returns the active `turnId` that accepted the input. Review and manual compaction turns reject `turn/steer`. - `turn/interrupt` — request cancellation of an in-flight turn by `(thread_id, turn_id)`; success is an empty `{}` response and the turn finishes with `status: "interrupted"`. @@ -220,6 +220,8 @@ Start a fresh thread when you need a new Codex conversation. "cwd": "/Users/me/project", "approvalPolicy": "never", "sandbox": "workspaceWrite", + // Prefer "permissionProfile" for full permission overrides. Do not send + // both "sandbox" and "permissionProfile". "personality": "friendly", "serviceName": "my_app_server_client", // optional metrics tag (`service_name`) "sessionStartSource": "startup", // optional: "startup" (default) or "clear" @@ -536,6 +538,8 @@ You can optionally specify config overrides on the new turn. If specified, these "writableRoots": ["/Users/me/project"], "networkAccess": true }, + // Prefer "permissionProfile" for full permission overrides. Do not send + // both "sandboxPolicy" and "permissionProfile". "model": "gpt-5.1-codex", "effort": "medium", "summary": "concise", @@ -806,7 +810,13 @@ Run a standalone command (argv vector) in the server’s sandbox without creatin "cwd": "/Users/me/project", // optional; defaults to server cwd "env": { "FOO": "override" }, // optional; merges into the server env and overrides matching names "size": { "rows": 40, "cols": 120 }, // optional; PTY size in character cells, only valid with tty=true - "sandboxPolicy": { "type": "workspaceWrite" }, // optional; defaults to user config + "permissionProfile": { // optional; defaults to user config + "fileSystem": { "entries": [ + { "path": { "type": "special", "value": { "kind": "root" } }, "access": "read" }, + { "path": { "type": "special", "value": { "kind": "current_working_directory" } }, "access": "write" } + ] }, + "network": { "enabled": false } + }, "outputBytesCap": 1048576, // optional; per-stream capture cap "disableOutputCap": false, // optional; cannot be combined with outputBytesCap "timeoutMs": 10000, // optional; ms timeout; defaults to server timeout @@ -819,12 +829,12 @@ Run a standalone command (argv vector) in the server’s sandbox without creatin } } ``` -- For clients that are already sandboxed externally, set `sandboxPolicy` to `{"type":"externalSandbox","networkAccess":"enabled"}` (or omit `networkAccess` to keep it restricted). Codex will not enforce its own sandbox in this mode; it tells the model it has full file-system access and passes the `networkAccess` state through `environment_context`. +- For clients that are already sandboxed externally, set the legacy `sandboxPolicy` to `{"type":"externalSandbox","networkAccess":"enabled"}` (or omit `networkAccess` to keep it restricted). Codex will not enforce its own sandbox in this mode; it tells the model it has full file-system access and passes the `networkAccess` state through `environment_context`. Notes: - Empty `command` arrays are rejected. -- `sandboxPolicy` accepts the same shape used by `turn/start` (e.g., `dangerFullAccess`, `readOnly`, `workspaceWrite` with flags, `externalSandbox` with `networkAccess` `restricted|enabled`). +- Prefer `permissionProfile` for command permission overrides. The legacy `sandboxPolicy` field accepts the same shape used by `turn/start` (e.g., `dangerFullAccess`, `readOnly`, `workspaceWrite` with flags, `externalSandbox` with `networkAccess` `restricted|enabled`), but cannot be combined with `permissionProfile`. - `env` merges into the environment produced by the server's shell environment policy. Matching names are overridden; unspecified variables are left intact. - When omitted, `timeoutMs` falls back to the server default. - When omitted, `outputBytesCap` falls back to the server default of 1 MiB per stream. diff --git a/codex-rs/app-server/src/codex_message_processor.rs b/codex-rs/app-server/src/codex_message_processor.rs index 7a2ada0765..acf8197cce 100644 --- a/codex-rs/app-server/src/codex_message_processor.rs +++ b/codex-rs/app-server/src/codex_message_processor.rs @@ -2,7 +2,7 @@ use crate::bespoke_event_handling::apply_bespoke_event_handling; use crate::bespoke_event_handling::maybe_emit_hook_prompt_item_completed; use crate::command_exec::CommandExecManager; use crate::command_exec::StartCommandExecParams; -use crate::config_api::apply_runtime_feature_enablement; +use crate::config_manager::ConfigManager; use crate::error_code::INPUT_TOO_LARGE_ERROR_CODE; use crate::error_code::INTERNAL_ERROR_CODE; use crate::error_code::INVALID_PARAMS_ERROR_CODE; @@ -102,6 +102,7 @@ use codex_app_server_protocol::MockExperimentalMethodParams; use codex_app_server_protocol::MockExperimentalMethodResponse; use codex_app_server_protocol::ModelListParams; use codex_app_server_protocol::ModelListResponse; +use codex_app_server_protocol::PermissionProfile as ApiPermissionProfile; use codex_app_server_protocol::PluginDetail; use codex_app_server_protocol::PluginInstallParams; use codex_app_server_protocol::PluginInstallResponse; @@ -212,8 +213,6 @@ use codex_arg0::Arg0DispatchPaths; use codex_backend_client::AddCreditsNudgeCreditType as BackendAddCreditsNudgeCreditType; use codex_backend_client::Client as BackendClient; use codex_chatgpt::connectors; -use codex_cloud_requirements::cloud_requirements_loader; -use codex_config::ThreadConfigLoader; use codex_config::types::McpServerTransportConfig; use codex_core::CodexThread; use codex_core::ForkSnapshot; @@ -231,9 +230,6 @@ use codex_core::config::edit::ConfigEdit; use codex_core::config::edit::ConfigEditsBuilder; use codex_core::config_loader::CloudRequirementsLoadError; use codex_core::config_loader::CloudRequirementsLoadErrorCode; -use codex_core::config_loader::CloudRequirementsLoader; -use codex_core::config_loader::LoaderOverrides; -use codex_core::config_loader::load_config_layers_state; use codex_core::config_loader::project_trust_key; use codex_core::exec::ExecCapturePolicy; use codex_core::exec::ExecExpiration; @@ -280,7 +276,6 @@ use codex_login::ServerOptions as LoginServerOptions; use codex_login::ShutdownHandle; use codex_login::auth::login_with_chatgpt_auth_tokens; use codex_login::complete_device_code_login; -use codex_login::default_client::set_default_client_residency_requirement; use codex_login::login_with_api_key; use codex_login::request_device_code; use codex_login::run_login_server; @@ -348,16 +343,13 @@ use codex_thread_store::ThreadStore; use codex_thread_store::ThreadStoreError; use codex_thread_store::UpdateThreadMetadataParams as StoreUpdateThreadMetadataParams; use codex_utils_absolute_path::AbsolutePathBuf; -use codex_utils_json_to_toml::json_to_toml; use codex_utils_pty::DEFAULT_OUTPUT_BYTES_CAP; -use std::collections::BTreeMap; use std::collections::HashMap; use std::collections::HashSet; use std::io::Error as IoError; use std::path::Path; use std::path::PathBuf; use std::sync::Arc; -use std::sync::RwLock; use std::sync::atomic::AtomicBool; use std::sync::atomic::Ordering; use std::time::Duration; @@ -478,10 +470,7 @@ pub(crate) struct CodexMessageProcessor { arg0_paths: Arg0DispatchPaths, config: Arc, thread_store: Arc, - cli_overrides: Arc>>, - runtime_feature_enablement: Arc>>, - cloud_requirements: Arc>, - thread_config_loader: Arc, + config_manager: ConfigManager, active_login: Arc>>, pending_thread_unloads: Arc>>, thread_state_manager: ThreadStateManager, @@ -638,11 +627,10 @@ pub(crate) struct CodexMessageProcessorArgs { pub(crate) outgoing: Arc, pub(crate) analytics_events_client: AnalyticsEventsClient, pub(crate) arg0_paths: Arg0DispatchPaths, + /// Startup config used as the process baseline. Fresh effective config loads + /// go through `config_manager`. pub(crate) config: Arc, - pub(crate) cli_overrides: Arc>>, - pub(crate) runtime_feature_enablement: Arc>>, - pub(crate) cloud_requirements: Arc>, - pub(crate) thread_config_loader: Arc, + pub(crate) config_manager: ConfigManager, pub(crate) feedback: CodexFeedback, pub(crate) log_db: Option, } @@ -727,10 +715,7 @@ impl CodexMessageProcessor { analytics_events_client, arg0_paths, config, - cli_overrides, - runtime_feature_enablement, - cloud_requirements, - thread_config_loader, + config_manager, feedback, log_db, } = args; @@ -742,10 +727,7 @@ impl CodexMessageProcessor { arg0_paths, thread_store: configured_thread_store(&config), config, - cli_overrides, - runtime_feature_enablement, - cloud_requirements, - thread_config_loader, + config_manager, active_login: Arc::new(Mutex::new(None)), pending_thread_unloads: Arc::new(Mutex::new(HashSet::new())), thread_state_manager: ThreadStateManager::new(), @@ -763,44 +745,14 @@ impl CodexMessageProcessor { &self, fallback_cwd: Option, ) -> Result { - let cloud_requirements = self.current_cloud_requirements(); - let mut config = codex_core::config::ConfigBuilder::default() - .cli_overrides(self.current_cli_overrides()) - .fallback_cwd(fallback_cwd) - .cloud_requirements(cloud_requirements) - .build() + self.config_manager + .load_latest_config(fallback_cwd) .await .map_err(|err| JSONRPCErrorError { code: INTERNAL_ERROR_CODE, message: format!("failed to reload config: {err}"), data: None, - })?; - apply_runtime_feature_enablement(&mut config, &self.current_runtime_feature_enablement()); - config.codex_self_exe = self.arg0_paths.codex_self_exe.clone(); - config.codex_linux_sandbox_exe = self.arg0_paths.codex_linux_sandbox_exe.clone(); - config.main_execve_wrapper_exe = self.arg0_paths.main_execve_wrapper_exe.clone(); - Ok(config) - } - - fn current_cloud_requirements(&self) -> CloudRequirementsLoader { - self.cloud_requirements - .read() - .map(|guard| guard.clone()) - .unwrap_or_default() - } - - fn current_cli_overrides(&self) -> Vec<(String, TomlValue)> { - self.cli_overrides - .read() - .map(|guard| guard.clone()) - .unwrap_or_default() - } - - fn current_runtime_feature_enablement(&self) -> BTreeMap { - self.runtime_feature_enablement - .read() - .map(|guard| guard.clone()) - .unwrap_or_default() + }) } /// If a client sends `developer_instructions: null` during a mode switch, @@ -1186,6 +1138,11 @@ impl CodexMessageProcessor { self.command_exec_terminate(to_connection_request_id(request_id), params) .await; } + ClientRequest::DeviceKeyCreate { .. } + | ClientRequest::DeviceKeyPublic { .. } + | ClientRequest::DeviceKeySign { .. } => { + warn!("Device key request reached CodexMessageProcessor unexpectedly"); + } ClientRequest::ConfigRead { .. } | ClientRequest::ConfigValueWrite { .. } | ClientRequest::ConfigBatchWrite { .. } @@ -1419,10 +1376,8 @@ impl CodexMessageProcessor { let outgoing_clone = self.outgoing.clone(); let active_login = self.active_login.clone(); let auth_manager = self.auth_manager.clone(); - let cloud_requirements = self.cloud_requirements.clone(); + let config_manager = self.config_manager.clone(); let chatgpt_base_url = self.config.chatgpt_base_url.clone(); - let codex_home = self.config.codex_home.to_path_buf(); - let cli_overrides = self.current_cli_overrides(); let auth_url = server.auth_url.clone(); tokio::spawn(async move { let (success, error_msg) = match tokio::time::timeout( @@ -1452,17 +1407,13 @@ impl CodexMessageProcessor { if success { auth_manager.reload(); - replace_cloud_requirements_loader( - cloud_requirements.as_ref(), + config_manager.replace_cloud_requirements_loader( auth_manager.clone(), chatgpt_base_url, - codex_home, ); - sync_default_client_residency_requirement( - &cli_overrides, - cloud_requirements.as_ref(), - ) - .await; + config_manager + .sync_default_client_residency_requirement() + .await; // Notify clients with the actual current auth mode. let auth = auth_manager.auth_cached(); @@ -1536,10 +1487,8 @@ impl CodexMessageProcessor { let outgoing_clone = self.outgoing.clone(); let active_login = self.active_login.clone(); let auth_manager = self.auth_manager.clone(); - let cloud_requirements = self.cloud_requirements.clone(); + let config_manager = self.config_manager.clone(); let chatgpt_base_url = self.config.chatgpt_base_url.clone(); - let codex_home = self.config.codex_home.to_path_buf(); - let cli_overrides = self.current_cli_overrides(); tokio::spawn(async move { let (success, error_msg) = tokio::select! { _ = cancel.cancelled() => { @@ -1566,17 +1515,13 @@ impl CodexMessageProcessor { if success { auth_manager.reload(); - replace_cloud_requirements_loader( - cloud_requirements.as_ref(), + config_manager.replace_cloud_requirements_loader( auth_manager.clone(), chatgpt_base_url, - codex_home, ); - sync_default_client_residency_requirement( - &cli_overrides, - cloud_requirements.as_ref(), - ) - .await; + config_manager + .sync_default_client_residency_requirement() + .await; let auth = auth_manager.auth_cached(); let payload_v2 = AccountUpdatedNotification { @@ -1706,14 +1651,12 @@ impl CodexMessageProcessor { return; } self.auth_manager.reload(); - replace_cloud_requirements_loader( - self.cloud_requirements.as_ref(), + self.config_manager.replace_cloud_requirements_loader( self.auth_manager.clone(), self.config.chatgpt_base_url.clone(), - self.config.codex_home.to_path_buf(), ); - let cli_overrides = self.current_cli_overrides(); - sync_default_client_residency_requirement(&cli_overrides, self.cloud_requirements.as_ref()) + self.config_manager + .sync_default_client_residency_requirement() .await; self.outgoing @@ -2121,7 +2064,16 @@ impl CodexMessageProcessor { env: env_overrides, size, sandbox_policy, + permission_profile, } = params; + if sandbox_policy.is_some() && permission_profile.is_some() { + self.send_invalid_request_error( + request_id, + "`permissionProfile` cannot be combined with `sandboxPolicy`".to_string(), + ) + .await; + return; + } if size.is_some() && !tty { let error = JSONRPCErrorError { @@ -2253,13 +2205,52 @@ impl CodexMessageProcessor { arg0: None, }; - let requested_policy = sandbox_policy.map(|policy| policy.to_core()); let ( effective_policy, effective_file_system_sandbox_policy, effective_network_sandbox_policy, - ) = match requested_policy { - Some(policy) => match self.config.permissions.sandbox_policy.can_set(&policy) { + ) = if let Some(permission_profile) = permission_profile { + let permission_profile = + codex_protocol::models::PermissionProfile::from(permission_profile); + let sandbox_policy = match permission_profile.to_legacy_sandbox_policy(&sandbox_cwd) { + Ok(sandbox_policy) => sandbox_policy, + Err(err) => { + let error = JSONRPCErrorError { + code: INVALID_REQUEST_ERROR_CODE, + message: format!("invalid permission profile: {err}"), + data: None, + }; + self.outgoing.send_error(request, error).await; + return; + } + }; + match self + .config + .permissions + .sandbox_policy + .can_set(&sandbox_policy) + { + Ok(()) => { + let (file_system_sandbox_policy, network_sandbox_policy) = + permission_profile.to_runtime_permissions(); + ( + sandbox_policy, + file_system_sandbox_policy, + network_sandbox_policy, + ) + } + Err(err) => { + let error = JSONRPCErrorError { + code: INVALID_REQUEST_ERROR_CODE, + message: format!("invalid permission profile: {err}"), + data: None, + }; + self.outgoing.send_error(request, error).await; + return; + } + } + } else if let Some(policy) = sandbox_policy.map(|policy| policy.to_core()) { + match self.config.permissions.sandbox_policy.can_set(&policy) { Ok(()) => { let file_system_sandbox_policy = codex_protocol::permissions::FileSystemSandboxPolicy::from_legacy_sandbox_policy(&policy, &sandbox_cwd); @@ -2276,12 +2267,13 @@ impl CodexMessageProcessor { self.outgoing.send_error(request, error).await; return; } - }, - None => ( + } + } else { + ( self.config.permissions.sandbox_policy.get().clone(), self.config.permissions.file_system_sandbox_policy.clone(), self.config.permissions.network_sandbox_policy, - ), + ) }; let codex_linux_sandbox_exe = self.arg0_paths.codex_linux_sandbox_exe.clone(); @@ -2399,6 +2391,7 @@ impl CodexMessageProcessor { approval_policy, approvals_reviewer, sandbox, + permission_profile, config, service_name, base_instructions, @@ -2411,6 +2404,14 @@ impl CodexMessageProcessor { session_start_source, persist_extended_history, } = params; + if sandbox.is_some() && permission_profile.is_some() { + self.send_invalid_request_error( + request_id, + "`permissionProfile` cannot be combined with `sandbox`".to_string(), + ) + .await; + return; + } let mut typesafe_overrides = self.build_thread_config_overrides( model, model_provider, @@ -2419,13 +2420,12 @@ impl CodexMessageProcessor { approval_policy, approvals_reviewer, sandbox, + permission_profile, base_instructions, developer_instructions, personality, ); typesafe_overrides.ephemeral = ephemeral; - let cloud_requirements = self.current_cloud_requirements(); - let cli_overrides = self.current_cli_overrides(); let listener_task_context = ListenerTaskContext { thread_manager: Arc::clone(&self.thread_manager), thread_state_manager: self.thread_state_manager.clone(), @@ -2438,15 +2438,11 @@ impl CodexMessageProcessor { codex_home: self.config.codex_home.to_path_buf(), }; let request_trace = request_context.request_trace(); - let runtime_feature_enablement = self.current_runtime_feature_enablement(); - let thread_config_loader = Arc::clone(&self.thread_config_loader); + let config_manager = self.config_manager.clone(); let thread_start_task = async move { Self::thread_start_task( listener_task_context, - cli_overrides, - runtime_feature_enablement, - cloud_requirements, - thread_config_loader, + config_manager, request_id, app_server_client_name, app_server_client_version, @@ -2520,10 +2516,7 @@ impl CodexMessageProcessor { #[allow(clippy::too_many_arguments)] async fn thread_start_task( listener_task_context: ListenerTaskContext, - cli_overrides: Vec<(String, TomlValue)>, - runtime_feature_enablement: BTreeMap, - cloud_requirements: CloudRequirementsLoader, - thread_config_loader: Arc, + config_manager: ConfigManager, request_id: ConnectionRequestId, app_server_client_name: Option, app_server_client_version: Option, @@ -2537,16 +2530,9 @@ impl CodexMessageProcessor { request_trace: Option, ) { let requested_cwd = typesafe_overrides.cwd.clone(); - let mut config = match derive_config_from_params( - &cli_overrides, - config_overrides.clone(), - typesafe_overrides.clone(), - Arc::clone(&thread_config_loader), - &cloud_requirements, - &listener_task_context.codex_home, - &runtime_feature_enablement, - ) - .await + let mut config = match config_manager + .load_with_overrides(config_overrides.clone(), typesafe_overrides.clone()) + .await { Ok(config) => config, Err(err) => { @@ -2585,6 +2571,7 @@ impl CodexMessageProcessor { let trust_target = resolve_root_git_project_for_trust(LOCAL_FS.as_ref(), &config.cwd) .await .unwrap_or_else(|| config.cwd.clone()); + let current_cli_overrides = config_manager.current_cli_overrides(); let cli_overrides_with_trust; let cli_overrides_for_reload = if let Err(err) = codex_core::config::set_project_trust_level( @@ -2606,7 +2593,7 @@ impl CodexMessageProcessor { project_trust_key(trust_target.as_path()), TomlValue::Table(project), ); - cli_overrides_with_trust = cli_overrides + cli_overrides_with_trust = current_cli_overrides .iter() .cloned() .chain(std::iter::once(( @@ -2616,19 +2603,17 @@ impl CodexMessageProcessor { .collect::>(); cli_overrides_with_trust.as_slice() } else { - &cli_overrides + current_cli_overrides.as_slice() }; - config = match derive_config_from_params( - cli_overrides_for_reload, - config_overrides, - typesafe_overrides, - thread_config_loader, - &cloud_requirements, - &listener_task_context.codex_home, - &runtime_feature_enablement, - ) - .await + config = match config_manager + .load_with_cli_overrides( + cli_overrides_for_reload, + config_overrides, + typesafe_overrides, + /*fallback_cwd*/ None, + ) + .await { Ok(config) => config, Err(err) => { @@ -2779,6 +2764,7 @@ impl CodexMessageProcessor { approval_policy: config_snapshot.approval_policy.into(), approvals_reviewer: config_snapshot.approvals_reviewer.into(), sandbox: config_snapshot.sandbox_policy.into(), + permission_profile: config_snapshot.permission_profile.into(), reasoning_effort: config_snapshot.reasoning_effort, }; if listener_task_context.general_analytics_enabled { @@ -2836,6 +2822,7 @@ impl CodexMessageProcessor { approval_policy: Option, approvals_reviewer: Option, sandbox: Option, + permission_profile: Option, base_instructions: Option, developer_instructions: Option, personality: Option, @@ -2850,6 +2837,7 @@ impl CodexMessageProcessor { approvals_reviewer: approvals_reviewer .map(codex_app_server_protocol::ApprovalsReviewer::to_core), sandbox_mode: sandbox.map(SandboxMode::to_core), + permission_profile: permission_profile.map(Into::into), codex_linux_sandbox_exe: self.arg0_paths.codex_linux_sandbox_exe.clone(), main_execve_wrapper_exe: self.arg0_paths.main_execve_wrapper_exe.clone(), base_instructions, @@ -4365,12 +4353,21 @@ impl CodexMessageProcessor { approval_policy, approvals_reviewer, sandbox, + permission_profile, config: mut request_overrides, base_instructions, developer_instructions, personality, persist_extended_history, } = params; + if sandbox.is_some() && permission_profile.is_some() { + self.send_invalid_request_error( + request_id, + "`permissionProfile` cannot be combined with `sandbox`".to_string(), + ) + .await; + return; + } let thread_history = if let Some(history) = history { let Some(thread_history) = self @@ -4399,6 +4396,7 @@ impl CodexMessageProcessor { approval_policy, approvals_reviewer, sandbox, + permission_profile, base_instructions, developer_instructions, personality, @@ -4412,19 +4410,10 @@ impl CodexMessageProcessor { .await; // Derive a Config using the same logic as new conversation, honoring overrides if provided. - let cloud_requirements = self.current_cloud_requirements(); - let cli_overrides = self.current_cli_overrides(); - let runtime_feature_enablement = self.current_runtime_feature_enablement(); - let config = match derive_config_for_cwd( - &cli_overrides, - request_overrides, - typesafe_overrides, - history_cwd, - &cloud_requirements, - &self.config.codex_home, - &runtime_feature_enablement, - ) - .await + let config = match self + .config_manager + .load_for_cwd(request_overrides, typesafe_overrides, history_cwd) + .await { Ok(config) => config, Err(err) => { @@ -4510,6 +4499,7 @@ impl CodexMessageProcessor { thread_status, /*has_live_in_progress_turn*/ false, ); + let permission_profile = codex_thread.config_snapshot().await.permission_profile; let response = ThreadResumeResponse { thread, @@ -4521,6 +4511,7 @@ impl CodexMessageProcessor { approval_policy: session_configured.approval_policy.into(), approvals_reviewer: session_configured.approvals_reviewer.into(), sandbox: session_configured.sandbox_policy.into(), + permission_profile: permission_profile.into(), reasoning_effort: session_configured.reasoning_effort, }; if self.config.features.enabled(Feature::GeneralAnalytics) { @@ -4904,12 +4895,21 @@ impl CodexMessageProcessor { approval_policy, approvals_reviewer, sandbox, + permission_profile, config: cli_overrides, base_instructions, developer_instructions, ephemeral, persist_extended_history, } = params; + if sandbox.is_some() && permission_profile.is_some() { + self.send_invalid_request_error( + request_id, + "`permissionProfile` cannot be combined with `sandbox`".to_string(), + ) + .await; + return; + } let (rollout_path, source_thread_id) = if let Some(path) = path { (path, None) @@ -4986,25 +4986,17 @@ impl CodexMessageProcessor { approval_policy, approvals_reviewer, sandbox, + permission_profile, base_instructions, developer_instructions, /*personality*/ None, ); typesafe_overrides.ephemeral = ephemeral.then_some(true); // Derive a Config using the same logic as new conversation, honoring overrides if provided. - let cloud_requirements = self.current_cloud_requirements(); - let cli_overrides = self.current_cli_overrides(); - let runtime_feature_enablement = self.current_runtime_feature_enablement(); - let config = match derive_config_for_cwd( - &cli_overrides, - request_overrides, - typesafe_overrides, - history_cwd, - &cloud_requirements, - &self.config.codex_home, - &runtime_feature_enablement, - ) - .await + let config = match self + .config_manager + .load_for_cwd(request_overrides, typesafe_overrides, history_cwd) + .await { Ok(config) => config, Err(err) => { @@ -5164,6 +5156,7 @@ impl CodexMessageProcessor { .await, /*has_in_progress_turn*/ false, ); + let permission_profile = forked_thread.config_snapshot().await.permission_profile; let response = ThreadForkResponse { thread: thread.clone(), @@ -5175,6 +5168,7 @@ impl CodexMessageProcessor { approval_policy: session_configured.approval_policy.into(), approvals_reviewer: session_configured.approvals_reviewer.into(), sandbox: session_configured.sandbox_policy.into(), + permission_profile: permission_profile.into(), reasoning_effort: session_configured.reasoning_effort, }; if self.config.features.enabled(Feature::GeneralAnalytics) { @@ -6041,17 +6035,19 @@ impl CodexMessageProcessor { params: McpServerToolCallParams, ) { let outgoing = Arc::clone(&self.outgoing); - let (_, thread) = match self.load_thread(¶ms.thread_id).await { + let thread_id = params.thread_id.clone(); + let (_, thread) = match self.load_thread(&thread_id).await { Ok(thread) => thread, Err(error) => { self.outgoing.send_error(request_id, error).await; return; } }; + let meta = with_mcp_tool_call_thread_id_meta(params.meta, &thread_id); tokio::spawn(async move { let result = thread - .call_mcp_tool(¶ms.server, ¶ms.tool, params.arguments, params.meta) + .call_mcp_tool(¶ms.server, ¶ms.tool, params.arguments, meta) .await; match result { Ok(result) => { @@ -6577,8 +6573,6 @@ impl CodexMessageProcessor { return; } }; - let cli_overrides = self.current_cli_overrides(); - let host_name = codex_config::host_name(); let mut data = Vec::new(); for cwd in cwds { let extra_roots = extra_roots_by_cwd @@ -6599,17 +6593,10 @@ impl CodexMessageProcessor { continue; } }; - let config_layer_stack = match load_config_layers_state( - LOCAL_FS.as_ref(), - &self.config.codex_home, - Some(cwd_abs.clone()), - &cli_overrides, - LoaderOverrides::default(), - CloudRequirementsLoader::default(), - self.thread_config_loader.as_ref(), - host_name.as_deref(), - ) - .await + let config_layer_stack = match self + .config_manager + .load_config_layers_for_cwd(cwd_abs.clone()) + .await { Ok(config_layer_stack) => config_layer_stack, Err(err) => { @@ -7303,6 +7290,7 @@ impl CodexMessageProcessor { || params.approval_policy.is_some() || params.approvals_reviewer.is_some() || params.sandbox_policy.is_some() + || params.permission_profile.is_some() || params.model.is_some() || params.service_tier.is_some() || params.effort.is_some() @@ -7310,6 +7298,15 @@ impl CodexMessageProcessor { || collaboration_mode.is_some() || params.personality.is_some(); + if params.sandbox_policy.is_some() && params.permission_profile.is_some() { + self.send_invalid_request_error( + request_id, + "`permissionProfile` cannot be combined with `sandboxPolicy`".to_string(), + ) + .await; + return; + } + // If any overrides are provided, update the session turn context first. if has_any_overrides { let _ = self @@ -7323,6 +7320,7 @@ impl CodexMessageProcessor { .approvals_reviewer .map(codex_app_server_protocol::ApprovalsReviewer::to_core), sandbox_policy: params.sandbox_policy.map(|p| p.to_core()), + permission_profile: params.permission_profile.map(Into::into), windows_sandbox_level: None, model: params.model, effort: params.effort.map(Some), @@ -8765,30 +8763,25 @@ impl CodexMessageProcessor { WindowsSandboxSetupMode::Unelevated => CoreWindowsSandboxSetupMode::Unelevated, }; let config = Arc::clone(&self.config); - let cloud_requirements = self.current_cloud_requirements(); + let config_manager = self.config_manager.clone(); let command_cwd = params .cwd .map(PathBuf::from) .unwrap_or_else(|| config.cwd.to_path_buf()); - let cli_overrides = self.current_cli_overrides(); - let runtime_feature_enablement = self.current_runtime_feature_enablement(); let outgoing = Arc::clone(&self.outgoing); let connection_id = request_id.connection_id; tokio::spawn(async move { - let derived_config = derive_config_for_cwd( - &cli_overrides, - /*request_overrides*/ None, - ConfigOverrides { - cwd: Some(command_cwd.clone()), - ..Default::default() - }, - Some(command_cwd.clone()), - &cloud_requirements, - &config.codex_home, - &runtime_feature_enablement, - ) - .await; + let derived_config = config_manager + .load_for_cwd( + /*request_overrides*/ None, + ConfigOverrides { + cwd: Some(command_cwd.clone()), + ..Default::default() + }, + Some(command_cwd.clone()), + ) + .await; let setup_result = match derived_config { Ok(config) => { let setup_request = WindowsSandboxSetupRequest { @@ -9042,6 +9035,7 @@ async fn handle_pending_thread_resume_request( approval_policy, approvals_reviewer, sandbox_policy, + permission_profile, cwd, reasoning_effort, .. @@ -9057,6 +9051,7 @@ async fn handle_pending_thread_resume_request( approval_policy: approval_policy.into(), approvals_reviewer: approvals_reviewer.into(), sandbox: sandbox_policy.into(), + permission_profile: permission_profile.into(), reasoning_effort, }; let token_usage_thread = response.thread.clone(); @@ -9241,6 +9236,16 @@ fn collect_resume_override_mismatches( )); } } + if let Some(requested_permission_profile) = request.permission_profile.as_ref() { + let requested_permission_profile = + codex_protocol::models::PermissionProfile::from(requested_permission_profile.clone()); + if requested_permission_profile != config_snapshot.permission_profile { + mismatch_details.push(format!( + "permission_profile requested={requested_permission_profile:?} active={:?}", + config_snapshot.permission_profile + )); + } + } if let Some(requested_personality) = request.personality.as_ref() && config_snapshot.personality.as_ref() != Some(requested_personality) { @@ -9518,116 +9523,6 @@ fn validate_dynamic_tools(tools: &[ApiDynamicToolSpec]) -> Result<(), String> { Ok(()) } -fn replace_cloud_requirements_loader( - cloud_requirements: &RwLock, - auth_manager: Arc, - chatgpt_base_url: String, - codex_home: PathBuf, -) { - let loader = cloud_requirements_loader(auth_manager, chatgpt_base_url, codex_home); - if let Ok(mut guard) = cloud_requirements.write() { - *guard = loader; - } else { - warn!("failed to update cloud requirements loader"); - } -} - -async fn sync_default_client_residency_requirement( - cli_overrides: &[(String, TomlValue)], - cloud_requirements: &RwLock, -) { - let loader = cloud_requirements - .read() - .map(|guard| guard.clone()) - .unwrap_or_default(); - match codex_core::config::ConfigBuilder::default() - .cli_overrides(cli_overrides.to_vec()) - .cloud_requirements(loader) - .build() - .await - { - Ok(config) => set_default_client_residency_requirement(config.enforce_residency.value()), - Err(err) => warn!( - error = %err, - "failed to sync default client residency requirement after auth refresh" - ), - } -} - -/// Derive the effective [`Config`] by layering three override sources. -/// -/// Precedence (lowest to highest): -/// - `cli_overrides`: process-wide startup `--config` flags. -/// - `request_overrides`: per-request dotted-path overrides (`params.config`), converted JSON->TOML. -/// - `typesafe_overrides`: Request objects such as `NewThreadParams` and -/// `ThreadStartParams` support a limited set of _explicit_ config overrides, so -/// `typesafe_overrides` is a `ConfigOverrides` derived from the respective request object. -/// Because the overrides are defined explicitly in the `*Params`, this takes priority over -/// the more general "bag of config options" provided by `cli_overrides` and `request_overrides`. -async fn derive_config_from_params( - cli_overrides: &[(String, TomlValue)], - request_overrides: Option>, - typesafe_overrides: ConfigOverrides, - thread_config_loader: Arc, - cloud_requirements: &CloudRequirementsLoader, - codex_home: &Path, - runtime_feature_enablement: &BTreeMap, -) -> std::io::Result { - let merged_cli_overrides = cli_overrides - .iter() - .cloned() - .chain( - request_overrides - .unwrap_or_default() - .into_iter() - .map(|(k, v)| (k, json_to_toml(v))), - ) - .collect::>(); - - let mut config = codex_core::config::ConfigBuilder::default() - .codex_home(codex_home.to_path_buf()) - .cli_overrides(merged_cli_overrides) - .harness_overrides(typesafe_overrides) - .cloud_requirements(cloud_requirements.clone()) - .thread_config_loader(thread_config_loader) - .build() - .await?; - apply_runtime_feature_enablement(&mut config, runtime_feature_enablement); - Ok(config) -} - -async fn derive_config_for_cwd( - cli_overrides: &[(String, TomlValue)], - request_overrides: Option>, - typesafe_overrides: ConfigOverrides, - cwd: Option, - cloud_requirements: &CloudRequirementsLoader, - codex_home: &Path, - runtime_feature_enablement: &BTreeMap, -) -> std::io::Result { - let merged_cli_overrides = cli_overrides - .iter() - .cloned() - .chain( - request_overrides - .unwrap_or_default() - .into_iter() - .map(|(k, v)| (k, json_to_toml(v))), - ) - .collect::>(); - - let mut config = codex_core::config::ConfigBuilder::default() - .codex_home(codex_home.to_path_buf()) - .cli_overrides(merged_cli_overrides) - .harness_overrides(typesafe_overrides) - .fallback_cwd(cwd) - .cloud_requirements(cloud_requirements.clone()) - .build() - .await?; - apply_runtime_feature_enablement(&mut config, runtime_feature_enablement); - Ok(config) -} - async fn read_history_cwd_from_state_db( config: &Config, thread_id: Option, @@ -9891,6 +9786,32 @@ fn thread_store_archive_error(operation: &str, err: ThreadStoreError) -> JSONRPC } } +const MCP_TOOL_THREAD_ID_META_KEY: &str = "threadId"; + +fn with_mcp_tool_call_thread_id_meta( + meta: Option, + thread_id: &str, +) -> Option { + match meta { + Some(serde_json::Value::Object(mut map)) => { + map.insert( + MCP_TOOL_THREAD_ID_META_KEY.to_string(), + serde_json::Value::String(thread_id.to_string()), + ); + Some(serde_json::Value::Object(map)) + } + None => { + let mut map = serde_json::Map::new(); + map.insert( + MCP_TOOL_THREAD_ID_META_KEY.to_string(), + serde_json::Value::String(thread_id.to_string()), + ); + Some(serde_json::Value::Object(map)) + } + other => other, + } +} + fn summary_from_stored_thread( thread: StoredThread, fallback_provider: &str, @@ -10523,6 +10444,8 @@ mod tests { use codex_config::SessionThreadConfig; use codex_config::StaticThreadConfigLoader; use codex_config::ThreadConfigSource; + use codex_core::config_loader::CloudRequirementsLoader; + use codex_core::config_loader::LoaderOverrides; use codex_model_provider_info::ModelProviderInfo; use codex_model_provider_info::WireApi; use codex_protocol::ThreadId; @@ -10536,8 +10459,10 @@ mod tests { use codex_utils_absolute_path::test_support::test_path_buf; use pretty_assertions::assert_eq; use serde_json::json; + use std::collections::BTreeMap; use std::path::PathBuf; use std::sync::Arc; + use std::sync::RwLock; use tempfile::TempDir; #[test] @@ -10811,21 +10736,13 @@ mod tests { requires_openai_auth: false, supports_websockets: true, }; - let config = derive_config_from_params( - &[], - Some(HashMap::from([ - ("model_provider".to_string(), json!("request")), - ("features.plugins".to_string(), json!(true)), - ( - "model_providers.session".to_string(), - json!({ - "name": "request", - "base_url": "http://127.0.0.1:9999/api/codex", - "wire_api": "responses", - }), - ), - ])), - ConfigOverrides::default(), + let config_manager = ConfigManager::new( + temp_dir.path().to_path_buf(), + Arc::new(RwLock::new(Vec::new())), + Arc::new(RwLock::new(BTreeMap::new())), + LoaderOverrides::default(), + Arc::new(RwLock::new(CloudRequirementsLoader::default())), + Arg0DispatchPaths::default(), Arc::new(StaticThreadConfigLoader::new(vec![ ThreadConfigSource::Session(SessionThreadConfig { model_provider: Some("session".to_string()), @@ -10836,11 +10753,24 @@ mod tests { features: BTreeMap::from([("plugins".to_string(), false)]), }), ])), - &CloudRequirementsLoader::default(), - temp_dir.path(), - &BTreeMap::new(), - ) - .await?; + ); + let config = config_manager + .load_with_overrides( + Some(HashMap::from([ + ("model_provider".to_string(), json!("request")), + ("features.plugins".to_string(), json!(true)), + ( + "model_providers.session".to_string(), + json!({ + "name": "request", + "base_url": "http://127.0.0.1:9999/api/codex", + "wire_api": "responses", + }), + ), + ])), + ConfigOverrides::default(), + ) + .await?; assert_eq!(config.model_provider_id, "session"); assert_eq!(config.model_provider, session_provider); @@ -10861,6 +10791,7 @@ mod tests { approval_policy: None, approvals_reviewer: None, sandbox: None, + permission_profile: None, config: None, base_instructions: None, developer_instructions: None, @@ -10874,6 +10805,11 @@ mod tests { approval_policy: codex_protocol::protocol::AskForApproval::OnRequest, approvals_reviewer: codex_protocol::config_types::ApprovalsReviewer::User, sandbox_policy: codex_protocol::protocol::SandboxPolicy::DangerFullAccess, + permission_profile: + codex_protocol::models::PermissionProfile::from_legacy_sandbox_policy( + &codex_protocol::protocol::SandboxPolicy::DangerFullAccess, + std::path::Path::new("/tmp"), + ), cwd: test_path_buf("/tmp").abs(), ephemeral: false, reasoning_effort: None, diff --git a/codex-rs/app-server/src/config_api.rs b/codex-rs/app-server/src/config_api.rs index c57d3893c1..ffccd6b1b2 100644 --- a/codex-rs/app-server/src/config_api.rs +++ b/codex-rs/app-server/src/config_api.rs @@ -1,3 +1,5 @@ +use crate::config_manager::ConfigManager; +use crate::config_manager_service::ConfigManagerError; use crate::error_code::INTERNAL_ERROR_CODE; use crate::error_code::INVALID_REQUEST_ERROR_CODE; use async_trait::async_trait; @@ -19,11 +21,7 @@ use codex_app_server_protocol::NetworkUnixSocketPermission; use codex_app_server_protocol::SandboxMode; use codex_core::ThreadManager; use codex_core::config::Config; -use codex_core::config::ConfigService; -use codex_core::config::ConfigServiceError; -use codex_core::config_loader::CloudRequirementsLoader; use codex_core::config_loader::ConfigRequirementsToml; -use codex_core::config_loader::LoaderOverrides; use codex_core::config_loader::ResidencyRequirement as CoreResidencyRequirement; use codex_core::config_loader::SandboxModeRequirement as CoreSandboxModeRequirement; use codex_core::plugins::PluginId; @@ -34,12 +32,8 @@ use codex_features::feature_for_key; use codex_protocol::config_types::WebSearchMode; use codex_protocol::protocol::Op; use serde_json::json; -use std::collections::BTreeMap; -use std::collections::BTreeSet; use std::path::PathBuf; use std::sync::Arc; -use std::sync::RwLock; -use toml::Value as TomlValue; use tracing::warn; const SUPPORTED_EXPERIMENTAL_FEATURE_ENABLEMENT: &[&str] = &[ @@ -72,86 +66,36 @@ impl UserConfigReloader for ThreadManager { #[derive(Clone)] pub(crate) struct ConfigApi { - codex_home: PathBuf, - cli_overrides: Arc>>, - runtime_feature_enablement: Arc>>, - loader_overrides: LoaderOverrides, - cloud_requirements: Arc>, + config_manager: ConfigManager, user_config_reloader: Arc, analytics_events_client: AnalyticsEventsClient, } impl ConfigApi { pub(crate) fn new( - codex_home: PathBuf, - cli_overrides: Arc>>, - runtime_feature_enablement: Arc>>, - loader_overrides: LoaderOverrides, - cloud_requirements: Arc>, + config_manager: ConfigManager, user_config_reloader: Arc, analytics_events_client: AnalyticsEventsClient, ) -> Self { Self { - codex_home, - cli_overrides, - runtime_feature_enablement, - loader_overrides, - cloud_requirements, + config_manager, user_config_reloader, analytics_events_client, } } - fn config_service(&self) -> ConfigService { - ConfigService::new( - self.codex_home.clone(), - self.current_cli_overrides(), - self.loader_overrides.clone(), - self.current_cloud_requirements(), - codex_config::host_name(), - ) - } - - fn current_cli_overrides(&self) -> Vec<(String, TomlValue)> { - self.cli_overrides - .read() - .map(|guard| guard.clone()) - .unwrap_or_default() - } - - fn current_runtime_feature_enablement(&self) -> BTreeMap { - self.runtime_feature_enablement - .read() - .map(|guard| guard.clone()) - .unwrap_or_default() - } - - fn current_cloud_requirements(&self) -> CloudRequirementsLoader { - self.cloud_requirements - .read() - .map(|guard| guard.clone()) - .unwrap_or_default() - } - pub(crate) async fn load_latest_config( &self, fallback_cwd: Option, ) -> Result { - let mut config = codex_core::config::ConfigBuilder::default() - .codex_home(self.codex_home.clone()) - .cli_overrides(self.current_cli_overrides()) - .loader_overrides(self.loader_overrides.clone()) - .fallback_cwd(fallback_cwd) - .cloud_requirements(self.current_cloud_requirements()) - .build() + self.config_manager + .load_latest_config(fallback_cwd) .await .map_err(|err| JSONRPCErrorError { code: INTERNAL_ERROR_CODE, message: format!("failed to resolve feature override precedence: {err}"), data: None, - })?; - apply_runtime_feature_enablement(&mut config, &self.current_runtime_feature_enablement()); - Ok(config) + }) } pub(crate) async fn read( @@ -159,11 +103,7 @@ impl ConfigApi { params: ConfigReadParams, ) -> Result { let fallback_cwd = params.cwd.as_ref().map(PathBuf::from); - let mut response = self - .config_service() - .read(params) - .await - .map_err(map_error)?; + let mut response = self.config_manager.read(params).await.map_err(map_error)?; let config = self.load_latest_config(fallback_cwd).await?; for feature_key in SUPPORTED_EXPERIMENTAL_FEATURE_ENABLEMENT { let Some(feature) = feature_for_key(feature_key) else { @@ -191,7 +131,7 @@ impl ConfigApi { &self, ) -> Result { let requirements = self - .config_service() + .config_manager .read_requirements() .await .map_err(map_error)? @@ -207,7 +147,7 @@ impl ConfigApi { let pending_changes = collect_plugin_enabled_candidates([(¶ms.key_path, ¶ms.value)].into_iter()); let response = self - .config_service() + .config_manager .write_value(params) .await .map_err(map_error)?; @@ -227,7 +167,7 @@ impl ConfigApi { .map(|edit| (&edit.key_path, &edit.value)), ); let response = self - .config_service() + .config_manager .batch_write(params) .await .map_err(map_error)?; @@ -278,21 +218,17 @@ impl ConfigApi { return Ok(ExperimentalFeatureEnablementSetResponse { enablement }); } - { - let mut runtime_feature_enablement = - self.runtime_feature_enablement - .write() - .map_err(|_| JSONRPCErrorError { - code: INTERNAL_ERROR_CODE, - message: "failed to update feature enablement".to_string(), - data: None, - })?; - runtime_feature_enablement.extend( + self.config_manager + .extend_runtime_feature_enablement( enablement .iter() .map(|(name, enabled)| (name.clone(), *enabled)), - ); - } + ) + .map_err(|_| JSONRPCErrorError { + code: INTERNAL_ERROR_CODE, + message: "failed to update feature enablement".to_string(), + data: None, + })?; self.load_latest_config(/*fallback_cwd*/ None).await?; self.user_config_reloader.reload_user_config().await; @@ -309,7 +245,8 @@ impl ConfigApi { continue; }; let metadata = - installed_plugin_telemetry_metadata(self.codex_home.as_path(), &plugin_id).await; + installed_plugin_telemetry_metadata(self.config_manager.codex_home(), &plugin_id) + .await; if enabled { self.analytics_events_client.track_plugin_enabled(metadata); } else { @@ -319,49 +256,6 @@ impl ConfigApi { } } -pub(crate) fn protected_feature_keys( - config_layer_stack: &codex_core::config_loader::ConfigLayerStack, -) -> BTreeSet { - let mut protected_features = config_layer_stack - .effective_config() - .get("features") - .and_then(toml::Value::as_table) - .map(|features| features.keys().cloned().collect::>()) - .unwrap_or_default(); - - if let Some(feature_requirements) = config_layer_stack - .requirements_toml() - .feature_requirements - .as_ref() - { - protected_features.extend(feature_requirements.entries.keys().cloned()); - } - - protected_features -} - -pub(crate) fn apply_runtime_feature_enablement( - config: &mut Config, - runtime_feature_enablement: &BTreeMap, -) { - let protected_features = protected_feature_keys(&config.config_layer_stack); - for (name, enabled) in runtime_feature_enablement { - if protected_features.contains(name) { - continue; - } - let Some(feature) = feature_for_key(name) else { - continue; - }; - if let Err(err) = config.features.set_enabled(feature, *enabled) { - warn!( - feature = name, - error = %err, - "failed to apply runtime feature enablement" - ); - } - } -} - fn map_requirements_toml_to_api(requirements: ConfigRequirementsToml) -> ConfigRequirements { ConfigRequirements { allowed_approval_policies: requirements.allowed_approval_policies.map(|policies| { @@ -495,7 +389,7 @@ fn map_network_unix_socket_permission_to_api( } } -fn map_error(err: ConfigServiceError) -> JSONRPCErrorError { +fn map_error(err: ConfigManagerError) -> JSONRPCErrorError { if let Some(code) = err.write_error_code() { return config_write_error(code, err.to_string()); } @@ -520,7 +414,11 @@ fn config_write_error(code: ConfigWriteErrorCode, message: impl Into) -> #[cfg(test)] mod tests { use super::*; + use crate::config_manager::apply_runtime_feature_enablement; use codex_analytics::AnalyticsEventsClient; + use codex_arg0::Arg0DispatchPaths; + use codex_core::config_loader::CloudRequirementsLoader; + use codex_core::config_loader::LoaderOverrides; use codex_core::config_loader::NetworkDomainPermissionToml as CoreNetworkDomainPermissionToml; use codex_core::config_loader::NetworkDomainPermissionsToml as CoreNetworkDomainPermissionsToml; use codex_core::config_loader::NetworkRequirementsToml as CoreNetworkRequirementsToml; @@ -533,9 +431,12 @@ mod tests { use codex_protocol::protocol::AskForApproval as CoreAskForApproval; use pretty_assertions::assert_eq; use serde_json::json; + use std::collections::BTreeMap; + use std::sync::RwLock; use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; use tempfile::TempDir; + use toml::Value as TomlValue; #[derive(Default)] struct RecordingUserConfigReloader { @@ -830,11 +731,15 @@ mod tests { ); let auth_manager = AuthManager::from_auth_for_testing(CodexAuth::from_api_key("test")); let config_api = ConfigApi::new( - codex_home.path().to_path_buf(), - Arc::new(RwLock::new(Vec::new())), - Arc::new(RwLock::new(BTreeMap::new())), - LoaderOverrides::default(), - Arc::new(RwLock::new(CloudRequirementsLoader::default())), + ConfigManager::new( + codex_home.path().to_path_buf(), + Arc::new(RwLock::new(Vec::new())), + Arc::new(RwLock::new(BTreeMap::new())), + LoaderOverrides::default(), + Arc::new(RwLock::new(CloudRequirementsLoader::default())), + Arg0DispatchPaths::default(), + Arc::new(codex_config::NoopThreadConfigLoader), + ), reloader.clone(), AnalyticsEventsClient::new( auth_manager, diff --git a/codex-rs/app-server/src/config_manager.rs b/codex-rs/app-server/src/config_manager.rs new file mode 100644 index 0000000000..67e0072f47 --- /dev/null +++ b/codex-rs/app-server/src/config_manager.rs @@ -0,0 +1,326 @@ +use codex_arg0::Arg0DispatchPaths; +use codex_cloud_requirements::cloud_requirements_loader; +use codex_config::ThreadConfigLoader; +use codex_core::config::Config; +use codex_core::config::ConfigOverrides; +use codex_core::config_loader::CloudRequirementsLoader; +use codex_core::config_loader::ConfigLayerStack; +use codex_core::config_loader::LoaderOverrides; +use codex_core::config_loader::load_config_layers_state; +use codex_exec_server::LOCAL_FS; +use codex_features::feature_for_key; +use codex_login::AuthManager; +use codex_login::default_client::set_default_client_residency_requirement; +use codex_utils_absolute_path::AbsolutePathBuf; +use codex_utils_json_to_toml::json_to_toml; +use std::collections::BTreeMap; +use std::collections::BTreeSet; +use std::collections::HashMap; +use std::path::Path; +use std::path::PathBuf; +use std::sync::Arc; +use std::sync::RwLock; +use toml::Value as TomlValue; +use tracing::warn; + +/// Shared app-server entry point for loading effective Codex configuration. +#[derive(Clone)] +pub(crate) struct ConfigManager { + codex_home: PathBuf, + cli_overrides: Arc>>, + runtime_feature_enablement: Arc>>, + loader_overrides: LoaderOverrides, + cloud_requirements: Arc>, + arg0_paths: Arg0DispatchPaths, + thread_config_loader: Arc, + host_name: Option, +} + +impl ConfigManager { + pub(crate) fn new( + codex_home: PathBuf, + cli_overrides: Arc>>, + runtime_feature_enablement: Arc>>, + loader_overrides: LoaderOverrides, + cloud_requirements: Arc>, + arg0_paths: Arg0DispatchPaths, + thread_config_loader: Arc, + ) -> Self { + Self::new_with_host_name( + codex_home, + cli_overrides, + runtime_feature_enablement, + loader_overrides, + cloud_requirements, + arg0_paths, + thread_config_loader, + codex_config::host_name(), + ) + } + + #[allow(clippy::too_many_arguments)] + fn new_with_host_name( + codex_home: PathBuf, + cli_overrides: Arc>>, + runtime_feature_enablement: Arc>>, + loader_overrides: LoaderOverrides, + cloud_requirements: Arc>, + arg0_paths: Arg0DispatchPaths, + thread_config_loader: Arc, + host_name: Option, + ) -> Self { + Self { + codex_home, + cli_overrides, + runtime_feature_enablement, + loader_overrides, + cloud_requirements, + arg0_paths, + thread_config_loader, + host_name, + } + } + + pub(crate) fn codex_home(&self) -> &Path { + self.codex_home.as_path() + } + + pub(crate) fn current_cli_overrides(&self) -> Vec<(String, TomlValue)> { + self.cli_overrides + .read() + .map(|guard| guard.clone()) + .unwrap_or_default() + } + + pub(crate) fn current_cloud_requirements(&self) -> CloudRequirementsLoader { + self.cloud_requirements + .read() + .map(|guard| guard.clone()) + .unwrap_or_default() + } + + pub(crate) fn extend_runtime_feature_enablement(&self, enablement: I) -> Result<(), ()> + where + I: IntoIterator, + { + let mut runtime_feature_enablement = + self.runtime_feature_enablement.write().map_err(|_| ())?; + runtime_feature_enablement.extend(enablement); + Ok(()) + } + + pub(crate) fn replace_cloud_requirements_loader( + &self, + auth_manager: Arc, + chatgpt_base_url: String, + ) { + let loader = + cloud_requirements_loader(auth_manager, chatgpt_base_url, self.codex_home.clone()); + if let Ok(mut guard) = self.cloud_requirements.write() { + *guard = loader; + } else { + warn!("failed to update cloud requirements loader"); + } + } + + pub(crate) async fn sync_default_client_residency_requirement(&self) { + match self.load_latest_config(/*fallback_cwd*/ None).await { + Ok(config) => { + set_default_client_residency_requirement(config.enforce_residency.value()); + } + Err(err) => warn!( + error = %err, + "failed to sync default client residency requirement after auth refresh" + ), + } + } + + pub(crate) async fn load_latest_config( + &self, + fallback_cwd: Option, + ) -> std::io::Result { + self.load_with_cli_overrides( + &self.current_cli_overrides(), + /*request_overrides*/ None, + ConfigOverrides::default(), + fallback_cwd, + ) + .await + } + + pub(crate) async fn load_with_overrides( + &self, + request_overrides: Option>, + typesafe_overrides: ConfigOverrides, + ) -> std::io::Result { + self.load_with_cli_overrides( + &self.current_cli_overrides(), + request_overrides, + typesafe_overrides, + /*fallback_cwd*/ None, + ) + .await + } + + pub(crate) async fn load_for_cwd( + &self, + request_overrides: Option>, + typesafe_overrides: ConfigOverrides, + cwd: Option, + ) -> std::io::Result { + self.load_with_cli_overrides( + &self.current_cli_overrides(), + request_overrides, + typesafe_overrides, + cwd, + ) + .await + } + + pub(crate) async fn load_with_cli_overrides( + &self, + cli_overrides: &[(String, TomlValue)], + request_overrides: Option>, + typesafe_overrides: ConfigOverrides, + fallback_cwd: Option, + ) -> std::io::Result { + let merged_cli_overrides = cli_overrides + .iter() + .cloned() + .chain( + request_overrides + .unwrap_or_default() + .into_iter() + .map(|(key, value)| (key, json_to_toml(value))), + ) + .collect::>(); + + let mut config = codex_core::config::ConfigBuilder::default() + .codex_home(self.codex_home.clone()) + .cli_overrides(merged_cli_overrides) + .loader_overrides(self.loader_overrides.clone()) + .harness_overrides(typesafe_overrides) + .fallback_cwd(fallback_cwd) + .cloud_requirements(self.current_cloud_requirements()) + .thread_config_loader(Arc::clone(&self.thread_config_loader)) + .host_name(self.host_name.clone()) + .build() + .await?; + self.apply_runtime_feature_enablement(&mut config); + self.apply_arg0_paths(&mut config); + Ok(config) + } + + pub(crate) async fn load_config_layers_for_cwd( + &self, + cwd: AbsolutePathBuf, + ) -> std::io::Result { + self.load_config_layers(Some(cwd)).await + } + + pub(crate) async fn load_config_layers( + &self, + cwd: Option, + ) -> std::io::Result { + load_config_layers_state( + LOCAL_FS.as_ref(), + &self.codex_home, + cwd, + &self.current_cli_overrides(), + self.loader_overrides.clone(), + self.current_cloud_requirements(), + self.thread_config_loader.as_ref(), + self.host_name.as_deref(), + ) + .await + } + + fn apply_runtime_feature_enablement(&self, config: &mut Config) { + apply_runtime_feature_enablement(config, &self.current_runtime_feature_enablement()); + } + + fn current_runtime_feature_enablement(&self) -> BTreeMap { + self.runtime_feature_enablement + .read() + .map(|guard| guard.clone()) + .unwrap_or_default() + } + + fn apply_arg0_paths(&self, config: &mut Config) { + config.codex_self_exe = self.arg0_paths.codex_self_exe.clone(); + config.codex_linux_sandbox_exe = self.arg0_paths.codex_linux_sandbox_exe.clone(); + config.main_execve_wrapper_exe = self.arg0_paths.main_execve_wrapper_exe.clone(); + } + + #[cfg(test)] + pub(crate) fn new_for_tests( + codex_home: PathBuf, + cli_overrides: Vec<(String, TomlValue)>, + loader_overrides: LoaderOverrides, + cloud_requirements: CloudRequirementsLoader, + host_name: Option, + ) -> Self { + Self::new_with_host_name( + codex_home, + Arc::new(RwLock::new(cli_overrides)), + Arc::new(RwLock::new(BTreeMap::new())), + loader_overrides, + Arc::new(RwLock::new(cloud_requirements)), + Arg0DispatchPaths::default(), + Arc::new(codex_config::NoopThreadConfigLoader), + host_name, + ) + } + + #[cfg(test)] + pub(crate) fn without_managed_config_for_tests(codex_home: PathBuf) -> Self { + Self::new_for_tests( + codex_home, + Vec::new(), + LoaderOverrides::without_managed_config_for_tests(), + CloudRequirementsLoader::default(), + /*host_name*/ None, + ) + } +} + +pub(crate) fn protected_feature_keys(config_layer_stack: &ConfigLayerStack) -> BTreeSet { + let mut protected_features = config_layer_stack + .effective_config() + .get("features") + .and_then(toml::Value::as_table) + .map(|features| features.keys().cloned().collect::>()) + .unwrap_or_default(); + + if let Some(feature_requirements) = config_layer_stack + .requirements_toml() + .feature_requirements + .as_ref() + { + protected_features.extend(feature_requirements.entries.keys().cloned()); + } + + protected_features +} + +pub(crate) fn apply_runtime_feature_enablement( + config: &mut Config, + runtime_feature_enablement: &BTreeMap, +) { + let protected_features = protected_feature_keys(&config.config_layer_stack); + for (name, enabled) in runtime_feature_enablement { + if protected_features.contains(name) { + continue; + } + let Some(feature) = feature_for_key(name) else { + continue; + }; + if let Err(err) = config.features.set_enabled(feature, *enabled) { + warn!( + feature = name, + error = %err, + "failed to apply runtime feature enablement" + ); + } + } +} diff --git a/codex-rs/core/src/config/service.rs b/codex-rs/app-server/src/config_manager_service.rs similarity index 74% rename from codex-rs/core/src/config/service.rs rename to codex-rs/app-server/src/config_manager_service.rs index e9546ef4db..0104429a4b 100644 --- a/codex-rs/core/src/config/service.rs +++ b/codex-rs/app-server/src/config_manager_service.rs @@ -1,20 +1,4 @@ -use super::deserialize_config_toml_with_base; -use crate::config::edit::ConfigEdit; -use crate::config::edit::ConfigEditsBuilder; -use crate::config::managed_features::validate_explicit_feature_settings_in_config_toml; -use crate::config::managed_features::validate_feature_requirements_in_config_toml; -use crate::config_loader::CloudRequirementsLoader; -use crate::config_loader::ConfigLayerEntry; -use crate::config_loader::ConfigLayerStack; -use crate::config_loader::ConfigLayerStackOrdering; -use crate::config_loader::ConfigRequirementsToml; -use crate::config_loader::LoaderOverrides; -use crate::config_loader::load_config_layers_state; -use crate::config_loader::merge_toml_values; -use crate::path_utils; -use crate::path_utils::SymlinkWritePaths; -use crate::path_utils::resolve_symlink_write_paths; -use crate::path_utils::write_atomically; +use crate::config_manager::ConfigManager; use codex_app_server_protocol::Config as ApiConfig; use codex_app_server_protocol::ConfigBatchWriteParams; use codex_app_server_protocol::ConfigLayerMetadata; @@ -29,7 +13,19 @@ use codex_app_server_protocol::OverriddenMetadata; use codex_app_server_protocol::WriteStatus; use codex_config::CONFIG_TOML_FILE; use codex_config::config_toml::ConfigToml; -use codex_exec_server::LOCAL_FS; +use codex_core::config::deserialize_config_toml_with_base; +use codex_core::config::edit::ConfigEdit; +use codex_core::config::edit::ConfigEditsBuilder; +use codex_core::config::validate_feature_requirements_for_config_toml; +use codex_core::config_loader::ConfigLayerEntry; +use codex_core::config_loader::ConfigLayerStack; +use codex_core::config_loader::ConfigLayerStackOrdering; +use codex_core::config_loader::ConfigRequirementsToml; +use codex_core::config_loader::merge_toml_values; +use codex_core::path_utils; +use codex_core::path_utils::SymlinkWritePaths; +use codex_core::path_utils::resolve_symlink_write_paths; +use codex_core::path_utils::write_atomically; use codex_utils_absolute_path::AbsolutePathBuf; use serde_json::Value as JsonValue; use std::borrow::Cow; @@ -41,7 +37,7 @@ use toml::Value as TomlValue; use toml_edit::Item as TomlItem; #[derive(Debug, Error)] -pub enum ConfigServiceError { +pub(crate) enum ConfigManagerError { #[error("{message}")] Write { code: ConfigWriteErrorCode, @@ -77,7 +73,7 @@ pub enum ConfigServiceError { }, } -impl ConfigServiceError { +impl ConfigManagerError { fn write(code: ConfigWriteErrorCode, message: impl Into) -> Self { Self::Write { code, @@ -101,7 +97,7 @@ impl ConfigServiceError { Self::Anyhow { context, source } } - pub fn write_error_code(&self) -> Option { + pub(crate) fn write_error_code(&self) -> Option { match self { Self::Write { code, .. } => Some(code.clone()), _ => None, @@ -109,78 +105,22 @@ impl ConfigServiceError { } } -#[derive(Clone)] -pub struct ConfigService { - codex_home: PathBuf, - cli_overrides: Vec<(String, TomlValue)>, - loader_overrides: LoaderOverrides, - cloud_requirements: CloudRequirementsLoader, - host_name: Option, -} - -impl ConfigService { - pub fn new( - codex_home: PathBuf, - cli_overrides: Vec<(String, TomlValue)>, - loader_overrides: LoaderOverrides, - cloud_requirements: CloudRequirementsLoader, - host_name: Option, - ) -> Self { - Self { - codex_home, - cli_overrides, - loader_overrides, - cloud_requirements, - host_name, - } - } - - pub fn new_with_defaults(codex_home: PathBuf) -> Self { - Self { - codex_home, - cli_overrides: Vec::new(), - loader_overrides: LoaderOverrides::default(), - cloud_requirements: CloudRequirementsLoader::default(), - host_name: codex_config::host_name(), - } - } - - #[cfg(test)] - pub(crate) fn without_managed_config_for_tests(codex_home: PathBuf) -> Self { - Self::new( - codex_home, - Vec::new(), - LoaderOverrides::without_managed_config_for_tests(), - CloudRequirementsLoader::default(), - /*host_name*/ None, - ) - } - - pub async fn read( +impl ConfigManager { + pub(crate) async fn read( &self, params: ConfigReadParams, - ) -> Result { + ) -> Result { let layers = match params.cwd.as_deref() { Some(cwd) => { let cwd = AbsolutePathBuf::try_from(PathBuf::from(cwd)).map_err(|err| { - ConfigServiceError::io("failed to resolve config cwd to an absolute path", err) + ConfigManagerError::io("failed to resolve config cwd to an absolute path", err) })?; - crate::config::ConfigBuilder::default() - .codex_home(self.codex_home.clone()) - .cli_overrides(self.cli_overrides.clone()) - .loader_overrides(self.loader_overrides.clone()) - .fallback_cwd(Some(cwd.to_path_buf())) - .cloud_requirements(self.cloud_requirements.clone()) - .host_name(self.host_name.clone()) - .build() - .await - .map_err(|err| { - ConfigServiceError::io("failed to read configuration layers", err) - })? - .config_layer_stack + self.load_config_layers(Some(cwd)).await.map_err(|err| { + ConfigManagerError::io("failed to read configuration layers", err) + })? } None => self.load_thread_agnostic_config().await.map_err(|err| { - ConfigServiceError::io("failed to read configuration layers", err) + ConfigManagerError::io("failed to read configuration layers", err) })?, }; @@ -188,12 +128,12 @@ impl ConfigService { let effective_config_toml: ConfigToml = effective .try_into() - .map_err(|err| ConfigServiceError::toml("invalid configuration", err))?; + .map_err(|err| ConfigManagerError::toml("invalid configuration", err))?; let json_value = serde_json::to_value(&effective_config_toml) - .map_err(|err| ConfigServiceError::json("failed to serialize configuration", err))?; + .map_err(|err| ConfigManagerError::json("failed to serialize configuration", err))?; let config: ApiConfig = serde_json::from_value(json_value) - .map_err(|err| ConfigServiceError::json("failed to deserialize configuration", err))?; + .map_err(|err| ConfigManagerError::json("failed to deserialize configuration", err))?; Ok(ConfigReadResponse { config, @@ -211,13 +151,13 @@ impl ConfigService { }) } - pub async fn read_requirements( + pub(crate) async fn read_requirements( &self, - ) -> Result, ConfigServiceError> { + ) -> Result, ConfigManagerError> { let layers = self .load_thread_agnostic_config() .await - .map_err(|err| ConfigServiceError::io("failed to read configuration layers", err))?; + .map_err(|err| ConfigManagerError::io("failed to read configuration layers", err))?; let requirements = layers.requirements_toml().clone(); if requirements.is_empty() { @@ -227,19 +167,19 @@ impl ConfigService { } } - pub async fn write_value( + pub(crate) async fn write_value( &self, params: ConfigValueWriteParams, - ) -> Result { + ) -> Result { let edits = vec![(params.key_path, params.value, params.merge_strategy)]; self.apply_edits(params.file_path, params.expected_version, edits) .await } - pub async fn batch_write( + pub(crate) async fn batch_write( &self, params: ConfigBatchWriteParams, - ) -> Result { + ) -> Result { let edits = params .edits .into_iter() @@ -250,37 +190,22 @@ impl ConfigService { .await } - pub async fn load_user_saved_config( - &self, - ) -> Result { - let layers = self - .load_thread_agnostic_config() - .await - .map_err(|err| ConfigServiceError::io("failed to load configuration", err))?; - - let toml_value = layers.effective_config(); - let cfg: ConfigToml = toml_value - .try_into() - .map_err(|err| ConfigServiceError::toml("failed to parse config.toml", err))?; - Ok(cfg.into()) - } - async fn apply_edits( &self, file_path: Option, expected_version: Option, edits: Vec<(String, JsonValue, MergeStrategy)>, - ) -> Result { + ) -> Result { let allowed_path = - AbsolutePathBuf::resolve_path_against_base(CONFIG_TOML_FILE, &self.codex_home); + AbsolutePathBuf::resolve_path_against_base(CONFIG_TOML_FILE, self.codex_home()); let provided_path = match file_path { Some(path) => AbsolutePathBuf::from_absolute_path(PathBuf::from(path)) - .map_err(|err| ConfigServiceError::io("failed to resolve user config path", err))?, + .map_err(|err| ConfigManagerError::io("failed to resolve user config path", err))?, None => allowed_path.clone(), }; if !paths_match(&allowed_path, &provided_path) { - return Err(ConfigServiceError::write( + return Err(ConfigManagerError::write( ConfigWriteErrorCode::ConfigLayerReadonly, "Only writes to the user config are allowed", )); @@ -289,7 +214,7 @@ impl ConfigService { let layers = self .load_thread_agnostic_config() .await - .map_err(|err| ConfigServiceError::io("failed to load configuration", err))?; + .map_err(|err| ConfigManagerError::io("failed to load configuration", err))?; let user_layer = match layers.get_user_layer() { Some(layer) => Cow::Borrowed(layer), None => Cow::Owned(create_empty_user_layer(&allowed_path).await?), @@ -298,7 +223,7 @@ impl ConfigService { if let Some(expected) = expected_version.as_deref() && expected != user_layer.version { - return Err(ConfigServiceError::write( + return Err(ConfigManagerError::write( ConfigWriteErrorCode::ConfigVersionConflict, "Configuration was modified since last read. Fetch latest version and retry.", )); @@ -310,20 +235,20 @@ impl ConfigService { for (key_path, value, strategy) in edits.into_iter() { let segments = parse_key_path(&key_path).map_err(|message| { - ConfigServiceError::write(ConfigWriteErrorCode::ConfigValidationError, message) + ConfigManagerError::write(ConfigWriteErrorCode::ConfigValidationError, message) })?; let original_value = value_at_path(&user_config, &segments).cloned(); let parsed_value = parse_value(value).map_err(|message| { - ConfigServiceError::write(ConfigWriteErrorCode::ConfigValidationError, message) + ConfigManagerError::write(ConfigWriteErrorCode::ConfigValidationError, message) })?; apply_merge(&mut user_config, &segments, parsed_value.as_ref(), strategy).map_err( |err| match err { - MergeError::PathNotFound => ConfigServiceError::write( + MergeError::PathNotFound => ConfigManagerError::write( ConfigWriteErrorCode::ConfigPathNotFound, "Path not found", ), - MergeError::Validation(message) => ConfigServiceError::write( + MergeError::Validation(message) => ConfigManagerError::write( ConfigWriteErrorCode::ConfigValidationError, message, ), @@ -336,7 +261,7 @@ impl ConfigService { Some(value) => ConfigEdit::SetPath { segments: segments.clone(), value: toml_value_to_item(&value).map_err(|err| { - ConfigServiceError::anyhow("failed to build config edits", err) + ConfigManagerError::anyhow("failed to build config edits", err) })?, }, None => ConfigEdit::ClearPath { @@ -350,56 +275,45 @@ impl ConfigService { } validate_config(&user_config).map_err(|err| { - ConfigServiceError::write( + ConfigManagerError::write( ConfigWriteErrorCode::ConfigValidationError, format!("Invalid configuration: {err}"), ) })?; let user_config_toml = - deserialize_config_toml_with_base(user_config.clone(), &self.codex_home).map_err( + deserialize_config_toml_with_base(user_config.clone(), self.codex_home()).map_err( |err| { - ConfigServiceError::write( + ConfigManagerError::write( ConfigWriteErrorCode::ConfigValidationError, format!("Invalid configuration: {err}"), ) }, )?; - validate_explicit_feature_settings_in_config_toml( + validate_feature_requirements_for_config_toml( &user_config_toml, layers.requirements().feature_requirements.as_ref(), ) .map_err(|err| { - ConfigServiceError::write( + ConfigManagerError::write( ConfigWriteErrorCode::ConfigValidationError, format!("Invalid configuration: {err}"), ) })?; - validate_feature_requirements_in_config_toml( - &user_config_toml, - layers.requirements().feature_requirements.as_ref(), - ) - .map_err(|err| { - ConfigServiceError::write( - ConfigWriteErrorCode::ConfigValidationError, - format!("Invalid configuration: {err}"), - ) - })?; - let updated_layers = layers.with_user_config(&provided_path, user_config.clone()); let effective = updated_layers.effective_config(); validate_config(&effective).map_err(|err| { - ConfigServiceError::write( + ConfigManagerError::write( ConfigWriteErrorCode::ConfigValidationError, format!("Invalid configuration: {err}"), ) })?; if !config_edits.is_empty() { - ConfigEditsBuilder::new(&self.codex_home) + ConfigEditsBuilder::new(self.codex_home()) .with_edits(config_edits) .apply() .await - .map_err(|err| ConfigServiceError::anyhow("failed to persist config.toml", err))?; + .map_err(|err| ConfigManagerError::anyhow("failed to persist config.toml", err))?; } let overridden = first_overridden_edit(&updated_layers, &effective, &parsed_segments); @@ -413,7 +327,7 @@ impl ConfigService { version: updated_layers .get_user_layer() .ok_or_else(|| { - ConfigServiceError::write( + ConfigManagerError::write( ConfigWriteErrorCode::UserLayerNotFound, "user layer not found in updated layers", ) @@ -429,40 +343,29 @@ impl ConfigService { /// include any in-repo .codex/ folders because there is no cwd/project root /// associated with this query. async fn load_thread_agnostic_config(&self) -> std::io::Result { - let cwd: Option = None; - load_config_layers_state( - LOCAL_FS.as_ref(), - &self.codex_home, - cwd, - &self.cli_overrides, - self.loader_overrides.clone(), - self.cloud_requirements.clone(), - &codex_config::NoopThreadConfigLoader, - self.host_name.as_deref(), - ) - .await + self.load_config_layers(/*cwd*/ None).await } } async fn create_empty_user_layer( config_toml: &AbsolutePathBuf, -) -> Result { +) -> Result { let SymlinkWritePaths { read_path, write_path, } = resolve_symlink_write_paths(config_toml.as_path()) - .map_err(|err| ConfigServiceError::io("failed to resolve user config path", err))?; + .map_err(|err| ConfigManagerError::io("failed to resolve user config path", err))?; let toml_value = match read_path { Some(path) => match tokio::fs::read_to_string(&path).await { Ok(contents) => toml::from_str(&contents).map_err(|e| { - ConfigServiceError::toml("failed to parse existing user config.toml", e) + ConfigManagerError::toml("failed to parse existing user config.toml", e) })?, Err(err) if err.kind() == std::io::ErrorKind::NotFound => { write_empty_user_config(write_path.clone()).await?; TomlValue::Table(toml::map::Map::new()) } Err(err) => { - return Err(ConfigServiceError::io( + return Err(ConfigManagerError::io( "failed to read user config.toml", err, )); @@ -481,11 +384,11 @@ async fn create_empty_user_layer( )) } -async fn write_empty_user_config(write_path: PathBuf) -> Result<(), ConfigServiceError> { +async fn write_empty_user_config(write_path: PathBuf) -> Result<(), ConfigManagerError> { task::spawn_blocking(move || write_atomically(&write_path, "")) .await - .map_err(|err| ConfigServiceError::anyhow("config persistence task panicked", err.into()))? - .map_err(|err| ConfigServiceError::io("failed to create empty user config.toml", err)) + .map_err(|err| ConfigManagerError::anyhow("config persistence task panicked", err.into()))? + .map_err(|err| ConfigManagerError::io("failed to create empty user config.toml", err)) } fn parse_value(value: JsonValue) -> Result, String> { @@ -746,5 +649,5 @@ fn find_effective_layer( } #[cfg(test)] -#[path = "service_tests.rs"] +#[path = "config_manager_service_tests.rs"] mod tests; diff --git a/codex-rs/core/src/config/service_tests.rs b/codex-rs/app-server/src/config_manager_service_tests.rs similarity index 95% rename from codex-rs/core/src/config/service_tests.rs rename to codex-rs/app-server/src/config_manager_service_tests.rs index ceb801c456..a871d8e43f 100644 --- a/codex-rs/core/src/config/service_tests.rs +++ b/codex-rs/app-server/src/config_manager_service_tests.rs @@ -4,6 +4,9 @@ use codex_app_server_protocol::AppConfig; use codex_app_server_protocol::AppToolApproval; use codex_app_server_protocol::AppsConfig; use codex_app_server_protocol::AskForApproval; +use codex_core::config_loader::CloudRequirementsLoader; +use codex_core::config_loader::FeatureRequirementsToml; +use codex_core::config_loader::LoaderOverrides; use codex_utils_absolute_path::AbsolutePathBuf; use pretty_assertions::assert_eq; use std::collections::BTreeMap; @@ -74,7 +77,7 @@ unified_exec = true "#; std::fs::write(tmp.path().join(CONFIG_TOML_FILE), original)?; - let service = ConfigService::without_managed_config_for_tests(tmp.path().to_path_buf()); + let service = ConfigManager::without_managed_config_for_tests(tmp.path().to_path_buf()); service .write_value(ConfigValueWriteParams { file_path: Some(tmp.path().join(CONFIG_TOML_FILE).display().to_string()), @@ -108,7 +111,7 @@ async fn write_value_supports_nested_app_paths() -> Result<()> { let tmp = tempdir().expect("tempdir"); std::fs::write(tmp.path().join(CONFIG_TOML_FILE), "")?; - let service = ConfigService::without_managed_config_for_tests(tmp.path().to_path_buf()); + let service = ConfigManager::without_managed_config_for_tests(tmp.path().to_path_buf()); service .write_value(ConfigValueWriteParams { file_path: Some(tmp.path().join(CONFIG_TOML_FILE).display().to_string()), @@ -172,7 +175,7 @@ async fn write_value_supports_custom_mcp_server_default_tool_approval_mode() -> "[mcp_servers.docs]\ncommand = \"docs-server\"\n", )?; - let service = ConfigService::without_managed_config_for_tests(tmp.path().to_path_buf()); + let service = ConfigManager::without_managed_config_for_tests(tmp.path().to_path_buf()); service .write_value(ConfigValueWriteParams { file_path: Some(tmp.path().join(CONFIG_TOML_FILE).display().to_string()), @@ -218,7 +221,7 @@ async fn read_includes_origins_and_layers() { std::fs::write(&managed_path, "approval_policy = \"never\"").unwrap(); let managed_file = AbsolutePathBuf::try_from(managed_path.clone()).expect("managed file"); - let service = ConfigService::new( + let service = ConfigManager::new_for_tests( tmp.path().to_path_buf(), vec![], LoaderOverrides::with_managed_config_path_for_tests(managed_path.clone()), @@ -297,7 +300,7 @@ writable_roots = ["~/code"] ), ); - let service = ConfigService::new( + let service = ConfigManager::new_for_tests( tmp.path().to_path_buf(), vec![], loader_overrides, @@ -338,7 +341,7 @@ async fn write_value_reports_override() { std::fs::write(&managed_path, "approval_policy = \"never\"").unwrap(); let managed_file = AbsolutePathBuf::try_from(managed_path.clone()).expect("managed file"); - let service = ConfigService::new( + let service = ConfigManager::new_for_tests( tmp.path().to_path_buf(), vec![], LoaderOverrides::with_managed_config_path_for_tests(managed_path.clone()), @@ -388,7 +391,7 @@ async fn version_conflict_rejected() { let user_path = tmp.path().join(CONFIG_TOML_FILE); std::fs::write(&user_path, "model = \"user\"").unwrap(); - let service = ConfigService::without_managed_config_for_tests(tmp.path().to_path_buf()); + let service = ConfigManager::without_managed_config_for_tests(tmp.path().to_path_buf()); let error = service .write_value(ConfigValueWriteParams { file_path: Some(tmp.path().join(CONFIG_TOML_FILE).display().to_string()), @@ -411,7 +414,7 @@ async fn write_value_defaults_to_user_config_path() { let tmp = tempdir().expect("tempdir"); std::fs::write(tmp.path().join(CONFIG_TOML_FILE), "").unwrap(); - let service = ConfigService::without_managed_config_for_tests(tmp.path().to_path_buf()); + let service = ConfigManager::without_managed_config_for_tests(tmp.path().to_path_buf()); service .write_value(ConfigValueWriteParams { file_path: None, @@ -438,7 +441,7 @@ async fn invalid_user_value_rejected_even_if_overridden_by_managed() { let managed_path = tmp.path().join("managed_config.toml"); std::fs::write(&managed_path, "approval_policy = \"never\"").unwrap(); - let service = ConfigService::new( + let service = ConfigManager::new_for_tests( tmp.path().to_path_buf(), vec![], LoaderOverrides::with_managed_config_path_for_tests(managed_path.clone()), @@ -471,7 +474,7 @@ async fn reserved_builtin_provider_override_rejected() { let tmp = tempdir().expect("tempdir"); std::fs::write(tmp.path().join(CONFIG_TOML_FILE), "model = \"user\"\n").unwrap(); - let service = ConfigService::without_managed_config_for_tests(tmp.path().to_path_buf()); + let service = ConfigManager::without_managed_config_for_tests(tmp.path().to_path_buf()); let error = service .write_value(ConfigValueWriteParams { file_path: Some(tmp.path().join(CONFIG_TOML_FILE).display().to_string()), @@ -499,13 +502,13 @@ async fn write_value_rejects_feature_requirement_conflict() { let tmp = tempdir().expect("tempdir"); std::fs::write(tmp.path().join(CONFIG_TOML_FILE), "").unwrap(); - let service = ConfigService::new( + let service = ConfigManager::new_for_tests( tmp.path().to_path_buf(), vec![], LoaderOverrides::without_managed_config_for_tests(), CloudRequirementsLoader::new(async { Ok(Some(ConfigRequirementsToml { - feature_requirements: Some(crate::config_loader::FeatureRequirementsToml { + feature_requirements: Some(FeatureRequirementsToml { entries: BTreeMap::from([("personality".to_string(), true)]), }), ..Default::default() @@ -546,13 +549,13 @@ async fn write_value_rejects_profile_feature_requirement_conflict() { let tmp = tempdir().expect("tempdir"); std::fs::write(tmp.path().join(CONFIG_TOML_FILE), "").unwrap(); - let service = ConfigService::new( + let service = ConfigManager::new_for_tests( tmp.path().to_path_buf(), vec![], LoaderOverrides::without_managed_config_for_tests(), CloudRequirementsLoader::new(async { Ok(Some(ConfigRequirementsToml { - feature_requirements: Some(crate::config_loader::FeatureRequirementsToml { + feature_requirements: Some(FeatureRequirementsToml { entries: BTreeMap::from([("personality".to_string(), true)]), }), ..Default::default() @@ -604,7 +607,7 @@ async fn read_reports_managed_overrides_user_and_session_flags() { TomlValue::String("session".to_string()), )]; - let service = ConfigService::new( + let service = ConfigManager::new_for_tests( tmp.path().to_path_buf(), cli_overrides, LoaderOverrides::with_managed_config_path_for_tests(managed_path.clone()), @@ -658,7 +661,7 @@ async fn write_value_reports_managed_override() { std::fs::write(&managed_path, "approval_policy = \"never\"").unwrap(); let managed_file = AbsolutePathBuf::try_from(managed_path.clone()).expect("managed file"); - let service = ConfigService::new( + let service = ConfigManager::new_for_tests( tmp.path().to_path_buf(), vec![], LoaderOverrides::with_managed_config_path_for_tests(managed_path.clone()), @@ -714,7 +717,7 @@ alpha = "a" std::fs::write(&path, base)?; - let service = ConfigService::without_managed_config_for_tests(tmp.path().to_path_buf()); + let service = ConfigManager::without_managed_config_for_tests(tmp.path().to_path_buf()); service .write_value(ConfigValueWriteParams { file_path: Some(path.display().to_string()), diff --git a/codex-rs/app-server/src/lib.rs b/codex-rs/app-server/src/lib.rs index 0eac54df2a..d4573b267a 100644 --- a/codex-rs/app-server/src/lib.rs +++ b/codex-rs/app-server/src/lib.rs @@ -72,6 +72,8 @@ mod codex_message_processor; mod command_exec; mod config; mod config_api; +mod config_manager; +mod config_manager_service; mod dynamic_tools; mod error_code; mod external_agent_config_api; diff --git a/codex-rs/app-server/src/message_processor.rs b/codex-rs/app-server/src/message_processor.rs index 2032eb61cd..53d9f2df4c 100644 --- a/codex-rs/app-server/src/message_processor.rs +++ b/codex-rs/app-server/src/message_processor.rs @@ -10,6 +10,7 @@ use std::sync::atomic::Ordering; use crate::codex_message_processor::CodexMessageProcessor; use crate::codex_message_processor::CodexMessageProcessorArgs; use crate::config_api::ConfigApi; +use crate::config_manager::ConfigManager; use crate::error_code::INVALID_REQUEST_ERROR_CODE; use crate::external_agent_config_api::ExternalAgentConfigApi; use crate::fs_api::FsApi; @@ -294,6 +295,15 @@ impl MessageProcessor { let cli_overrides = Arc::new(RwLock::new(cli_overrides)); let runtime_feature_enablement = Arc::new(RwLock::new(BTreeMap::new())); let cloud_requirements = Arc::new(RwLock::new(cloud_requirements)); + let config_manager = ConfigManager::new( + config.codex_home.to_path_buf(), + cli_overrides, + runtime_feature_enablement, + loader_overrides, + cloud_requirements, + arg0_paths.clone(), + thread_config_loader, + ); let codex_message_processor = CodexMessageProcessor::new(CodexMessageProcessorArgs { auth_manager: auth_manager.clone(), thread_manager: Arc::clone(&thread_manager), @@ -301,10 +311,7 @@ impl MessageProcessor { analytics_events_client: analytics_events_client.clone(), arg0_paths, config: Arc::clone(&config), - cli_overrides: cli_overrides.clone(), - runtime_feature_enablement: runtime_feature_enablement.clone(), - cloud_requirements: cloud_requirements.clone(), - thread_config_loader, + config_manager: config_manager.clone(), feedback, log_db, }); @@ -314,11 +321,7 @@ impl MessageProcessor { .plugins_manager() .maybe_start_plugin_startup_tasks_for_config(&config, auth_manager.clone()); let config_api = ConfigApi::new( - config.codex_home.to_path_buf(), - cli_overrides, - runtime_feature_enablement, - loader_overrides, - cloud_requirements, + config_manager, thread_manager.clone(), analytics_events_client.clone(), ); diff --git a/codex-rs/app-server/src/message_processor/tracing_tests.rs b/codex-rs/app-server/src/message_processor/tracing_tests.rs index 83f8bc98d7..6f2db58de4 100644 --- a/codex-rs/app-server/src/message_processor/tracing_tests.rs +++ b/codex-rs/app-server/src/message_processor/tracing_tests.rs @@ -619,6 +619,7 @@ async fn turn_start_jsonrpc_span_parents_core_turn_spans() -> Result<()> { cwd: None, approval_policy: None, sandbox_policy: None, + permission_profile: None, approvals_reviewer: None, model: None, service_tier: None, diff --git a/codex-rs/app-server/tests/suite/v2/command_exec.rs b/codex-rs/app-server/tests/suite/v2/command_exec.rs index d7645f13e3..f93e5fc0b8 100644 --- a/codex-rs/app-server/tests/suite/v2/command_exec.rs +++ b/codex-rs/app-server/tests/suite/v2/command_exec.rs @@ -5,6 +5,7 @@ use app_test_support::create_mock_responses_server_sequence_unchecked; use app_test_support::to_response; use base64::Engine; use base64::engine::general_purpose::STANDARD; +use codex_app_server_protocol::AdditionalNetworkPermissions; use codex_app_server_protocol::CommandExecOutputDeltaNotification; use codex_app_server_protocol::CommandExecOutputStream; use codex_app_server_protocol::CommandExecParams; @@ -13,9 +14,16 @@ use codex_app_server_protocol::CommandExecResponse; use codex_app_server_protocol::CommandExecTerminalSize; use codex_app_server_protocol::CommandExecTerminateParams; use codex_app_server_protocol::CommandExecWriteParams; +use codex_app_server_protocol::FileSystemAccessMode; +use codex_app_server_protocol::FileSystemPath; +use codex_app_server_protocol::FileSystemSandboxEntry; +use codex_app_server_protocol::FileSystemSpecialPath; use codex_app_server_protocol::JSONRPCMessage; use codex_app_server_protocol::JSONRPCNotification; +use codex_app_server_protocol::PermissionProfile; +use codex_app_server_protocol::PermissionProfileFileSystemPermissions; use codex_app_server_protocol::RequestId; +use codex_app_server_protocol::SandboxPolicy; use pretty_assertions::assert_eq; use std::collections::HashMap; use tempfile::TempDir; @@ -57,6 +65,7 @@ async fn command_exec_without_streams_can_be_terminated() -> Result<()> { env: None, size: None, sandbox_policy: None, + permission_profile: None, }) .await?; let terminate_request_id = mcp @@ -109,6 +118,7 @@ async fn command_exec_without_process_id_keeps_buffered_compatibility() -> Resul env: None, size: None, sandbox_policy: None, + permission_profile: None, }) .await?; @@ -167,6 +177,7 @@ async fn command_exec_env_overrides_merge_with_server_environment_and_support_un ])), size: None, sandbox_policy: None, + permission_profile: None, }) .await?; @@ -186,6 +197,91 @@ async fn command_exec_env_overrides_merge_with_server_environment_and_support_un Ok(()) } +#[tokio::test] +async fn command_exec_accepts_permission_profile() -> Result<()> { + let server = create_mock_responses_server_sequence_unchecked(Vec::new()).await; + let codex_home = TempDir::new()?; + create_config_toml(codex_home.path(), &server.uri(), "never")?; + let mut mcp = McpProcess::new(codex_home.path()).await?; + timeout(DEFAULT_READ_TIMEOUT, mcp.initialize()).await??; + + let command_request_id = mcp + .send_command_exec_request(CommandExecParams { + command: vec![ + "sh".to_string(), + "-lc".to_string(), + "printf 'profile'".to_string(), + ], + process_id: None, + tty: false, + stream_stdin: false, + stream_stdout_stderr: false, + output_bytes_cap: None, + disable_output_cap: false, + disable_timeout: false, + timeout_ms: None, + cwd: None, + env: None, + size: None, + sandbox_policy: None, + permission_profile: Some(root_read_only_permission_profile()), + }) + .await?; + + let response = mcp + .read_stream_until_response_message(RequestId::Integer(command_request_id)) + .await?; + let response: CommandExecResponse = to_response(response)?; + assert_eq!( + response, + CommandExecResponse { + exit_code: 0, + stdout: "profile".to_string(), + stderr: String::new(), + } + ); + + Ok(()) +} + +#[tokio::test] +async fn command_exec_rejects_sandbox_policy_with_permission_profile() -> Result<()> { + let server = create_mock_responses_server_sequence_unchecked(Vec::new()).await; + let codex_home = TempDir::new()?; + create_config_toml(codex_home.path(), &server.uri(), "never")?; + let mut mcp = McpProcess::new(codex_home.path()).await?; + timeout(DEFAULT_READ_TIMEOUT, mcp.initialize()).await??; + + let command_request_id = mcp + .send_command_exec_request(CommandExecParams { + command: vec!["sh".to_string(), "-lc".to_string(), "true".to_string()], + process_id: None, + tty: false, + stream_stdin: false, + stream_stdout_stderr: false, + output_bytes_cap: None, + disable_output_cap: false, + disable_timeout: false, + timeout_ms: None, + cwd: None, + env: None, + size: None, + sandbox_policy: Some(SandboxPolicy::DangerFullAccess), + permission_profile: Some(root_read_only_permission_profile()), + }) + .await?; + + let error = mcp + .read_stream_until_error_message(RequestId::Integer(command_request_id)) + .await?; + assert_eq!( + error.error.message, + "`permissionProfile` cannot be combined with `sandboxPolicy`" + ); + + Ok(()) +} + #[tokio::test] async fn command_exec_rejects_disable_timeout_with_timeout_ms() -> Result<()> { let server = create_mock_responses_server_sequence_unchecked(Vec::new()).await; @@ -209,6 +305,7 @@ async fn command_exec_rejects_disable_timeout_with_timeout_ms() -> Result<()> { env: None, size: None, sandbox_policy: None, + permission_profile: None, }) .await?; @@ -246,6 +343,7 @@ async fn command_exec_rejects_disable_output_cap_with_output_bytes_cap() -> Resu env: None, size: None, sandbox_policy: None, + permission_profile: None, }) .await?; @@ -283,6 +381,7 @@ async fn command_exec_rejects_negative_timeout_ms() -> Result<()> { env: None, size: None, sandbox_policy: None, + permission_profile: None, }) .await?; @@ -320,6 +419,7 @@ async fn command_exec_without_process_id_rejects_streaming() -> Result<()> { env: None, size: None, sandbox_policy: None, + permission_profile: None, }) .await?; @@ -361,6 +461,7 @@ async fn command_exec_non_streaming_respects_output_cap() -> Result<()> { env: None, size: None, sandbox_policy: None, + permission_profile: None, }) .await?; @@ -408,6 +509,7 @@ async fn command_exec_streaming_does_not_buffer_output() -> Result<()> { env: None, size: None, sandbox_policy: None, + permission_profile: None, }) .await?; @@ -471,6 +573,7 @@ async fn command_exec_pipe_streams_output_and_accepts_write() -> Result<()> { env: None, size: None, sandbox_policy: None, + permission_profile: None, }) .await?; @@ -546,6 +649,7 @@ async fn command_exec_tty_implies_streaming_and_reports_pty_output() -> Result<( env: None, size: None, sandbox_policy: None, + permission_profile: None, }) .await?; @@ -619,6 +723,7 @@ async fn command_exec_tty_supports_initial_size_and_resize() -> Result<()> { cols: 101, }), sandbox_policy: None, + permission_profile: None, }) .await?; @@ -888,6 +993,23 @@ fn decode_delta_notification( serde_json::from_value(params).context("deserialize command/exec/outputDelta notification") } +fn root_read_only_permission_profile() -> PermissionProfile { + PermissionProfile { + network: Some(AdditionalNetworkPermissions { + enabled: Some(false), + }), + file_system: Some(PermissionProfileFileSystemPermissions { + entries: vec![FileSystemSandboxEntry { + path: FileSystemPath::Special { + value: FileSystemSpecialPath::Root, + }, + access: FileSystemAccessMode::Read, + }], + glob_scan_max_depth: None, + }), + } +} + async fn read_initialize_response( stream: &mut super::connection_handling_websocket::WsClient, request_id: i64, diff --git a/codex-rs/app-server/tests/suite/v2/experimental_feature_list.rs b/codex-rs/app-server/tests/suite/v2/experimental_feature_list.rs index 07bdd0bde1..3f7e6989f8 100644 --- a/codex-rs/app-server/tests/suite/v2/experimental_feature_list.rs +++ b/codex-rs/app-server/tests/suite/v2/experimental_feature_list.rs @@ -15,6 +15,7 @@ use codex_app_server_protocol::JSONRPCError; use codex_app_server_protocol::JSONRPCResponse; use codex_app_server_protocol::RequestId; use codex_core::config::ConfigBuilder; +use codex_core::config_loader::LoaderOverrides; use codex_features::FEATURES; use codex_features::Stage; use pretty_assertions::assert_eq; @@ -32,6 +33,9 @@ async fn experimental_feature_list_returns_feature_metadata_with_stage() -> Resu let config = ConfigBuilder::default() .codex_home(codex_home.path().to_path_buf()) .fallback_cwd(Some(codex_home.path().to_path_buf())) + .loader_overrides(LoaderOverrides::with_managed_config_path_for_tests( + codex_home.path().join("managed_config.toml"), + )) .build() .await?; let mut mcp = McpProcess::new(codex_home.path()).await?; diff --git a/codex-rs/app-server/tests/suite/v2/mcp_tool.rs b/codex-rs/app-server/tests/suite/v2/mcp_tool.rs index 87556c8364..8a323efcef 100644 --- a/codex-rs/app-server/tests/suite/v2/mcp_tool.rs +++ b/codex-rs/app-server/tests/suite/v2/mcp_tool.rs @@ -83,10 +83,11 @@ url = "{mcp_server_url}/mcp" ) .await??; let ThreadStartResponse { thread, .. } = to_response(thread_start_resp)?; + let thread_id = thread.id.clone(); let tool_call_request_id = mcp .send_mcp_server_tool_call_request(McpServerToolCallParams { - thread_id: thread.id, + thread_id: thread_id.clone(), server: TEST_SERVER_NAME.to_string(), tool: TEST_TOOL_NAME.to_string(), arguments: Some(json!({ @@ -114,6 +115,7 @@ url = "{mcp_server_url}/mcp" response.structured_content, Some(json!({ "echoed": "hello from app", + "threadId": thread_id, })) ); assert_eq!(response.is_error, Some(false)); @@ -203,7 +205,7 @@ impl ServerHandler for ToolAppsMcpServer { async fn call_tool( &self, request: CallToolRequestParams, - _context: RequestContext, + context: RequestContext, ) -> Result { assert_eq!(request.name.as_ref(), TEST_TOOL_NAME); let message = request @@ -212,12 +214,19 @@ impl ServerHandler for ToolAppsMcpServer { .and_then(|arguments| arguments.get("message")) .and_then(|value| value.as_str()) .unwrap_or_default(); + let thread_id = context + .meta + .0 + .get("threadId") + .and_then(|value| value.as_str()) + .unwrap_or_default(); let mut meta = Meta::new(); meta.0.insert("calledBy".to_string(), json!("mcp-app")); let mut result = CallToolResult::structured(json!({ "echoed": message, + "threadId": thread_id, })); result.content = vec![Content::text(format!("echo: {message}"))]; result.meta = Some(meta); diff --git a/codex-rs/app-server/tests/suite/v2/skills_list.rs b/codex-rs/app-server/tests/suite/v2/skills_list.rs index 8675b3a429..195c4a86db 100644 --- a/codex-rs/app-server/tests/suite/v2/skills_list.rs +++ b/codex-rs/app-server/tests/suite/v2/skills_list.rs @@ -315,6 +315,7 @@ async fn skills_changed_notification_is_emitted_after_skill_change() -> Result<( approval_policy: None, approvals_reviewer: None, sandbox: None, + permission_profile: None, config: None, service_name: None, base_instructions: None, diff --git a/codex-rs/app-server/tests/suite/v2/turn_start.rs b/codex-rs/app-server/tests/suite/v2/turn_start.rs index 65f8442b0d..b8e3182fd2 100644 --- a/codex-rs/app-server/tests/suite/v2/turn_start.rs +++ b/codex-rs/app-server/tests/suite/v2/turn_start.rs @@ -1749,6 +1749,7 @@ async fn turn_start_updates_sandbox_and_cwd_between_turns_v2() -> Result<()> { exclude_tmpdir_env_var: false, exclude_slash_tmp: false, }), + permission_profile: None, model: Some("mock-model".to_string()), effort: Some(ReasoningEffort::Medium), summary: Some(ReasoningSummary::Auto), @@ -1783,6 +1784,7 @@ async fn turn_start_updates_sandbox_and_cwd_between_turns_v2() -> Result<()> { approval_policy: Some(codex_app_server_protocol::AskForApproval::Never), approvals_reviewer: None, sandbox_policy: Some(codex_app_server_protocol::SandboxPolicy::DangerFullAccess), + permission_profile: None, model: Some("mock-model".to_string()), effort: Some(ReasoningEffort::Medium), summary: Some(ReasoningSummary::Auto), diff --git a/codex-rs/cli/tests/debug_clear_memories.rs b/codex-rs/cli/tests/debug_clear_memories.rs index a24f7ebdde..9d5e114dbf 100644 --- a/codex-rs/cli/tests/debug_clear_memories.rs +++ b/codex-rs/cli/tests/debug_clear_memories.rs @@ -105,7 +105,7 @@ INSERT INTO jobs ( let memory_root = codex_home.path().join("memories"); std::fs::create_dir_all(&memory_root)?; std::fs::write(memory_root.join("memory_summary.md"), "stale memory")?; - drop(pool); + pool.close().await; let mut cmd = codex_command(codex_home.path())?; cmd.args(["debug", "clear-memories"]) @@ -127,6 +127,7 @@ INSERT INTO jobs ( assert_eq!(memory_jobs_count, 0); assert!(memory_root.exists()); assert_eq!(std::fs::read_dir(memory_root)?.count(), 0); + pool.close().await; Ok(()) } diff --git a/codex-rs/codex-mcp/src/mcp_connection_manager.rs b/codex-rs/codex-mcp/src/mcp_connection_manager.rs index 10c48e040e..bcc7685a31 100644 --- a/codex-rs/codex-mcp/src/mcp_connection_manager.rs +++ b/codex-rs/codex-mcp/src/mcp_connection_manager.rs @@ -42,6 +42,7 @@ use codex_protocol::approvals::ElicitationRequest; use codex_protocol::approvals::ElicitationRequestEvent; use codex_protocol::mcp::CallToolResult; use codex_protocol::mcp::RequestId as ProtocolRequestId; +use codex_protocol::models::PermissionProfile; use codex_protocol::protocol::AskForApproval; use codex_protocol::protocol::Event; use codex_protocol::protocol::EventMsg; @@ -646,6 +647,8 @@ pub const MCP_SANDBOX_STATE_META_CAPABILITY: &str = "codex/sandbox-state-meta"; #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct SandboxState { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub permission_profile: Option, pub sandbox_policy: SandboxPolicy, pub codex_linux_sandbox_exe: Option, pub sandbox_cwd: PathBuf, diff --git a/codex-rs/core-skills/src/lib.rs b/codex-rs/core-skills/src/lib.rs index 6d3ac7a4fe..06ced0d5d4 100644 --- a/codex-rs/core-skills/src/lib.rs +++ b/codex-rs/core-skills/src/lib.rs @@ -22,8 +22,8 @@ pub use model::SkillLoadOutcome; pub use model::SkillMetadata; pub use model::SkillPolicy; pub use model::filter_skill_load_outcome_for_product; -pub use render::RenderedSkillsSection; +pub use render::AvailableSkills; pub use render::SkillMetadataBudget; pub use render::SkillRenderReport; +pub use render::build_available_skills; pub use render::default_skill_metadata_budget; -pub use render::render_skills_section; diff --git a/codex-rs/core-skills/src/render.rs b/codex-rs/core-skills/src/render.rs index ad674fbffa..6bcd5e4e05 100644 --- a/codex-rs/core-skills/src/render.rs +++ b/codex-rs/core-skills/src/render.rs @@ -3,8 +3,6 @@ use codex_otel::SessionTelemetry; use codex_otel::THREAD_SKILLS_ENABLED_TOTAL_METRIC; use codex_otel::THREAD_SKILLS_KEPT_TOTAL_METRIC; use codex_otel::THREAD_SKILLS_TRUNCATED_METRIC; -use codex_protocol::protocol::SKILLS_INSTRUCTIONS_CLOSE_TAG; -use codex_protocol::protocol::SKILLS_INSTRUCTIONS_OPEN_TAG; use codex_protocol::protocol::SkillScope; use codex_utils_output_truncation::approx_token_count; @@ -48,8 +46,8 @@ pub enum SkillRenderSideEffects<'a> { } #[derive(Debug, Clone, PartialEq, Eq)] -pub struct RenderedSkillsSection { - pub text: String, +pub struct AvailableSkills { + pub skill_lines: Vec, pub report: SkillRenderReport, pub emit_warning: bool, } @@ -71,11 +69,11 @@ pub fn default_skill_metadata_budget(context_window: Option) -> SkillMetada )) } -pub fn render_skills_section( +pub fn build_available_skills( skills: &[SkillMetadata], budget: SkillMetadataBudget, side_effects: SkillRenderSideEffects<'_>, -) -> Option { +) -> Option { if skills.is_empty() { let _ = record_skill_render_side_effects( side_effects, @@ -93,39 +91,8 @@ pub fn render_skills_section( report.included_count, report.omitted_count > 0, ); - let mut lines: Vec = Vec::new(); - lines.push("## Skills".to_string()); - lines.push("A skill is a set of local instructions to follow that is stored in a `SKILL.md` file. Below is the list of skills that can be used. Each entry includes a name, description, and file path so you can open the source for full instructions when using a specific skill.".to_string()); - lines.push("### Available skills".to_string()); - if !skill_lines.is_empty() { - lines.extend(skill_lines); - } - - lines.push("### How to use skills".to_string()); - lines.push( - r###"- Discovery: The list above is the skills available in this session (name + description + file path). Skill bodies live on disk at the listed paths. -- Trigger rules: If the user names a skill (with `$SkillName` or plain text) OR the task clearly matches a skill's description shown above, you must use that skill for that turn. Multiple mentions mean use them all. Do not carry skills across turns unless re-mentioned. -- Missing/blocked: If a named skill isn't in the list or the path can't be read, say so briefly and continue with the best fallback. -- How to use a skill (progressive disclosure): - 1) After deciding to use a skill, open its `SKILL.md`. Read only enough to follow the workflow. - 2) When `SKILL.md` references relative paths (e.g., `scripts/foo.py`), resolve them relative to the skill directory listed above first, and only consider other paths if needed. - 3) If `SKILL.md` points to extra folders such as `references/`, load only the specific files needed for the request; don't bulk-load everything. - 4) If `scripts/` exist, prefer running or patching them instead of retyping large code blocks. - 5) If `assets/` or templates exist, reuse them instead of recreating from scratch. -- Coordination and sequencing: - - If multiple skills apply, choose the minimal set that covers the request and state the order you'll use them. - - Announce which skill(s) you're using and why (one short line). If you skip an obvious skill, say why. -- Context hygiene: - - Keep context small: summarize long sections instead of pasting them; only load extra files when needed. - - Avoid deep reference-chasing: prefer opening only files directly linked from `SKILL.md` unless you're blocked. - - When variants exist (frameworks, providers, domains), pick only the relevant reference file(s) and note that choice. -- Safety and fallback: If a skill can't be applied cleanly (missing files, unclear instructions), state the issue, pick the next-best approach, and continue."### - .to_string(), - ); - - let body = lines.join("\n"); - Some(RenderedSkillsSection { - text: format!("{SKILLS_INSTRUCTIONS_OPEN_TAG}\n{body}\n{SKILLS_INSTRUCTIONS_CLOSE_TAG}"), + Some(AvailableSkills { + skill_lines, report, emit_warning, }) @@ -274,7 +241,7 @@ mod tests { .cost(&format!("{}\n", render_skill_line(&admin))); let budget = SkillMetadataBudget::Characters(system_cost + admin_cost); - let rendered = render_skills_section( + let rendered = build_available_skills( &[system, user, repo, admin], budget, SkillRenderSideEffects::None, @@ -284,10 +251,11 @@ mod tests { assert_eq!(rendered.report.included_count, 2); assert_eq!(rendered.report.omitted_count, 2); assert!(!rendered.emit_warning); - assert!(rendered.text.contains("- system-skill:")); - assert!(rendered.text.contains("- admin-skill:")); - assert!(!rendered.text.contains("- repo-skill:")); - assert!(!rendered.text.contains("- user-skill:")); + let rendered_text = rendered.skill_lines.join("\n"); + assert!(rendered_text.contains("- system-skill:")); + assert!(rendered_text.contains("- admin-skill:")); + assert!(!rendered_text.contains("- repo-skill:")); + assert!(!rendered_text.contains("- user-skill:")); } #[test] @@ -300,13 +268,14 @@ mod tests { let budget = SkillMetadataBudget::Characters(repo_cost); let rendered = - render_skills_section(&[oversized, repo], budget, SkillRenderSideEffects::None) + build_available_skills(&[oversized, repo], budget, SkillRenderSideEffects::None) .expect("skills render"); assert_eq!(rendered.report.included_count, 1); assert_eq!(rendered.report.omitted_count, 1); assert!(!rendered.emit_warning); - assert!(!rendered.text.contains("- oversized-system-skill:")); - assert!(rendered.text.contains("- repo-skill:")); + let rendered_text = rendered.skill_lines.join("\n"); + assert!(!rendered_text.contains("- oversized-system-skill:")); + assert!(rendered_text.contains("- repo-skill:")); } } diff --git a/codex-rs/core/Cargo.toml b/codex-rs/core/Cargo.toml index 6ef6741fd9..d1cca0ac32 100644 --- a/codex-rs/core/Cargo.toml +++ b/codex-rs/core/Cargo.toml @@ -104,7 +104,6 @@ sha2 = { workspace = true } shlex = { workspace = true } similar = { workspace = true } tempfile = { workspace = true } -test-log = { workspace = true } thiserror = { workspace = true } tokio = { workspace = true, features = [ "io-std", @@ -166,6 +165,7 @@ opentelemetry_sdk = { workspace = true, features = [ ] } serial_test = { workspace = true } tempfile = { workspace = true } +test-log = { workspace = true } tracing-opentelemetry = { workspace = true } tracing-subscriber = { workspace = true } tracing-test = { workspace = true, features = ["no-env-filter"] } diff --git a/codex-rs/core/src/apps/mod.rs b/codex-rs/core/src/apps/mod.rs index dcb5c4c20a..5a58d22204 100644 --- a/codex-rs/core/src/apps/mod.rs +++ b/codex-rs/core/src/apps/mod.rs @@ -1,3 +1,2 @@ +#[cfg(test)] mod render; - -pub(crate) use render::render_apps_section; diff --git a/codex-rs/core/src/apps/render.rs b/codex-rs/core/src/apps/render.rs index fe23a09f8d..3793231e10 100644 --- a/codex-rs/core/src/apps/render.rs +++ b/codex-rs/core/src/apps/render.rs @@ -1,22 +1,11 @@ +use crate::context::AppsInstructions; +use crate::context::ContextualUserFragment; use codex_app_server_protocol::AppInfo; -use codex_mcp::CODEX_APPS_MCP_SERVER_NAME; use codex_protocol::protocol::APPS_INSTRUCTIONS_CLOSE_TAG; use codex_protocol::protocol::APPS_INSTRUCTIONS_OPEN_TAG; pub(crate) fn render_apps_section(connectors: &[AppInfo]) -> Option { - if !connectors - .iter() - .any(|connector| connector.is_accessible && connector.is_enabled) - { - return None; - } - - let body = format!( - "## Apps (Connectors)\nApps (Connectors) can be explicitly triggered in user messages in the format `[$app-name](app://{{connector_id}})`. Apps can also be implicitly triggered as long as the context suggests usage of available apps.\nAn app is equivalent to a set of MCP tools within the `{CODEX_APPS_MCP_SERVER_NAME}` MCP.\nAn installed app's MCP tools are either provided to you already, or can be lazy-loaded through the `tool_search` tool. If `tool_search` is available, the apps that are searchable by `tools_search` will be listed by it.\nDo not additionally call list_mcp_resources or list_mcp_resource_templates for apps." - ); - Some(format!( - "{APPS_INSTRUCTIONS_OPEN_TAG}\n{body}\n{APPS_INSTRUCTIONS_CLOSE_TAG}" - )) + AppsInstructions::from_connectors(connectors).map(|instructions| instructions.render()) } #[cfg(test)] diff --git a/codex-rs/core/src/codex_thread.rs b/codex-rs/core/src/codex_thread.rs index 6513f09d07..7c8e9fa68a 100644 --- a/codex-rs/core/src/codex_thread.rs +++ b/codex-rs/core/src/codex_thread.rs @@ -11,6 +11,7 @@ use codex_protocol::error::CodexErr; use codex_protocol::error::Result as CodexResult; use codex_protocol::mcp::CallToolResult; use codex_protocol::models::ContentItem; +use codex_protocol::models::PermissionProfile; use codex_protocol::models::ResponseInputItem; use codex_protocol::models::ResponseItem; use codex_protocol::openai_models::ReasoningEffort; @@ -42,6 +43,7 @@ pub struct ThreadConfigSnapshot { pub approval_policy: AskForApproval, pub approvals_reviewer: ApprovalsReviewer, pub sandbox_policy: SandboxPolicy, + pub permission_profile: PermissionProfile, pub cwd: AbsolutePathBuf, pub ephemeral: bool, pub reasoning_effort: Option, diff --git a/codex-rs/core/src/config/config_tests.rs b/codex-rs/core/src/config/config_tests.rs index e7c7aa31dd..897e1bf611 100644 --- a/codex-rs/core/src/config/config_tests.rs +++ b/codex-rs/core/src/config/config_tests.rs @@ -53,6 +53,9 @@ use codex_model_provider_info::LMSTUDIO_OSS_PROVIDER_ID; use codex_model_provider_info::OLLAMA_OSS_PROVIDER_ID; use codex_model_provider_info::WireApi; use codex_models_manager::bundled_models_response; +use codex_protocol::models::FileSystemPermissions; +use codex_protocol::models::NetworkPermissions; +use codex_protocol::models::PermissionProfile; use codex_protocol::permissions::FileSystemAccessMode; use codex_protocol::permissions::FileSystemPath; use codex_protocol::permissions::FileSystemSandboxEntry; @@ -61,6 +64,7 @@ use codex_protocol::permissions::FileSystemSpecialPath; use codex_protocol::permissions::NetworkSandboxPolicy; use codex_protocol::protocol::ReadOnlyAccess; use codex_protocol::protocol::RealtimeVoice; +use codex_protocol::protocol::SandboxPolicy; use serde::Deserialize; use tempfile::tempdir; @@ -782,6 +786,44 @@ async fn default_permissions_profile_populates_runtime_sandbox_policy() -> std:: Ok(()) } +#[tokio::test] +async fn permission_profile_override_populates_runtime_permissions() -> std::io::Result<()> { + let codex_home = TempDir::new()?; + let cwd = TempDir::new()?; + let permission_profile = PermissionProfile { + network: Some(NetworkPermissions { + enabled: Some(true), + }), + file_system: Some(FileSystemPermissions { + entries: vec![FileSystemSandboxEntry { + path: FileSystemPath::Special { + value: FileSystemSpecialPath::Root, + }, + access: FileSystemAccessMode::Write, + }], + glob_scan_max_depth: None, + }), + }; + + let config = Config::load_from_base_config_with_overrides( + ConfigToml::default(), + ConfigOverrides { + cwd: Some(cwd.path().to_path_buf()), + permission_profile: Some(permission_profile.clone()), + ..Default::default() + }, + codex_home.abs(), + ) + .await?; + + assert_eq!(config.permissions.permission_profile(), permission_profile); + assert_eq!( + config.permissions.sandbox_policy.get(), + &SandboxPolicy::DangerFullAccess + ); + Ok(()) +} + #[tokio::test] async fn project_root_glob_none_compiles_to_filesystem_pattern_entry() -> std::io::Result<()> { let codex_home = TempDir::new()?; diff --git a/codex-rs/core/src/config/mod.rs b/codex-rs/core/src/config/mod.rs index a6240fdcb3..123606509b 100644 --- a/codex-rs/core/src/config/mod.rs +++ b/codex-rs/core/src/config/mod.rs @@ -7,6 +7,7 @@ use crate::config_loader::ConfigLayerStackOrdering; use crate::config_loader::ConfigRequirements; use crate::config_loader::ConfigRequirementsToml; use crate::config_loader::ConstrainedWithSource; +use crate::config_loader::FeatureRequirementsToml; use crate::config_loader::LoaderOverrides; use crate::config_loader::McpServerIdentity; use crate::config_loader::McpServerRequirement; @@ -78,6 +79,7 @@ use codex_protocol::config_types::Verbosity; use codex_protocol::config_types::WebSearchConfig; use codex_protocol::config_types::WebSearchMode; use codex_protocol::config_types::WindowsSandboxLevel; +use codex_protocol::models::PermissionProfile; use codex_protocol::openai_models::ModelsResponse; use codex_protocol::openai_models::ReasoningEffort; use codex_protocol::permissions::FileSystemSandboxPolicy; @@ -108,7 +110,6 @@ mod network_proxy_spec; mod permissions; #[cfg(test)] mod schema; -pub(crate) mod service; pub use codex_config::Constrained; pub use codex_config::ConstraintError; pub use codex_config::ConstraintResult; @@ -118,8 +119,6 @@ pub use managed_features::ManagedFeatures; pub use network_proxy_spec::NetworkProxySpec; pub use network_proxy_spec::StartedNetworkProxy; pub(crate) use permissions::resolve_permission_profile; -pub use service::ConfigService; -pub use service::ConfigServiceError; pub use codex_git_utils::GhostSnapshotConfig; @@ -219,6 +218,17 @@ pub struct Permissions { pub windows_sandbox_private_desktop: bool, } +impl Permissions { + /// Effective runtime permissions after config requirements and runtime + /// readable-root additions have been applied. + pub fn permission_profile(&self) -> PermissionProfile { + PermissionProfile::from_runtime_permissions( + &self.file_system_sandbox_policy, + self.network_sandbox_policy, + ) + } +} + /// Application configuration loaded from disk and merged with overrides. #[derive(Debug, Clone, PartialEq)] pub struct Config { @@ -947,7 +957,7 @@ pub async fn load_config_as_toml_with_cli_and_loader_overrides( Ok(cfg) } -pub(crate) fn deserialize_config_toml_with_base( +pub fn deserialize_config_toml_with_base( root_value: TomlValue, config_base_dir: &Path, ) -> std::io::Result { @@ -959,6 +969,15 @@ pub(crate) fn deserialize_config_toml_with_base( .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e)) } +/// Validate user-visible feature settings against managed feature requirements. +pub fn validate_feature_requirements_for_config_toml( + cfg: &ConfigToml, + feature_requirements: Option<&Sourced>, +) -> std::io::Result<()> { + managed_features::validate_explicit_feature_settings_in_config_toml(cfg, feature_requirements)?; + managed_features::validate_feature_requirements_in_config_toml(cfg, feature_requirements) +} + fn load_catalog_json(path: &AbsolutePathBuf) -> std::io::Result { let file_contents = std::fs::read_to_string(path)?; let catalog = serde_json::from_str::(&file_contents).map_err(|err| { @@ -1366,6 +1385,7 @@ pub struct ConfigOverrides { pub approval_policy: Option, pub approvals_reviewer: Option, pub sandbox_mode: Option, + pub permission_profile: Option, pub model_provider: Option, pub service_tier: Option>, pub config_profile: Option, @@ -1583,6 +1603,7 @@ impl Config { approval_policy: approval_policy_override, approvals_reviewer: approvals_reviewer_override, sandbox_mode, + permission_profile, model_provider, service_tier: service_tier_override, config_profile: config_profile_key, @@ -1603,6 +1624,13 @@ impl Config { additional_writable_roots, } = overrides; + if sandbox_mode.is_some() && permission_profile.is_some() { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + "`sandbox_mode` and `permission_profile` overrides cannot both be set", + )); + } + let active_profile_name = config_profile_key .as_ref() .or(cfg.profile.as_ref()) @@ -1723,7 +1751,34 @@ impl Config { sandbox_policy, file_system_sandbox_policy, network_sandbox_policy, - ) = if profiles_are_active { + ) = if let Some(permission_profile) = permission_profile { + let configured_network_proxy_config = NetworkProxyConfig::default(); + let (mut file_system_sandbox_policy, network_sandbox_policy) = + permission_profile.to_runtime_permissions(); + let mut sandbox_policy = permission_profile + .to_legacy_sandbox_policy(resolved_cwd.as_path()) + .map_err(|err| { + std::io::Error::new( + std::io::ErrorKind::InvalidInput, + format!("invalid permission_profile override: {err}"), + ) + })?; + if matches!(sandbox_policy, SandboxPolicy::WorkspaceWrite { .. }) { + file_system_sandbox_policy = file_system_sandbox_policy + .with_additional_writable_roots( + resolved_cwd.as_path(), + &additional_writable_roots, + ); + sandbox_policy = file_system_sandbox_policy + .to_legacy_sandbox_policy(network_sandbox_policy, resolved_cwd.as_path())?; + } + ( + configured_network_proxy_config, + sandbox_policy, + file_system_sandbox_policy, + network_sandbox_policy, + ) + } else if profiles_are_active { let permissions = cfg.permissions.as_ref().ok_or_else(|| { std::io::Error::new( std::io::ErrorKind::InvalidInput, diff --git a/codex-rs/core/src/context/approved_command_prefix_saved.rs b/codex-rs/core/src/context/approved_command_prefix_saved.rs new file mode 100644 index 0000000000..3aac17712a --- /dev/null +++ b/codex-rs/core/src/context/approved_command_prefix_saved.rs @@ -0,0 +1,24 @@ +use super::ContextualUserFragment; + +#[derive(Debug, Clone, PartialEq)] +pub(crate) struct ApprovedCommandPrefixSaved { + prefixes: String, +} + +impl ApprovedCommandPrefixSaved { + pub(crate) fn new(prefixes: impl Into) -> Self { + Self { + prefixes: prefixes.into(), + } + } +} + +impl ContextualUserFragment for ApprovedCommandPrefixSaved { + const ROLE: &'static str = "developer"; + const START_MARKER: &'static str = ""; + const END_MARKER: &'static str = ""; + + fn body(&self) -> String { + format!("Approved command prefix saved:\n{}", self.prefixes) + } +} diff --git a/codex-rs/core/src/context/apps_instructions.rs b/codex-rs/core/src/context/apps_instructions.rs new file mode 100644 index 0000000000..55865b429a --- /dev/null +++ b/codex-rs/core/src/context/apps_instructions.rs @@ -0,0 +1,30 @@ +use codex_app_server_protocol::AppInfo; +use codex_mcp::CODEX_APPS_MCP_SERVER_NAME; +use codex_protocol::protocol::APPS_INSTRUCTIONS_CLOSE_TAG; +use codex_protocol::protocol::APPS_INSTRUCTIONS_OPEN_TAG; + +use super::ContextualUserFragment; + +#[derive(Debug, Clone, PartialEq)] +pub(crate) struct AppsInstructions; + +impl AppsInstructions { + pub(crate) fn from_connectors(connectors: &[AppInfo]) -> Option { + connectors + .iter() + .any(|connector| connector.is_accessible && connector.is_enabled) + .then_some(Self) + } +} + +impl ContextualUserFragment for AppsInstructions { + const ROLE: &'static str = "developer"; + const START_MARKER: &'static str = APPS_INSTRUCTIONS_OPEN_TAG; + const END_MARKER: &'static str = APPS_INSTRUCTIONS_CLOSE_TAG; + + fn body(&self) -> String { + format!( + "\n## Apps (Connectors)\nApps (Connectors) can be explicitly triggered in user messages in the format `[$app-name](app://{{connector_id}})`. Apps can also be implicitly triggered as long as the context suggests usage of available apps.\nAn app is equivalent to a set of MCP tools within the `{CODEX_APPS_MCP_SERVER_NAME}` MCP.\nAn installed app's MCP tools are either provided to you already, or can be lazy-loaded through the `tool_search` tool. If `tool_search` is available, the apps that are searchable by `tools_search` will be listed by it.\nDo not additionally call list_mcp_resources or list_mcp_resource_templates for apps.\n" + ) + } +} diff --git a/codex-rs/core/src/context/available_plugins_instructions.rs b/codex-rs/core/src/context/available_plugins_instructions.rs new file mode 100644 index 0000000000..52f9c8df48 --- /dev/null +++ b/codex-rs/core/src/context/available_plugins_instructions.rs @@ -0,0 +1,58 @@ +use codex_plugin::PluginCapabilitySummary; +use codex_protocol::protocol::PLUGINS_INSTRUCTIONS_CLOSE_TAG; +use codex_protocol::protocol::PLUGINS_INSTRUCTIONS_OPEN_TAG; + +use super::ContextualUserFragment; + +#[derive(Debug, Clone, PartialEq)] +pub(crate) struct AvailablePluginsInstructions { + plugins: Vec, +} + +impl AvailablePluginsInstructions { + pub(crate) fn from_plugins(plugins: &[PluginCapabilitySummary]) -> Option { + if plugins.is_empty() { + return None; + } + + Some(Self { + plugins: plugins.to_vec(), + }) + } +} + +impl ContextualUserFragment for AvailablePluginsInstructions { + const ROLE: &'static str = "developer"; + const START_MARKER: &'static str = PLUGINS_INSTRUCTIONS_OPEN_TAG; + const END_MARKER: &'static str = PLUGINS_INSTRUCTIONS_CLOSE_TAG; + + fn body(&self) -> String { + let mut lines = vec![ + "## Plugins".to_string(), + "A plugin is a local bundle of skills, MCP servers, and apps. Below is the list of plugins that are enabled and available in this session.".to_string(), + "### Available plugins".to_string(), + ]; + + lines.extend( + self.plugins + .iter() + .map(|plugin| match plugin.description.as_deref() { + Some(description) => format!("- `{}`: {description}", plugin.display_name), + None => format!("- `{}`", plugin.display_name), + }), + ); + + lines.push("### How to use plugins".to_string()); + lines.push( + r###"- Discovery: The list above is the plugins available in this session. +- Skill naming: If a plugin contributes skills, those skill entries are prefixed with `plugin_name:` in the Skills list. +- Trigger rules: If the user explicitly names a plugin, prefer capabilities associated with that plugin for that turn. +- Relationship to capabilities: Plugins are not invoked directly. Use their underlying skills, MCP tools, and app tools to help solve the task. +- Preference: When a relevant plugin is available, prefer using capabilities associated with that plugin over standalone capabilities that provide similar functionality. +- Missing/blocked: If the user requests a plugin that is not listed above, or the plugin does not have relevant callable capabilities for the task, say so briefly and continue with the best fallback."### + .to_string(), + ); + + format!("\n{}\n", lines.join("\n")) + } +} diff --git a/codex-rs/core/src/context/available_skills_instructions.rs b/codex-rs/core/src/context/available_skills_instructions.rs new file mode 100644 index 0000000000..aba4b20135 --- /dev/null +++ b/codex-rs/core/src/context/available_skills_instructions.rs @@ -0,0 +1,56 @@ +use codex_core_skills::AvailableSkills; +use codex_protocol::protocol::SKILLS_INSTRUCTIONS_CLOSE_TAG; +use codex_protocol::protocol::SKILLS_INSTRUCTIONS_OPEN_TAG; + +use super::ContextualUserFragment; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub(crate) struct AvailableSkillsInstructions { + skill_lines: Vec, +} + +impl From for AvailableSkillsInstructions { + fn from(available_skills: AvailableSkills) -> Self { + Self { + skill_lines: available_skills.skill_lines, + } + } +} + +impl ContextualUserFragment for AvailableSkillsInstructions { + const ROLE: &'static str = "developer"; + const START_MARKER: &'static str = SKILLS_INSTRUCTIONS_OPEN_TAG; + const END_MARKER: &'static str = SKILLS_INSTRUCTIONS_CLOSE_TAG; + + fn body(&self) -> String { + let mut lines: Vec = Vec::new(); + lines.push("## Skills".to_string()); + lines.push("A skill is a set of local instructions to follow that is stored in a `SKILL.md` file. Below is the list of skills that can be used. Each entry includes a name, description, and file path so you can open the source for full instructions when using a specific skill.".to_string()); + lines.push("### Available skills".to_string()); + lines.extend(self.skill_lines.iter().cloned()); + + lines.push("### How to use skills".to_string()); + lines.push( + r###"- Discovery: The list above is the skills available in this session (name + description + file path). Skill bodies live on disk at the listed paths. +- Trigger rules: If the user names a skill (with `$SkillName` or plain text) OR the task clearly matches a skill's description shown above, you must use that skill for that turn. Multiple mentions mean use them all. Do not carry skills across turns unless re-mentioned. +- Missing/blocked: If a named skill isn't in the list or the path can't be read, say so briefly and continue with the best fallback. +- How to use a skill (progressive disclosure): + 1) After deciding to use a skill, open its `SKILL.md`. Read only enough to follow the workflow. + 2) When `SKILL.md` references relative paths (e.g., `scripts/foo.py`), resolve them relative to the skill directory listed above first, and only consider other paths if needed. + 3) If `SKILL.md` points to extra folders such as `references/`, load only the specific files needed for the request; don't bulk-load everything. + 4) If `scripts/` exist, prefer running or patching them instead of retyping large code blocks. + 5) If `assets/` or templates exist, reuse them instead of recreating from scratch. +- Coordination and sequencing: + - If multiple skills apply, choose the minimal set that covers the request and state the order you'll use them. + - Announce which skill(s) you're using and why (one short line). If you skip an obvious skill, say why. +- Context hygiene: + - Keep context small: summarize long sections instead of pasting them; only load extra files when needed. + - Avoid deep reference-chasing: prefer opening only files directly linked from `SKILL.md` unless you're blocked. + - When variants exist (frameworks, providers, domains), pick only the relevant reference file(s) and note that choice. +- Safety and fallback: If a skill can't be applied cleanly (missing files, unclear instructions), state the issue, pick the next-best approach, and continue."### + .to_string(), + ); + + format!("\n{}\n", lines.join("\n")) + } +} diff --git a/codex-rs/core/src/context/collaboration_mode_instructions.rs b/codex-rs/core/src/context/collaboration_mode_instructions.rs new file mode 100644 index 0000000000..dcf3bac1de --- /dev/null +++ b/codex-rs/core/src/context/collaboration_mode_instructions.rs @@ -0,0 +1,32 @@ +use super::ContextualUserFragment; +use codex_protocol::config_types::CollaborationMode; +use codex_protocol::protocol::COLLABORATION_MODE_CLOSE_TAG; +use codex_protocol::protocol::COLLABORATION_MODE_OPEN_TAG; + +#[derive(Debug, Clone, PartialEq)] +pub(crate) struct CollaborationModeInstructions { + instructions: String, +} + +impl CollaborationModeInstructions { + pub(crate) fn from_collaboration_mode(collaboration_mode: &CollaborationMode) -> Option { + collaboration_mode + .settings + .developer_instructions + .as_ref() + .filter(|instructions| !instructions.is_empty()) + .map(|instructions| Self { + instructions: instructions.clone(), + }) + } +} + +impl ContextualUserFragment for CollaborationModeInstructions { + const ROLE: &'static str = "developer"; + const START_MARKER: &'static str = COLLABORATION_MODE_OPEN_TAG; + const END_MARKER: &'static str = COLLABORATION_MODE_CLOSE_TAG; + + fn body(&self) -> String { + self.instructions.clone() + } +} diff --git a/codex-rs/core/src/context/environment_context.rs b/codex-rs/core/src/context/environment_context.rs index c676bfb9d9..c4e77624f8 100644 --- a/codex-rs/core/src/context/environment_context.rs +++ b/codex-rs/core/src/context/environment_context.rs @@ -200,7 +200,7 @@ impl ContextualUserFragment for EnvironmentContext { lines.extend(subagents.lines().map(|line| format!(" {line}"))); lines.push(" ".to_string()); } - format!("\n{}", lines.join("\n")) + format!("\n{}\n", lines.join("\n")) } } diff --git a/codex-rs/core/src/context/fragment.rs b/codex-rs/core/src/context/fragment.rs index e0e6d03303..34f4a7c367 100644 --- a/codex-rs/core/src/context/fragment.rs +++ b/codex-rs/core/src/context/fragment.rs @@ -28,13 +28,16 @@ impl FragmentRegistration for FragmentRegistrationPro } } -/// Context payload that is injected as a user-authored message fragment. +/// Context payload that is injected as a message fragment. /// -/// Implementations own the response role, start/end markers used to recognize -/// the fragment, and provide the fragment body appended directly after the -/// start marker. The default helpers wrap that body and convert it into the -/// response item shape expected by model input assembly. -pub(crate) trait ContextualUserFragment { +/// Implementations own the response role and provide the exact fragment body. +/// Marked fragments also provide start/end markers used to recognize injected +/// context later. `render()` concatenates markers and body without adding +/// separators, so implementations should include any whitespace they need +/// between tags in `body()`. Unmarked fragments should leave both markers empty, +/// in which case the default helpers render only the body and never match +/// arbitrary text. +pub trait ContextualUserFragment { const ROLE: &'static str; const START_MARKER: &'static str; const END_MARKER: &'static str; @@ -45,6 +48,10 @@ pub(crate) trait ContextualUserFragment { where Self: Sized, { + if Self::START_MARKER.is_empty() || Self::END_MARKER.is_empty() { + return false; + } + let trimmed = text.trim_start(); let starts_with_marker = trimmed .get(..Self::START_MARKER.len()) @@ -57,12 +64,11 @@ pub(crate) trait ContextualUserFragment { } fn render(&self) -> String { - format!( - "{}{}\n{}", - Self::START_MARKER, - self.body(), - Self::END_MARKER - ) + if Self::START_MARKER.is_empty() && Self::END_MARKER.is_empty() { + return self.body(); + } + + format!("{}{}{}", Self::START_MARKER, self.body(), Self::END_MARKER) } fn into(self) -> ResponseItem diff --git a/codex-rs/core/src/context/guardian_followup_review_reminder.rs b/codex-rs/core/src/context/guardian_followup_review_reminder.rs new file mode 100644 index 0000000000..972355ba95 --- /dev/null +++ b/codex-rs/core/src/context/guardian_followup_review_reminder.rs @@ -0,0 +1,21 @@ +use super::ContextualUserFragment; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) struct GuardianFollowupReviewReminder; + +impl ContextualUserFragment for GuardianFollowupReviewReminder { + const ROLE: &'static str = "developer"; + const START_MARKER: &'static str = ""; + const END_MARKER: &'static str = ""; + + fn body(&self) -> String { + concat!( + "Use prior reviews as context, not binding precedent. ", + "Follow the Workspace Policy. ", + "If the user explicitly approves a previously rejected action after being informed of the ", + "concrete risks, set outcome to \"allow\" unless the policy explicitly disallows user ", + "overwrites in such cases." + ) + .to_string() + } +} diff --git a/codex-rs/core/src/context/hook_additional_context.rs b/codex-rs/core/src/context/hook_additional_context.rs new file mode 100644 index 0000000000..01c95a6524 --- /dev/null +++ b/codex-rs/core/src/context/hook_additional_context.rs @@ -0,0 +1,22 @@ +use super::ContextualUserFragment; + +#[derive(Debug, Clone, PartialEq)] +pub(crate) struct HookAdditionalContext { + text: String, +} + +impl HookAdditionalContext { + pub(crate) fn new(text: impl Into) -> Self { + Self { text: text.into() } + } +} + +impl ContextualUserFragment for HookAdditionalContext { + const ROLE: &'static str = "developer"; + const START_MARKER: &'static str = ""; + const END_MARKER: &'static str = ""; + + fn body(&self) -> String { + self.text.clone() + } +} diff --git a/codex-rs/core/src/context/image_generation_instructions.rs b/codex-rs/core/src/context/image_generation_instructions.rs new file mode 100644 index 0000000000..01abee9096 --- /dev/null +++ b/codex-rs/core/src/context/image_generation_instructions.rs @@ -0,0 +1,30 @@ +use super::ContextualUserFragment; +use std::fmt::Display; + +#[derive(Debug, Clone, PartialEq)] +pub(crate) struct ImageGenerationInstructions { + image_output_dir: String, + image_output_path: String, +} + +impl ImageGenerationInstructions { + pub(crate) fn new(image_output_dir: impl Display, image_output_path: impl Display) -> Self { + Self { + image_output_dir: image_output_dir.to_string(), + image_output_path: image_output_path.to_string(), + } + } +} + +impl ContextualUserFragment for ImageGenerationInstructions { + const ROLE: &'static str = "developer"; + const START_MARKER: &'static str = ""; + const END_MARKER: &'static str = ""; + + fn body(&self) -> String { + format!( + "Generated images are saved to {} as {} by default.\nIf you need to use a generated image at another path, copy it and leave the original in place unless the user explicitly asks you to delete it.", + self.image_output_dir, self.image_output_path + ) + } +} diff --git a/codex-rs/core/src/context/mod.rs b/codex-rs/core/src/context/mod.rs index 94c5849f9d..bbc5bcacf1 100644 --- a/codex-rs/core/src/context/mod.rs +++ b/codex-rs/core/src/context/mod.rs @@ -1,20 +1,56 @@ +//! Context fragments injected into model input. + +mod approved_command_prefix_saved; +mod apps_instructions; +mod available_plugins_instructions; +mod available_skills_instructions; +mod collaboration_mode_instructions; mod contextual_user_message; mod environment_context; mod fragment; +mod guardian_followup_review_reminder; +mod hook_additional_context; +mod image_generation_instructions; +mod model_switch_instructions; +mod network_rule_saved; +mod permissions_instructions; +mod personality_spec_instructions; +mod plugin_instructions; +mod realtime_end_instructions; +mod realtime_start_instructions; +mod realtime_start_with_instructions; mod skill_instructions; +mod spawn_agent_instructions; mod subagent_notification; mod turn_aborted; mod user_instructions; mod user_shell_command; +pub(crate) use approved_command_prefix_saved::ApprovedCommandPrefixSaved; +pub(crate) use apps_instructions::AppsInstructions; +pub(crate) use available_plugins_instructions::AvailablePluginsInstructions; +pub(crate) use available_skills_instructions::AvailableSkillsInstructions; +pub(crate) use collaboration_mode_instructions::CollaborationModeInstructions; pub(crate) use contextual_user_message::is_contextual_user_fragment; pub(crate) use contextual_user_message::is_memory_excluded_contextual_user_fragment; pub(crate) use contextual_user_message::parse_visible_hook_prompt_message; pub(crate) use environment_context::EnvironmentContext; -pub(crate) use fragment::ContextualUserFragment; +pub use fragment::ContextualUserFragment; pub(crate) use fragment::FragmentRegistration; pub(crate) use fragment::FragmentRegistrationProxy; +pub(crate) use guardian_followup_review_reminder::GuardianFollowupReviewReminder; +pub(crate) use hook_additional_context::HookAdditionalContext; +pub(crate) use image_generation_instructions::ImageGenerationInstructions; +pub(crate) use model_switch_instructions::ModelSwitchInstructions; +pub(crate) use network_rule_saved::NetworkRuleSaved; +pub use permissions_instructions::PermissionsInstructions; +pub(crate) use personality_spec_instructions::PersonalitySpecInstructions; +pub(crate) use plugin_instructions::PluginInstructions; +pub(crate) use realtime_end_instructions::RealtimeEndInstructions; +pub(crate) use realtime_start_instructions::RealtimeStartInstructions; +pub(crate) use realtime_start_with_instructions::RealtimeStartWithInstructions; pub(crate) use skill_instructions::SkillInstructions; +pub(crate) use spawn_agent_instructions::SpawnAgentInstructions; pub(crate) use subagent_notification::SubagentNotification; pub(crate) use turn_aborted::TurnAborted; pub(crate) use user_instructions::UserInstructions; diff --git a/codex-rs/core/src/context/model_switch_instructions.rs b/codex-rs/core/src/context/model_switch_instructions.rs new file mode 100644 index 0000000000..0b75afb61a --- /dev/null +++ b/codex-rs/core/src/context/model_switch_instructions.rs @@ -0,0 +1,27 @@ +use super::ContextualUserFragment; + +#[derive(Debug, Clone, PartialEq)] +pub(crate) struct ModelSwitchInstructions { + model_instructions: String, +} + +impl ModelSwitchInstructions { + pub(crate) fn new(model_instructions: impl Into) -> Self { + Self { + model_instructions: model_instructions.into(), + } + } +} + +impl ContextualUserFragment for ModelSwitchInstructions { + const ROLE: &'static str = "developer"; + const START_MARKER: &'static str = ""; + const END_MARKER: &'static str = ""; + + fn body(&self) -> String { + format!( + "\nThe user was previously using a different model. Please continue the conversation according to the following instructions:\n\n{}\n", + self.model_instructions + ) + } +} diff --git a/codex-rs/core/src/context/network_rule_saved.rs b/codex-rs/core/src/context/network_rule_saved.rs new file mode 100644 index 0000000000..8162e6bda2 --- /dev/null +++ b/codex-rs/core/src/context/network_rule_saved.rs @@ -0,0 +1,35 @@ +use super::ContextualUserFragment; +use codex_protocol::approvals::NetworkPolicyAmendment; +use codex_protocol::approvals::NetworkPolicyRuleAction; + +#[derive(Debug, Clone, PartialEq)] +pub(crate) struct NetworkRuleSaved { + action: NetworkPolicyRuleAction, + host: String, +} + +impl NetworkRuleSaved { + pub(crate) fn new(amendment: &NetworkPolicyAmendment) -> Self { + Self { + action: amendment.action, + host: amendment.host.clone(), + } + } +} + +impl ContextualUserFragment for NetworkRuleSaved { + const ROLE: &'static str = "developer"; + const START_MARKER: &'static str = ""; + const END_MARKER: &'static str = ""; + + fn body(&self) -> String { + let (action, list_name) = match self.action { + NetworkPolicyRuleAction::Allow => ("Allowed", "allowlist"), + NetworkPolicyRuleAction::Deny => ("Denied", "denylist"), + }; + format!( + "{action} network rule saved in execpolicy ({list_name}): {}", + self.host + ) + } +} diff --git a/codex-rs/core/src/context/permissions_instructions.rs b/codex-rs/core/src/context/permissions_instructions.rs new file mode 100644 index 0000000000..db420f7464 --- /dev/null +++ b/codex-rs/core/src/context/permissions_instructions.rs @@ -0,0 +1,316 @@ +use super::ContextualUserFragment; +use codex_execpolicy::Policy; +use codex_protocol::config_types::ApprovalsReviewer; +use codex_protocol::config_types::SandboxMode; +use codex_protocol::models::format_allow_prefixes; +use codex_protocol::protocol::AskForApproval; +use codex_protocol::protocol::GranularApprovalConfig; +use codex_protocol::protocol::NetworkAccess; +use codex_protocol::protocol::SandboxPolicy; +use codex_protocol::protocol::WritableRoot; +use codex_utils_template::Template; +use std::path::Path; +use std::sync::LazyLock; + +const APPROVAL_POLICY_NEVER: &str = include_str!("prompts/permissions/approval_policy/never.md"); +const APPROVAL_POLICY_UNLESS_TRUSTED: &str = + include_str!("prompts/permissions/approval_policy/unless_trusted.md"); +const APPROVAL_POLICY_ON_FAILURE: &str = + include_str!("prompts/permissions/approval_policy/on_failure.md"); +const APPROVAL_POLICY_ON_REQUEST_RULE: &str = + include_str!("prompts/permissions/approval_policy/on_request.md"); +const APPROVAL_POLICY_ON_REQUEST_RULE_REQUEST_PERMISSION: &str = + include_str!("prompts/permissions/approval_policy/on_request_rule_request_permission.md"); +const AUTO_REVIEW_APPROVAL_SUFFIX: &str = "`approvals_reviewer` is `auto_review`: Sandbox escalations with require_escalated will be reviewed for compliance with the policy. If a rejection happens, you should proceed only with a materially safer alternative, or inform the user of the risk and send a final message to ask for approval."; + +const SANDBOX_MODE_DANGER_FULL_ACCESS: &str = + include_str!("prompts/permissions/sandbox_mode/danger_full_access.md"); +const SANDBOX_MODE_WORKSPACE_WRITE: &str = + include_str!("prompts/permissions/sandbox_mode/workspace_write.md"); +const SANDBOX_MODE_READ_ONLY: &str = include_str!("prompts/permissions/sandbox_mode/read_only.md"); + +static SANDBOX_MODE_DANGER_FULL_ACCESS_TEMPLATE: LazyLock