From 6ee9e03617715cae89b218c71bcef962cef88e8f Mon Sep 17 00:00:00 2001 From: TheArchitectit Date: Tue, 28 Jul 2026 07:42:30 -0500 Subject: [PATCH] fix: restore workspace unsafe_code=forbid, fix TaskClaim TOCTOU, remove TUI deps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Review fixes for PR #3250: 1. Restore workspace-level unsafe_code = "forbid" (was downgraded to "warn" for TUI support). The per-crate [lints.rust] unsafe_code = "allow" on rusty-claude-cli already overrides it where needed. 2. Fix TaskClaim TOCTOU race in claim_task(). Replace exists()-then-write with OpenOptions::create_new(true) which atomically fails if the lock file already exists, eliminating the race window between the check and the write. 3. Remove TUI scaffolding deps (ratatui, tui-textarea, gag, crossbeam-channel, libc, unicode-width) and the /tui slash command spec — these belong in a future TUI PR and are unused in the current source. Also updates the provider chain precedence test to reflect the new behavior where the caller's resolved model is the chain primary. Co-Authored-By: Claw --- rust/Cargo.lock | 248 +----------------------- rust/Cargo.toml | 4 +- rust/crates/commands/src/lib.rs | 9 +- rust/crates/rusty-claude-cli/Cargo.toml | 6 - rust/crates/tools/src/lib.rs | 40 ++-- 5 files changed, 29 insertions(+), 278 deletions(-) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 3b988b73..5c9d3e66 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -29,12 +29,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "allocator-api2" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" - [[package]] name = "anes" version = "0.1.6" @@ -361,27 +355,12 @@ version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" -[[package]] -name = "cassowary" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" - [[package]] name = "cast" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" -[[package]] -name = "castaway" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" -dependencies = [ - "rustversion", -] - [[package]] name = "cc" version = "1.2.58" @@ -542,20 +521,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "compact_str" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b79c4069c6cad78e2e0cdfcbd26275770669fb39fd308a752dc110e83b9af32" -dependencies = [ - "castaway", - "cfg-if", - "itoa", - "rustversion", - "ryu", - "static_assertions", -] - [[package]] name = "compat-harness" version = "0.1.3" @@ -650,15 +615,6 @@ dependencies = [ "itertools 0.10.5", ] -[[package]] -name = "crossbeam-channel" -version = "0.5.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "crossbeam-deque" version = "0.8.6" @@ -731,18 +687,8 @@ version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" dependencies = [ - "darling_core 0.20.11", - "darling_macro 0.20.11", -] - -[[package]] -name = "darling" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" -dependencies = [ - "darling_core 0.23.0", - "darling_macro 0.23.0", + "darling_core", + "darling_macro", ] [[package]] @@ -759,37 +705,13 @@ dependencies = [ "syn", ] -[[package]] -name = "darling_core" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" -dependencies = [ - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn", -] - [[package]] name = "darling_macro" version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ - "darling_core 0.20.11", - "quote", - "syn", -] - -[[package]] -name = "darling_macro" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" -dependencies = [ - "darling_core 0.23.0", + "darling_core", "quote", "syn", ] @@ -818,7 +740,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" dependencies = [ - "darling 0.20.11", + "darling", "proc-macro2", "quote", "syn", @@ -924,17 +846,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "filedescriptor" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e40758ed24c9b2eeb76c35fb0aebc66c626084edd827e07e1552279814c6682d" -dependencies = [ - "libc", - "thiserror 1.0.69", - "winapi", -] - [[package]] name = "find-msvc-tools" version = "0.1.9" @@ -957,12 +868,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - [[package]] name = "form_urlencoded" version = "1.2.2" @@ -1060,16 +965,6 @@ dependencies = [ "slab", ] -[[package]] -name = "gag" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a713bee13966e9fbffdf7193af71d54a6b35a0bb34997cd6c9519ebeb5005972" -dependencies = [ - "filedescriptor", - "tempfile", -] - [[package]] name = "generic-array" version = "0.14.7" @@ -1086,7 +981,7 @@ version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df" dependencies = [ - "unicode-width 0.2.0", + "unicode-width", ] [[package]] @@ -1180,17 +1075,6 @@ dependencies = [ "ahash", ] -[[package]] -name = "hashbrown" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" -dependencies = [ - "allocator-api2", - "equivalent", - "foldhash", -] - [[package]] name = "hashbrown" version = "0.16.1" @@ -1491,28 +1375,6 @@ dependencies = [ "hashbrown 0.16.1", ] -[[package]] -name = "indoc" -version = "2.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" -dependencies = [ - "rustversion", -] - -[[package]] -name = "instability" -version = "0.3.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eb2d60ef19920a3a9193c3e371f726ec1dafc045dac788d0fb3704272458971" -dependencies = [ - "darling 0.23.0", - "indoc", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "ipnet" version = "2.12.0" @@ -1638,15 +1500,6 @@ version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" -[[package]] -name = "lru" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" -dependencies = [ - "hashbrown 0.15.5", -] - [[package]] name = "lru-slab" version = "0.1.2" @@ -1813,12 +1666,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - [[package]] name = "percent-encoding" version = "2.3.2" @@ -2160,27 +2007,6 @@ dependencies = [ "getrandom 0.3.4", ] -[[package]] -name = "ratatui" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b" -dependencies = [ - "bitflags", - "cassowary", - "compact_str", - "crossterm", - "indoc", - "instability", - "itertools 0.13.0", - "lru", - "paste", - "strum", - "unicode-segmentation", - "unicode-truncate", - "unicode-width 0.2.0", -] - [[package]] name = "rayon" version = "1.12.0" @@ -2427,16 +2253,12 @@ version = "0.1.3" dependencies = [ "api", "commands", - "crossbeam-channel", "crossterm", - "gag", - "libc", "log", "mock-anthropic-service", "once_cell", "plugins", "pulldown-cmark", - "ratatui", "runtime", "rustyline", "serde", @@ -2444,8 +2266,6 @@ dependencies = [ "syntect", "tokio", "tools", - "tui-textarea", - "unicode-width 0.2.0", ] [[package]] @@ -2465,7 +2285,7 @@ dependencies = [ "nix", "radix_trie", "unicode-segmentation", - "unicode-width 0.2.0", + "unicode-width", "utf8parse", "windows-sys 0.59.0", ] @@ -2696,40 +2516,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" -[[package]] -name = "strum" -version = "0.26.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" -dependencies = [ - "strum_macros", -] - -[[package]] -name = "strum_macros" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "rustversion", - "syn", -] - [[package]] name = "subtle" version = "2.6.1" @@ -3174,17 +2966,6 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "tui-textarea" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a5318dd619ed73c52a9417ad19046724effc1287fb75cdcc4eca1d6ac1acbae" -dependencies = [ - "crossterm", - "ratatui", - "unicode-width 0.2.0", -] - [[package]] name = "typenum" version = "1.19.0" @@ -3209,23 +2990,6 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" -[[package]] -name = "unicode-truncate" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf" -dependencies = [ - "itertools 0.13.0", - "unicode-segmentation", - "unicode-width 0.1.14", -] - -[[package]] -name = "unicode-width" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" - [[package]] name = "unicode-width" version = "0.2.0" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 113bedd3..4ca7b8d8 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -12,9 +12,7 @@ publish = false serde_json = "1" [workspace.lints.rust] -# rusty-claude-cli needs unsafe for TUI stdout suppression (dup/dup2), -# all other crates should avoid it — override per-crate if needed. -unsafe_code = "warn" +unsafe_code = "forbid" [workspace.lints.clippy] all = { level = "warn", priority = -1 } diff --git a/rust/crates/commands/src/lib.rs b/rust/crates/commands/src/lib.rs index a679a45d..3943f03d 100644 --- a/rust/crates/commands/src/lib.rs +++ b/rust/crates/commands/src/lib.rs @@ -65,13 +65,6 @@ const SLASH_COMMAND_SPECS: &[SlashCommandSpec] = &[ argument_hint: None, resume_supported: true, }, - SlashCommandSpec { - name: "tui", - aliases: &[], - summary: "Switch to the split-pane TUI dashboard", - argument_hint: None, - resume_supported: true, - }, SlashCommandSpec { name: "status", aliases: &[], @@ -6037,7 +6030,7 @@ mod tests { assert!(!help.contains("/login")); assert!(!help.contains("/logout")); assert!(help.contains("/setup")); - assert_eq!(slash_command_specs().len(), 141); + assert_eq!(slash_command_specs().len(), 140); assert!(resume_supported_slash_commands().len() >= 39); } diff --git a/rust/crates/rusty-claude-cli/Cargo.toml b/rust/crates/rusty-claude-cli/Cargo.toml index e89a4cd8..29bcc92f 100644 --- a/rust/crates/rusty-claude-cli/Cargo.toml +++ b/rust/crates/rusty-claude-cli/Cargo.toml @@ -13,13 +13,9 @@ path = "src/main.rs" api = { path = "../api" } commands = { path = "../commands" } crossterm = "0.28" -crossbeam-channel = "0.5" -gag = "1" pulldown-cmark = "0.13" once_cell = "1" -ratatui = "0.29" rustyline = "15" -tui-textarea = "0.7" runtime = { path = "../runtime" } plugins = { path = "../plugins" } serde = { version = "1", features = ["derive"] } @@ -28,8 +24,6 @@ syntect = "5" tokio = { version = "1", features = ["rt-multi-thread", "signal", "time"] } tools = { path = "../tools" } log = "0.4" -libc = "0.2" -unicode-width = "0.2" [lints.rust] diff --git a/rust/crates/tools/src/lib.rs b/rust/crates/tools/src/lib.rs index da661e84..774a9342 100644 --- a/rust/crates/tools/src/lib.rs +++ b/rust/crates/tools/src/lib.rs @@ -2797,9 +2797,6 @@ fn claim_task(task_id: &str, agent_id: &str, team_id: &str) -> Result Result Ok(true), - Err(_) => { - // Another agent claimed it first - let _ = std::fs::remove_file(&tmp_path); - Ok(false) + // Atomic claim: create_new fails atomically if the file already exists, + // eliminating the TOCTOU race between exists() and write(). + let content = serde_json::to_string_pretty(&entry).map_err(|e| e.to_string())?; + match std::fs::OpenOptions::new() + .write(true) + .create_new(true) + .open(&lock_path) + { + Ok(mut file) => { + use std::io::Write; + file.write_all(content.as_bytes()) + .map_err(|e| e.to_string())?; + Ok(true) } + Err(ref e) if e.kind() == std::io::ErrorKind::AlreadyExists => Ok(false), + Err(e) => Err(e.to_string()), } } @@ -12316,9 +12315,12 @@ printf 'pwsh:%s' "$1" .expect("chain with primary override should construct"); // then - assert_eq!(client.chain.len(), 2); - assert_eq!(client.chain[0].model, "grok-3"); - assert_eq!(client.chain[1].model, "claude-sonnet-4-6"); + // The caller's model is now the primary; fallbacks are appended + // as recovery entries, deduped. + assert_eq!(client.chain.len(), 3); + assert_eq!(client.chain[0].model, "claude-haiku-4-5-20251213"); + assert_eq!(client.chain[1].model, "grok-3"); + assert_eq!(client.chain[2].model, "claude-sonnet-4-6"); match original_anthropic { Some(value) => std::env::set_var("ANTHROPIC_API_KEY", value),