From 6a17d035f79ad582ca3f4f3cdc38d376f2c4087f Mon Sep 17 00:00:00 2001 From: Wes Date: Sat, 8 Aug 2026 09:43:44 -0600 Subject: [PATCH 01/18] Revert "fix(acp): reject unattended permission requests" (#5323) Reverts block/buzz#4609 --- crates/buzz-acp/src/acp.rs | 193 ++++++++++++++-------------------- crates/buzz-acp/src/config.rs | 51 +++++---- crates/buzz-acp/src/lib.rs | 4 +- crates/buzz-acp/src/pool.rs | 16 +-- 4 files changed, 116 insertions(+), 148 deletions(-) diff --git a/crates/buzz-acp/src/acp.rs b/crates/buzz-acp/src/acp.rs index 93109fa94d..700d5e8dcf 100644 --- a/crates/buzz-acp/src/acp.rs +++ b/crates/buzz-acp/src/acp.rs @@ -155,7 +155,7 @@ pub struct AcpClient { /// a `cancelled` outcome before the agent returns from `session/prompt`. pending_permission_id: Option, /// Whether we have already sent a response to the pending permission request. - /// Guards against double-response if a timeout fires after the rejection + /// Guards against double-response if a timeout fires after the allow_once /// response was written but before `pending_permission_id` was cleared. permission_responded: bool, /// The JSON-RPC id of the most recently sent `session/prompt` request. @@ -1162,8 +1162,7 @@ impl AcpClient { /// /// While waiting, handles: /// - `session/update` notifications → logged via tracing - /// - `session/request_permission` requests → rejected unless an owner has - /// already selected a non-interactive permission mode at session setup + /// - `session/request_permission` requests → auto-approved with `allow_once` /// - Any other messages → debug-logged and ignored; if they carry an `id` /// (i.e. they are requests, not notifications), a JSON-RPC -32601 error is sent. /// @@ -1871,12 +1870,12 @@ impl AcpClient { } } - /// Reject a `session/request_permission` request from the agent. + /// Auto-approve a `session/request_permission` request from the agent. /// - /// Buzz has no human permission prompt in this harness, so selecting - /// `allow_once` would turn any admitted prompt into an implicit approval. - /// Find `reject_once` by kind when the adapter offers it; otherwise use the - /// protocol's cancelled outcome, which is also fail-closed. + /// Finds the option with `kind == "allow_once"` and responds with its `optionId`. + /// If no `allow_once` option exists, falls back to `reject_once`. + /// + /// **Critical:** Never hardcode `optionId` — always find it dynamically by `kind`. /// /// The request `id` is stored as `serde_json::Value` to support both numeric /// and string IDs per JSON-RPC 2.0. @@ -1902,7 +1901,40 @@ impl AcpClient { options.len() ); - let response = permission_denial_response(&id, options)?; + // Find allow_once by kind — NEVER hardcode optionId. + let allow_once = options + .iter() + .find(|opt| opt.get("kind").and_then(|k| k.as_str()) == Some("allow_once")); + + let response = if let Some(opt) = allow_once { + let option_id = opt["optionId"] + .as_str() + .ok_or_else(|| AcpError::Protocol("allow_once option missing optionId".into()))?; + tracing::info!( + target: "acp::permission", + "auto-approving permission id={id} with allow_once optionId={option_id:?}" + ); + permission_response_selected(&id, option_id) + } else { + // No allow_once — fall back to reject_once. + tracing::warn!( + target: "acp::permission", + "no allow_once option found in permission request id={id}, falling back to reject_once" + ); + let reject = options + .iter() + .find(|opt| opt.get("kind").and_then(|k| k.as_str()) == Some("reject_once")); + + if let Some(opt) = reject { + let option_id = opt["optionId"].as_str().unwrap_or("reject"); + permission_response_selected(&id, option_id) + } else { + return Err(AcpError::Protocol( + "no suitable permission option found (neither allow_once nor reject_once)" + .into(), + )); + } + }; // Write the response first, then mark as responded. // @@ -2014,42 +2046,6 @@ fn permission_response_cancelled(id: &serde_json::Value) -> serde_json::Value { }) } -/// Choose the fail-closed response to a `session/request_permission` request. -/// -/// Buzz has no human permission prompt in this harness, so selecting -/// `allow_once` would turn any admitted prompt into an implicit approval. -/// Prefer the adapter's `reject_once` option — matched by `kind`, never by a -/// hardcoded `optionId` — and fall back to the protocol's cancelled outcome for -/// adapters that do not offer one. Both answers deny. -/// -/// Kept free of the client so the decision is testable without an agent -/// subprocess: `AcpClient` owns a real `Child` and its stdio pipes. -fn permission_denial_response( - id: &serde_json::Value, - options: &[serde_json::Value], -) -> Result { - let reject_once = options - .iter() - .find(|opt| opt.get("kind").and_then(|k| k.as_str()) == Some("reject_once")); - - let Some(opt) = reject_once else { - tracing::warn!( - target: "acp::permission", - "no reject_once option found in permission request id={id}, cancelling" - ); - return Ok(permission_response_cancelled(id)); - }; - - let option_id = opt["optionId"] - .as_str() - .ok_or_else(|| AcpError::Protocol("reject_once option missing optionId".into()))?; - tracing::info!( - target: "acp::permission", - "rejecting permission id={id} with reject_once optionId={option_id:?}" - ); - Ok(permission_response_selected(id, option_id)) -} - /// Full `session/new` response — session ID plus the raw JSON result. /// /// Callers use the extractor helpers to pull model info from `raw`. @@ -2304,96 +2300,63 @@ mod tests { assert_eq!(StopReason::from_str("Refusal"), Some(StopReason::Refusal)); } - fn options(json: &str) -> Vec { - serde_json::from_str(json).expect("option list") - } - - fn outcome(response: &serde_json::Value) -> Option<&str> { - response["result"]["outcome"]["outcome"].as_str() - } - - /// The offered `allow_once` and `allow_always` options must be ignored: - /// there is no human to click them, so choosing either would make every - /// admitted prompt an implicit approval. `optionId`s are deliberately - /// non-obvious to prove they are matched by `kind`, never hardcoded. #[test] - fn permission_requests_select_reject_once_not_allow_once() { - let options = options( + fn find_allow_once_by_kind_not_by_option_id() { + // optionId values are intentionally non-obvious to prove we don't hardcode them. + let options: Vec = serde_json::from_str( r#"[ {"optionId": "opt-reject-42", "name": "Reject", "kind": "reject_once"}, {"optionId": "opt-allow-99", "name": "Allow once", "kind": "allow_once"}, {"optionId": "opt-always-7", "name": "Always allow", "kind": "allow_always"} ]"#, - ); + ) + .unwrap(); - let response = - permission_denial_response(&serde_json::json!(7), &options).expect("denial response"); + let allow_once = options + .iter() + .find(|opt| opt.get("kind").and_then(|k| k.as_str()) == Some("allow_once")); - assert_eq!(outcome(&response), Some("selected")); - assert_eq!( - response["result"]["outcome"]["optionId"].as_str(), - Some("opt-reject-42"), - "must select reject_once even when allow options are offered" - ); + assert!(allow_once.is_some(), "should find allow_once option"); + let opt = allow_once.unwrap(); + // Found by kind, not by hardcoded optionId + assert_eq!(opt["kind"].as_str(), Some("allow_once")); + assert_eq!(opt["optionId"].as_str(), Some("opt-allow-99")); } - /// Fail-closed backstop: an adapter that offers no `reject_once` must still - /// be denied, via the protocol's cancelled outcome rather than an error or - /// an approval. #[test] - fn permission_request_without_reject_once_is_cancelled() { - let options = options( + fn find_allow_once_returns_none_when_absent() { + let options: Vec = serde_json::from_str( r#"[ - {"optionId": "opt-allow-99", "name": "Allow once", "kind": "allow_once"}, - {"optionId": "opt-always-7", "name": "Always allow", "kind": "allow_always"} + {"optionId": "reject-1", "name": "Reject", "kind": "reject_once"}, + {"optionId": "reject-always", "name": "Always reject", "kind": "reject_always"} ]"#, - ); - - let response = permission_denial_response(&serde_json::json!("req-1"), &options) - .expect("cancelled response"); - - assert_eq!(outcome(&response), Some("cancelled")); - assert_eq!( - response["id"].as_str(), - Some("req-1"), - "string ids must round-trip per JSON-RPC 2.0" - ); - } - - /// An empty option list is the degenerate form of the same backstop. - #[test] - fn permission_request_with_no_options_is_cancelled() { - let response = - permission_denial_response(&serde_json::json!(1), &[]).expect("cancelled response"); - - assert_eq!(outcome(&response), Some("cancelled")); - } - - /// A `reject_once` option missing its `optionId` is a protocol violation. - /// Erroring propagates to the caller, which tears the turn down — still no - /// approval is ever sent. - #[test] - fn reject_once_without_option_id_is_a_protocol_error() { - let options = options(r#"[{"name": "Reject", "kind": "reject_once"}]"#); + ) + .unwrap(); - let err = permission_denial_response(&serde_json::json!(1), &options) - .expect_err("missing optionId must error"); + let allow_once = options + .iter() + .find(|opt| opt.get("kind").and_then(|k| k.as_str()) == Some("allow_once")); - assert!(matches!(err, AcpError::Protocol(_)), "got {err:?}"); + assert!(allow_once.is_none()); } #[test] - fn find_reject_once_by_kind() { - let options = - options(r#"[{"optionId": "rej-x", "name": "Reject", "kind": "reject_once"}]"#); + fn find_reject_once_fallback_when_no_allow_once() { + let options: Vec = serde_json::from_str( + r#"[{"optionId": "rej-x", "name": "Reject", "kind": "reject_once"}]"#, + ) + .unwrap(); - let response = - permission_denial_response(&serde_json::json!(1), &options).expect("denial response"); + let allow_once = options + .iter() + .find(|opt| opt.get("kind").and_then(|k| k.as_str()) == Some("allow_once")); + assert!(allow_once.is_none()); - assert_eq!( - response["result"]["outcome"]["optionId"].as_str(), - Some("rej-x") - ); + let reject_once = options + .iter() + .find(|opt| opt.get("kind").and_then(|k| k.as_str()) == Some("reject_once")); + assert!(reject_once.is_some()); + assert_eq!(reject_once.unwrap()["optionId"].as_str(), Some("rej-x")); } #[test] diff --git a/crates/buzz-acp/src/config.rs b/crates/buzz-acp/src/config.rs index d959685846..35aaec188d 100644 --- a/crates/buzz-acp/src/config.rs +++ b/crates/buzz-acp/src/config.rs @@ -116,6 +116,7 @@ impl std::fmt::Display for RespondTo { /// /// - `default` — agent's built-in behaviour (permission requests per tool call). /// - `acceptEdits` — auto-approve file edits, still ask for other tools. +/// - `bypassPermissions` — skip the permission flow entirely. /// - `dontAsk` — never prompt; reject anything that would require permission. /// - `plan` — planning-only mode (no tool execution). #[derive(Debug, Clone, Copy, PartialEq, clap::ValueEnum)] @@ -126,6 +127,9 @@ pub enum PermissionMode { /// Auto-approve file edits, still ask for other tools. #[value(alias = "acceptEdits")] AcceptEdits, + /// Skip the permission flow entirely. + #[value(alias = "bypassPermissions")] + BypassPermissions, /// Never prompt; reject anything that would require permission. #[value(alias = "dontAsk")] DontAsk, @@ -141,6 +145,7 @@ impl PermissionMode { match self { Self::Default => "default", Self::AcceptEdits => "acceptEdits", + Self::BypassPermissions => "bypassPermissions", Self::DontAsk => "dontAsk", Self::Plan => "plan", } @@ -427,12 +432,13 @@ pub struct CliArgs { /// Permission mode for agents that support `session/set_config_option` /// with `configId: "mode"` (e.g. `claude-agent-acp`). /// - /// Defaults to `dontAsk`, which rejects operations that need interactive - /// approval because Buzz does not expose a human permission prompt. + /// Defaults to `bypassPermissions` which skips the per-tool-call + /// permission flow. Set to `default` to restore the agent's built-in + /// behaviour. #[arg( long, env = "BUZZ_ACP_PERMISSION_MODE", - default_value = "dont-ask", + default_value = "bypass-permissions", value_enum )] pub permission_mode: PermissionMode, @@ -1463,7 +1469,7 @@ mod tests { memory_enabled: true, model: None, session_title: None, - permission_mode: PermissionMode::DontAsk, + permission_mode: PermissionMode::BypassPermissions, respond_to: RespondTo::Anyone, respond_to_allowlist: HashSet::new(), allowed_respond_to: Vec::new(), @@ -2264,6 +2270,10 @@ channels = "ALL" fn test_permission_mode_wire_strings() { assert_eq!(PermissionMode::Default.as_wire_str(), "default"); assert_eq!(PermissionMode::AcceptEdits.as_wire_str(), "acceptEdits"); + assert_eq!( + PermissionMode::BypassPermissions.as_wire_str(), + "bypassPermissions" + ); assert_eq!(PermissionMode::DontAsk.as_wire_str(), "dontAsk"); assert_eq!(PermissionMode::Plan.as_wire_str(), "plan"); } @@ -2271,6 +2281,7 @@ channels = "ALL" #[test] fn test_permission_mode_is_default() { assert!(PermissionMode::Default.is_default()); + assert!(!PermissionMode::BypassPermissions.is_default()); assert!(!PermissionMode::AcceptEdits.is_default()); assert!(!PermissionMode::DontAsk.is_default()); assert!(!PermissionMode::Plan.is_default()); @@ -2278,17 +2289,20 @@ channels = "ALL" #[test] fn test_permission_mode_display() { - assert_eq!(format!("{}", PermissionMode::DontAsk), "dontAsk"); + assert_eq!( + format!("{}", PermissionMode::BypassPermissions), + "bypassPermissions" + ); assert_eq!(format!("{}", PermissionMode::Default), "default"); } #[test] fn test_summary_includes_permission_mode() { let mut config = test_config(SubscribeMode::Mentions); - config.permission_mode = PermissionMode::DontAsk; + config.permission_mode = PermissionMode::BypassPermissions; let s = config.summary(); assert!( - s.contains("permission_mode=dontAsk"), + s.contains("permission_mode=bypassPermissions"), "summary should include permission_mode, got: {s}" ); } @@ -2305,9 +2319,9 @@ channels = "ALL" } #[test] - fn test_default_config_rejects_interactive_permissions() { + fn test_default_config_uses_bypass_permissions() { let config = test_config(SubscribeMode::Mentions); - assert_eq!(config.permission_mode, PermissionMode::DontAsk); + assert_eq!(config.permission_mode, PermissionMode::BypassPermissions); } #[test] @@ -2318,6 +2332,7 @@ channels = "ALL" let cases = [ ("default", PermissionMode::Default), ("accept-edits", PermissionMode::AcceptEdits), + ("bypass-permissions", PermissionMode::BypassPermissions), ("dont-ask", PermissionMode::DontAsk), ("plan", PermissionMode::Plan), ]; @@ -2332,12 +2347,14 @@ channels = "ALL" #[test] fn test_permission_mode_value_enum_camel_case_aliases() { - // Operators may set env vars using the camelCase wire-format strings. - // The #[value(alias)] attributes ensure these parse correctly. + // Operators may set env vars using the camelCase wire-format strings + // (e.g. BUZZ_ACP_PERMISSION_MODE=bypassPermissions). The #[value(alias)] + // attributes ensure these parse correctly. use clap::ValueEnum; let cases = [ ("default", PermissionMode::Default), ("acceptEdits", PermissionMode::AcceptEdits), + ("bypassPermissions", PermissionMode::BypassPermissions), ("dontAsk", PermissionMode::DontAsk), ("plan", PermissionMode::Plan), ]; @@ -2350,18 +2367,6 @@ channels = "ALL" } } - #[test] - fn test_permission_mode_rejects_unattended_bypass() { - use clap::ValueEnum; - - for input in ["bypass-permissions", "bypassPermissions"] { - assert!( - PermissionMode::from_str(input, true).is_err(), - "{input:?} must not disable the ACP permission boundary" - ); - } - } - /// Helper: resolve idle_timeout_secs using the same precedence logic as Config::from_args. /// Precedence: explicit --idle-timeout > --turn-timeout (deprecated) > `DEFAULT_IDLE_TIMEOUT_SECS`. fn resolve_idle_timeout(idle: Option, turn: Option) -> u64 { diff --git a/crates/buzz-acp/src/lib.rs b/crates/buzz-acp/src/lib.rs index 65c9dd6203..b69a1f453a 100644 --- a/crates/buzz-acp/src/lib.rs +++ b/crates/buzz-acp/src/lib.rs @@ -6199,7 +6199,7 @@ mod build_mcp_servers_tests { memory_enabled: false, model: None, session_title: None, - permission_mode: config::PermissionMode::DontAsk, + permission_mode: config::PermissionMode::BypassPermissions, respond_to: config::RespondTo::Anyone, respond_to_allowlist: std::collections::HashSet::new(), allowed_respond_to: vec![], @@ -6421,7 +6421,7 @@ mod error_outcome_emission_tests { memory_enabled: false, model: None, session_title: None, - permission_mode: config::PermissionMode::DontAsk, + permission_mode: config::PermissionMode::BypassPermissions, respond_to: config::RespondTo::Anyone, respond_to_allowlist: HashSet::new(), allowed_respond_to: vec![], diff --git a/crates/buzz-acp/src/pool.rs b/crates/buzz-acp/src/pool.rs index 8430307d9c..ddc0330d9f 100644 --- a/crates/buzz-acp/src/pool.rs +++ b/crates/buzz-acp/src/pool.rs @@ -1017,7 +1017,7 @@ async fn create_session_and_apply_model( // Apply permission mode if not the agent's built-in default AND the agent // advertises the requested mode in session/new. Agents that don't support // the mode (e.g., goose crashes on unrecognized set_config_option values) - // are safely skipped — the harness rejects interactive permission requests. + // are safely skipped — the harness auto-approves via handle_permission_request. if !ctx.permission_mode.is_default() && agent_supports_mode(&resp.raw, ctx.permission_mode.as_wire_str()) { @@ -1130,7 +1130,11 @@ async fn apply_model_switch( Ok(()) } -/// Check whether the agent's `session/new` response advertises a given mode ID +/// Set the session permission mode via `session/set_config_option`. +/// +/// Non-fatal for most errors: logs and proceeds. The agent falls back +/// to its default permission mode (`"default"`), which still works via +/// Check if the agent's `session/new` response advertises a given mode ID /// in `result.modes.availableModes[].id`. Returns `false` if the modes /// field is absent or the mode isn't listed. fn agent_supports_mode(session_new_result: &serde_json::Value, mode_wire: &str) -> bool { @@ -1146,11 +1150,7 @@ fn agent_supports_mode(session_new_result: &serde_json::Value, mode_wire: &str) .unwrap_or(false) } -/// Set the session permission mode via `session/set_config_option`. -/// -/// Non-fatal for most errors: logs and proceeds. The agent falls back to its -/// default mode, and any interactive permission request is rejected by -/// `handle_permission_request`. +/// per-tool auto-approval in `handle_permission_request`. /// /// **Fatal exception:** if the agent process exits (e.g., goose crashes on /// unrecognized methods), returns `Err(AgentExited)` so the caller can respawn. @@ -1190,7 +1190,7 @@ async fn apply_permission_mode( Ok(Err(e)) => { tracing::warn!( target: "pool::permission", - "failed to set permission mode {wire:?}: {e} — falling back to per-tool rejection" + "failed to set permission mode {wire:?}: {e} — falling back to per-tool auto-approval" ); } Err(_) => { From 261c46076166c6de5bb9a71fb4a0fd0b70aa1efa Mon Sep 17 00:00:00 2001 From: Tyler <109685178+tlongwell-block@users.noreply.github.com> Date: Sat, 8 Aug 2026 12:17:22 -0400 Subject: [PATCH 02/18] fix(buzz-agent): recover from 400-shaped image rejections; unbound benchmark agent rounds (#5318) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Problem Two failure modes from the `tb21-glm52-crusoe-1` benchmark run (GLM-5.2 solo, TB2.1) wedged or killed 13 of 89 trials without the model being at fault: 1. **Conversation poisoning on text-only endpoints.** Crusoe's serverless `crusoeai/GLM-5.2-NVFP4` rejects any request whose history contains an image with `400: ... is not a multimodal model`. The recovery machinery for exactly this case already exists — `AgentError::UnsupportedImageInput` → `replace_unsupported_images()` strips the image blocks, marks the tool result as an error, substitutes a text placeholder, and continues the turn. But classification only matched OpenRouter's 404 body (`no endpoints found that support image input`) and was only consulted on the 404 arms. The Crusoe 400 fell through to terminal `AgentError::Llm`: the image stayed in history, every subsequent call failed identically, buzz-acp rode its 10-retry ladder (~40 min), and the trial idled to budget death. Measured blast radius: **8 trials wedged, 12.7h aggregate idle-after-poison.** 2. **Bounded agent rounds in benchmark trials.** The harness default `DEFAULT_MAX_AGENT_ROUNDS = 32` ended solo trials mid-work when turns rotated (thinking-heavy models hit max_tokens rotation fast; 4 trials died this way). Benchmark trials already have a wall-clock budget as the real limit — the round cap only converts recoverable rotation into trial death. ## Fix - `is_unsupported_image_input_error()` also matches the verbatim `is not a multimodal model` body. Matcher stays deliberately tight (same doctrine as `is_context_length_error`): misclassifying a generic 400 as recoverable would mutate history for an error that removing images cannot fix. - Both status ladders — shared `post()` and `openrouter_post()` — consult it on their 400 arms and return the typed `UnsupportedImageInput` (OpenAI-compatible providers report this as 400; a BYOK/passthrough upstream can surface the provider's own 400 through OpenRouter). - Harness `DEFAULT_MAX_AGENT_ROUNDS` → `0` (unbounded — `BUZZ_AGENT_MAX_ROUNDS=0` is the agent config's documented unbounded value). Per-agent `budget.max_calls` in manifests still overrides. ## Acceptance - A 400 with the image-rejection body reaches the existing image-strip recovery path instead of wedging the session — asserted through `complete()` (covers the return path into the convergence mapper) and at the `openrouter_post` terminal, both proving single-attempt (a deterministic capability rejection must never be retried). - Ordinary 400s stay terminal `AgentError::Llm` (existing negative tests unchanged). - Benchmark trials run unbounded rounds by default; python tests updated for 0-is-legal with a negative arm at -1. ## Verification - `cargo test -p buzz-agent`: 427 + 18 + 20 + 15 + 8 + 1 + 48 passed, 0 failed (full package, 3 consecutive clean runs) - `cargo clippy -p buzz-agent --all-targets`, `cargo fmt --check`: clean - `uv run --extra dev pytest tests/` in harbor-buzz-orchestra: 35 passed - Pre-push hooks (full workspace rust-tests + desktop-tauri-checks) green on rustc 1.95.0 at head b0438602 Signed-off-by: Eva <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz> Co-authored-by: Eva <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz> --- .../container_runtime.py | 6 +- .../tests/test_container_runtime.py | 11 ++- crates/buzz-agent/src/llm.rs | 99 ++++++++++++++++++- 3 files changed, 107 insertions(+), 9 deletions(-) diff --git a/benchmarks/harbor-buzz-orchestra/src/harbor_buzz_orchestra/container_runtime.py b/benchmarks/harbor-buzz-orchestra/src/harbor_buzz_orchestra/container_runtime.py index ed883a820a..a0602111d1 100644 --- a/benchmarks/harbor-buzz-orchestra/src/harbor_buzz_orchestra/container_runtime.py +++ b/benchmarks/harbor-buzz-orchestra/src/harbor_buzz_orchestra/container_runtime.py @@ -24,7 +24,7 @@ from .provisioning import AgentCredential, TrialHandle from .runtime import RuntimeResult -DEFAULT_MAX_AGENT_ROUNDS = 32 +DEFAULT_MAX_AGENT_ROUNDS = 0 # 0 = unbounded (BUZZ_AGENT_MAX_ROUNDS=0); the trial budget is the clock # Container-side layout for the uploaded Buzz stack. REMOTE_ROOT = "/opt/buzz" REMOTE_BIN = f"{REMOTE_ROOT}/bin" @@ -80,8 +80,8 @@ def __init__( readiness_timeout_seconds: float = 60.0, poll_seconds: float = 1.0, ) -> None: - if max_agent_rounds <= 0: - raise ValueError("max_agent_rounds must be positive") + if max_agent_rounds < 0: + raise ValueError("max_agent_rounds must be >= 0 (0 = unbounded)") if readiness_timeout_seconds <= 0: raise ValueError("readiness_timeout_seconds must be positive") self.logs_dir = Path(logs_dir) diff --git a/benchmarks/harbor-buzz-orchestra/tests/test_container_runtime.py b/benchmarks/harbor-buzz-orchestra/tests/test_container_runtime.py index 5fc0e63e54..c0f5beeef2 100644 --- a/benchmarks/harbor-buzz-orchestra/tests/test_container_runtime.py +++ b/benchmarks/harbor-buzz-orchestra/tests/test_container_runtime.py @@ -247,7 +247,7 @@ async def test_forwarder_bridges_the_canonical_relay_address(tmp_path): rt._ws_authority("http://relay") -@pytest.mark.parametrize(("configured", "expected"), [(None, "32"), (7, "7")]) +@pytest.mark.parametrize(("configured", "expected"), [(None, "0"), (7, "7")]) async def test_launch_wires_the_desktop_environment(tmp_path, configured, expected): manifest = write_manifest(tmp_path) agent_class = manifest.roster[0] @@ -290,9 +290,12 @@ async def test_launch_wires_the_desktop_environment(tmp_path, configured, expect ) -def test_runtime_rejects_unbounded_agent_rounds(tmp_path): - with pytest.raises(ValueError, match="positive"): - runtime(tmp_path, max_agent_rounds=0) +def test_runtime_validates_construction_bounds(tmp_path): + # 0 is legal and means unbounded (BUZZ_AGENT_MAX_ROUNDS=0); the trial + # budget is the clock. Only negatives are rejected. + runtime(tmp_path, max_agent_rounds=0) + with pytest.raises(ValueError, match="unbounded"): + runtime(tmp_path, max_agent_rounds=-1) with pytest.raises(ValueError, match="positive"): runtime(tmp_path, readiness_timeout_seconds=0) diff --git a/crates/buzz-agent/src/llm.rs b/crates/buzz-agent/src/llm.rs index 289adbd1ad..dc9501aeef 100644 --- a/crates/buzz-agent/src/llm.rs +++ b/crates/buzz-agent/src/llm.rs @@ -1932,9 +1932,24 @@ fn classify_body_read_error( } } +/// Provider bodies that mean "this model cannot accept image input", the +/// signal the agent loop uses to strip rejected images from history and +/// continue the turn (see `replace_unsupported_images`). +/// +/// Deliberately tight, same doctrine as [`is_context_length_error`]: each +/// phrase is a verbatim capability rejection observed live. Misclassifying a +/// generic 400 as recoverable would mutate history for an error that removing +/// images cannot fix. fn is_unsupported_image_input_error(body: &str) -> bool { - body.to_ascii_lowercase() - .contains("no endpoints found that support image input") + let b = body.to_ascii_lowercase(); + // OpenRouter 404: no provider endpoint accepts images for this model. + b.contains("no endpoints found that support image input") + // OpenAI-compatible 400 from text-only single-model deployments, + // e.g. Crusoe serverless GLM: `"crusoeai/GLM-5.2-NVFP4 is not a + // multimodal model"`. Without this arm the 400 is terminal, the image + // stays in history, and every subsequent request in the session fails + // identically — the turn wedges until the harness/user gives up. + || b.contains("is not a multimodal model") } /// Build the terminal `AgentError::Llm` for a `post()` exit that has given up @@ -2129,6 +2144,13 @@ where "{status}: {body}" )))); } + // Image-capability rejection is equally recoverable and equally + // deterministic: a text-only deployment 400s the same request + // forever. Typed here (not just on the 404 arm) because + // OpenAI-compatible providers report it as a 400. + if status == 400 && is_unsupported_image_input_error(&body) { + return Err(PostError::Agent(AgentError::UnsupportedImageInput(body))); + } return Err(PostError::Agent(AgentError::Llm(format!( "{status}: {body}" )))); @@ -2535,6 +2557,12 @@ async fn openrouter_post( if status == 400 && is_context_length_error(&body) { return Err(AgentError::LlmContextExceeded(format!("{status}: {body}"))); } + // Same 400-shaped image rejection as the shared `post()` terminal: + // OpenRouter normally reports this as a 404 (handled above), but a + // BYOK/passthrough upstream can surface the provider's own 400. + if status == 400 && is_unsupported_image_input_error(&body) { + return Err(AgentError::UnsupportedImageInput(body)); + } return Err(AgentError::Llm(format!("{status}: {body}"))); } if let Some(len) = resp.content_length() { @@ -7544,6 +7572,73 @@ mod tests { ); } + /// OpenAI-compatible text-only deployments report the image rejection as a + /// 400, not OpenRouter's 404 — Crusoe serverless GLM answers + /// `"crusoeai/GLM-5.2-NVFP4 is not a multimodal model"` to every request + /// whose history contains an image. Before the 400 arm existed, this fell + /// through to terminal `AgentError::Llm`: the image stayed in history and + /// every later call in the session failed identically (measured live: + /// 8 wedged benchmark trials, 40 min of doomed retries each). Asserted + /// through `complete()` so the arm's return path into the convergence + /// mapper is covered, same doctrine as the context-400 tests above. + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn openai_400_unsupported_image_is_typed_through_complete() { + let (base_url, captured) = spawn_sequence_stub(vec![StubHttpResponse { + status: 400, + body: json!({"error":{"message":"crusoeai/GLM-5.2-NVFP4 is not a multimodal model","type":"invalid_request_error"}}), + }]) + .await; + let mut c = cfg(Provider::OpenAi); + c.base_url = base_url; + let llm = Llm::new(&c).unwrap(); + let err = complete_model(&llm, &c, "gpt-probe-model") + .await + .unwrap_err(); + assert!( + matches!(&err, AgentError::UnsupportedImageInput(s) if s.contains("not a multimodal model")), + "a text-only deployment's 400 must reach the history-recovery path: got {err:?}" + ); + assert_eq!( + captured.lock().await.len(), + 1, + "a deterministic capability rejection must not be retried" + ); + } + + /// Same 400-shaped rejection at the OpenRouter terminal, which has its own + /// status ladder: a BYOK/passthrough upstream can surface the provider's + /// own 400 body instead of OpenRouter's 404 routing error. + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn openrouter_post_400_unsupported_image_is_typed_and_not_retried() { + let (url, _captured, attempts) = spawn_openrouter_stub(vec![CannedResponse::new( + 400, + r#"{"error":{"message":"crusoeai/GLM-5.2-NVFP4 is not a multimodal model"}}"#, + )]) + .await; + let http = Client::builder() + .timeout(Duration::from_secs(5)) + .build() + .unwrap(); + let err = openrouter_post( + &http, + &format!("{url}/x"), + &json!({}), + "key", + Duration::from_secs(5), + ) + .await + .unwrap_err(); + assert!( + matches!(&err, AgentError::UnsupportedImageInput(s) if s.contains("not a multimodal model")), + "image rejection must reach the history-recovery path: got {err:?}" + ); + assert_eq!( + attempts.load(std::sync::atomic::Ordering::SeqCst), + 1, + "a deterministic capability rejection must not be retried" + ); + } + /// Every other 404 still maps to `LlmModelNotFound`, including one that /// shares the `No endpoints found` prefix but is about the model rather than /// the parameters — the discriminator is narrow enough that a genuinely From c815a9c6e1a1d1818a0547f60f894e4a5388761a Mon Sep 17 00:00:00 2001 From: Wes Date: Sat, 8 Aug 2026 10:18:29 -0600 Subject: [PATCH 03/18] chore(release): release Buzz Desktop version 0.5.8 (#5326) ## Buzz Desktop release v0.5.8 - **Frozen main:** `6a17d035f79ad582ca3f4f3cdc38d376f2c4087f` - **Reviewed candidate:** `f3de860574bb3119018b4592353e9761635aeb07` - **Previous desktop release:** `desktop-v0.5.7` - **Proposed immutable tag:** `desktop-v0.5.8` This PR may be **squash merged** after the Desktop Release Candidate check and all protected-branch checks pass. Merging authorizes publication of the exact reviewed candidate; later or unrelated changes on `main` cannot alter it. The checked-in changelog accounts for every non-merge commit in the release range. The Desktop tag points to the reviewed candidate commit, not the later squash commit. Publication remains bound to that immutable candidate tag. Signed-off-by: Wes Co-authored-by: Release Automation --- .release/desktop-candidate.json | 14 +++++++------- CHANGELOG.md | 14 ++++++++++++++ desktop/package.json | 2 +- desktop/src-tauri/Cargo.lock | 2 +- desktop/src-tauri/Cargo.toml | 2 +- desktop/src-tauri/tauri.conf.json | 2 +- 6 files changed, 25 insertions(+), 11 deletions(-) diff --git a/.release/desktop-candidate.json b/.release/desktop-candidate.json index 67979737a9..843ac0dd7d 100644 --- a/.release/desktop-candidate.json +++ b/.release/desktop-candidate.json @@ -1,10 +1,10 @@ { "schema": 2, - "version": "0.5.7", - "base_sha": "74b913cff8512c015dc6f1a7473b253fa803f954", - "previous_tag": "desktop-v0.5.6", - "previous_base_sha": "78c87ae20e182fffdd99744d6c9ff99df82b159c", - "previous_merge_sha": "3855687e7699f1b169f179122b8bc92f433abd6d", - "tag": "desktop-v0.5.7", - "commit_count": 5 + "version": "0.5.8", + "base_sha": "6a17d035f79ad582ca3f4f3cdc38d376f2c4087f", + "previous_tag": "desktop-v0.5.7", + "previous_base_sha": "74b913cff8512c015dc6f1a7473b253fa803f954", + "previous_merge_sha": "13c9e900c84cac1e2c8eeb7551bd1510ecb544d3", + "tag": "desktop-v0.5.8", + "commit_count": 4 } diff --git a/CHANGELOG.md b/CHANGELOG.md index 37a4753a6d..7ca9525074 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## v0.5.8 + +### Desktop and shared changes + +- feat(desktop): unify add agent flows ([#5015](https://github.com/block/buzz/pull/5015)) ([`02f640bc4559c48ac0c2ec595ef34dd2c294b0db`](https://github.com/block/buzz/commit/02f640bc4559c48ac0c2ec595ef34dd2c294b0db)) +- fix(buzz-agent): budget summarizer reasoning separately so it cannot starve the handoff summary ([#5248](https://github.com/block/buzz/pull/5248)) ([`c7b663680a29a837dbd2fdde810f239f3d303025`](https://github.com/block/buzz/commit/c7b663680a29a837dbd2fdde810f239f3d303025)) + +### Other repository changes + +- Revert "fix(acp): reject unattended permission requests" ([#5323](https://github.com/block/buzz/pull/5323)) ([`6a17d035f79ad582ca3f4f3cdc38d376f2c4087f`](https://github.com/block/buzz/commit/6a17d035f79ad582ca3f4f3cdc38d376f2c4087f)) +- infra: bind development services to loopback ([#4871](https://github.com/block/buzz/pull/4871)) ([`65834d68d0d3441c4e628540d6d5c8b0a2e757c9`](https://github.com/block/buzz/commit/65834d68d0d3441c4e628540d6d5c8b0a2e757c9)) + +[Compare desktop-v0.5.7...desktop-v0.5.8](https://github.com/block/buzz/compare/desktop-v0.5.7...desktop-v0.5.8) + ## v0.5.7 ### Desktop and shared changes diff --git a/desktop/package.json b/desktop/package.json index 7cfef35e26..14c412ff1d 100644 --- a/desktop/package.json +++ b/desktop/package.json @@ -1,7 +1,7 @@ { "name": "buzz", "private": true, - "version": "0.5.7", + "version": "0.5.8", "type": "module", "scripts": { "dev": "vite", diff --git a/desktop/src-tauri/Cargo.lock b/desktop/src-tauri/Cargo.lock index 94504f970d..c66bf4cb54 100644 --- a/desktop/src-tauri/Cargo.lock +++ b/desktop/src-tauri/Cargo.lock @@ -1061,7 +1061,7 @@ dependencies = [ [[package]] name = "buzz-desktop" -version = "0.5.7" +version = "0.5.8" dependencies = [ "anyhow", "arboard", diff --git a/desktop/src-tauri/Cargo.toml b/desktop/src-tauri/Cargo.toml index b8f58568b4..9b2de6a575 100644 --- a/desktop/src-tauri/Cargo.toml +++ b/desktop/src-tauri/Cargo.toml @@ -7,7 +7,7 @@ members = ["crates/buzz-terminal"] [package] name = "buzz-desktop" -version = "0.5.7" +version = "0.5.8" description = "Buzz desktop app" authors = ["you"] edition = "2021" diff --git a/desktop/src-tauri/tauri.conf.json b/desktop/src-tauri/tauri.conf.json index da476c1e57..3f332ddbf1 100644 --- a/desktop/src-tauri/tauri.conf.json +++ b/desktop/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "Buzz", - "version": "0.5.7", + "version": "0.5.8", "identifier": "xyz.block.buzz.app", "build": { "beforeDevCommand": { From 6e5c462ac524de60d7edb46c66130fd779cc9006 Mon Sep 17 00:00:00 2001 From: Will Pfleger Date: Sat, 8 Aug 2026 12:26:24 -0400 Subject: [PATCH 04/18] chore(release): release Buzz Relay version 0.2.1 (#2856) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Buzz Relay release v0.2.1 ### Changes since relay-v0.2.0: - fix(sdk): preserve self-mention p tags in message and forum event builders ([#4975](https://github.com/block/buzz/pull/4975)) ([`78c87ae20e`](https://github.com/block/buzz/commit/78c87ae20e182fffdd99744d6c9ff99df82b159c)) - feat(desktop): adding rich link previews to messages ([#3818](https://github.com/block/buzz/pull/3818)) ([`1922d49cb2`](https://github.com/block/buzz/commit/1922d49cb200a3382a91ec253f530b44dfda5f55)) - feat(relay): accept kind:30179 private managed-agent events at ingest ([#5133](https://github.com/block/buzz/pull/5133)) ([`ad923353a2`](https://github.com/block/buzz/commit/ad923353a24b784df13a7c88757d6b24ebe36299)) - fix(media): require authenticated reads ([#4610](https://github.com/block/buzz/pull/4610)) ([`769ac70b74`](https://github.com/block/buzz/commit/769ac70b741e3ad6809bff14eba29d3dd2cbd318)) - feat(identity): recover desktop identity from a signed-in phone ([#4845](https://github.com/block/buzz/pull/4845)) ([`6eb65919f1`](https://github.com/block/buzz/commit/6eb65919f1eabd46b3850c15eefab31092dd500b)) - ci: prove the relay-driven mesh lifecycle — discover, join, infer, deny — with real nodes ([#3862](https://github.com/block/buzz/pull/3862)) ([`38bf642fcf`](https://github.com/block/buzz/commit/38bf642fcfa7a9fc1e06d6cf87d66ae94da29341)) - relay: fuzz WebSocket 1012 restart-close timing on graceful drain (BUZZ_DRAIN_JITTER_MS) ([#4542](https://github.com/block/buzz/pull/4542)) ([`e14fff74d0`](https://github.com/block/buzz/commit/e14fff74d00623acd30945eec5be366e25b0cf09)) - fix(reactions): support max-length custom emoji ([#3833](https://github.com/block/buzz/pull/3833)) ([`2ea9385015`](https://github.com/block/buzz/commit/2ea9385015fb922de2adf0a53e86fc5a21d07b90)) - fix(channels): restrict private-channel invitations ([#4612](https://github.com/block/buzz/pull/4612)) ([`efe1893dd3`](https://github.com/block/buzz/commit/efe1893dd372cfb92ed2e8a3ada2ed7b62c9477a)) - fix(workflow): bind trigger author to the signed event ([#4607](https://github.com/block/buzz/pull/4607)) ([`885bed35ee`](https://github.com/block/buzz/commit/885bed35eee3f933c48d333c8979fdbc038e98b9)) - fix(git): revoke access for banned relay members ([#4608](https://github.com/block/buzz/pull/4608)) ([`997b8caaa4`](https://github.com/block/buzz/commit/997b8caaa4c9e5af69dd8a496b4995d09a69f694)) - Define private managed agent wire protocol ([#4593](https://github.com/block/buzz/pull/4593)) ([`067c085f37`](https://github.com/block/buzz/commit/067c085f37d9dcb2f598b0e2a6b6653903364783)) - perf(relay): index channel-id lookups and skip trace-only reads ([#4647](https://github.com/block/buzz/pull/4647)) ([`bc9e6528a7`](https://github.com/block/buzz/commit/bc9e6528a7ba6007c5a25f6a0aca9c05d72e9d2c)) - Polish mobile inbox and media flows ([#4512](https://github.com/block/buzz/pull/4512)) ([`feccf4eabc`](https://github.com/block/buzz/commit/feccf4eabc23fdba94ce3537a194357ed17b197c)) - fix(git): allow deleting the default branch ([#4297](https://github.com/block/buzz/pull/4297)) ([`fc598f5f8d`](https://github.com/block/buzz/commit/fc598f5f8d70728d11d0712b9fa8e3acc44ea4c3)) - feat(projects): add buzz projects CLI commands (NIP-MP kind:30621) ([#4020](https://github.com/block/buzz/pull/4020)) ([`b7bb15122e`](https://github.com/block/buzz/commit/b7bb15122e8a2053b545dc2210afc167f6c7a626)) - perf(relay): serve relay-membership checks from the read replica ([#4124](https://github.com/block/buzz/pull/4124)) ([`ac4fa13b8e`](https://github.com/block/buzz/commit/ac4fa13b8e4d947071d57deb6918dcf12bf74961)) - fix(relay): allow open relays to set their NIP-11 workspace icon (kind:9033) ([#3998](https://github.com/block/buzz/pull/3998)) ([`5765fc74b7`](https://github.com/block/buzz/commit/5765fc74b77224f0207ddd4b41736a5ff18d333d)) - feat(relay): accept kind:30621 multi-repo projects at ingest ([#3171](https://github.com/block/buzz/pull/3171)) ([`cb9701cd30`](https://github.com/block/buzz/commit/cb9701cd30fb344bf134585634a09007f3155bfb)) - feat(relay): raise hosted community limit to five ([#3829](https://github.com/block/buzz/pull/3829)) ([`10d5a26414`](https://github.com/block/buzz/commit/10d5a26414dc90dc89fd27de74b21e105d4fa622)) - fix(relay): align NIP-11 max_limit with REQ ceiling ([#3635](https://github.com/block/buzz/pull/3635)) ([`23f0c26b1c`](https://github.com/block/buzz/commit/23f0c26b1ceba8e07bf3c160a1e08c7bda82ccd9)) - feat(relay): gate kind 30178 team-catalog reads behind the shared tag ([#3358](https://github.com/block/buzz/pull/3358)) ([`114d40d9d3`](https://github.com/block/buzz/commit/114d40d9d37f05eff83ee90347ed93fb3da512c5)) - fix(db): isolate usage metrics advisory-lock test on scratch DB ([#3670](https://github.com/block/buzz/pull/3670)) ([`dba97eecd9`](https://github.com/block/buzz/commit/dba97eecd9d8659c9c816cd6666fa6d687b6bca1)) - perf(presence): reduce heartbeat frequency ([#3783](https://github.com/block/buzz/pull/3783)) ([`bf139e8d0b`](https://github.com/block/buzz/commit/bf139e8d0bdba10df9a5adbf16843140e0a78a59)) - feat(mesh): upgrade embedded mesh to v0.74 and harden shared compute (split 1/2 of #3467) ([#3741](https://github.com/block/buzz/pull/3741)) ([`4933672eb4`](https://github.com/block/buzz/commit/4933672eb4589e7208b312829ebddcd10dfa9dd3)) - feat(replica): portable heartbeat-token fence with snapshot-local reader routing ([#3268](https://github.com/block/buzz/pull/3268)) ([`63496cc1d4`](https://github.com/block/buzz/commit/63496cc1d4c6f1b7c613801bdcc694169dcf391a)) - fix(git): channel binding tooling + author remediation for unbound repos ([#3626](https://github.com/block/buzz/pull/3626)) ([`788b3c002b`](https://github.com/block/buzz/commit/788b3c002bd2509455444f57f8a03a054b4b496a)) - feat: configure S3 URL addressing style ([#3400](https://github.com/block/buzz/pull/3400)) ([`7012d86d52`](https://github.com/block/buzz/commit/7012d86d52fd188b27c7beedeaa132d9c1f61fa8)) - feat(tracing): correlate trace IDs in relay logs ([#3608](https://github.com/block/buzz/pull/3608)) ([`005b5b819a`](https://github.com/block/buzz/commit/005b5b819a98ce85d4d80cd81b258fb6f9b8d51e)) - fix(relay): avoid subscription lock inversion ([#3413](https://github.com/block/buzz/pull/3413)) ([`22be8bb351`](https://github.com/block/buzz/commit/22be8bb35177e27efc2dca2534df9a8dd871eae0)) - feat(cli): add users set-status command for NIP-38 profile status ([#3253](https://github.com/block/buzz/pull/3253)) ([`60158fce3e`](https://github.com/block/buzz/commit/60158fce3e670f11bb35d42627857ccaea50ff06)) - feat(relay): make Postgres pool size configurable, default 50 ([#3191](https://github.com/block/buzz/pull/3191)) ([`2ce2d71cc3`](https://github.com/block/buzz/commit/2ce2d71cc38a9657eaf344c10e07f155b8a18615)) - feat(tracing): add datastore tracing plumbing ([#2760](https://github.com/block/buzz/pull/2760)) ([`e94b9aeda0`](https://github.com/block/buzz/commit/e94b9aeda0b2272d36e3744e78680be69295b8b5)) - feat(invites): add use-limited invite links ([#3141](https://github.com/block/buzz/pull/3141)) ([`d500c2d5cf`](https://github.com/block/buzz/commit/d500c2d5cf5d9aabe0ca4ebebfcafdbe5f5b7fd3)) - feat(admin): show reported message content in report detail ([#3149](https://github.com/block/buzz/pull/3149)) ([`f069a85503`](https://github.com/block/buzz/commit/f069a8550373328babe4239ed614fcdf884721e2)) - resolve findings ([#3150](https://github.com/block/buzz/pull/3150)) ([`9b0f744804`](https://github.com/block/buzz/commit/9b0f744804697b802f7afb88947194702765c78d)) - Revert "fix(cli,relay): resolve agents by verified owner" ([#3168](https://github.com/block/buzz/pull/3168)) ([`a041e2d21e`](https://github.com/block/buzz/commit/a041e2d21e292a271fdfc26f0cdcdd0456f815c5)) - fix(cli,relay): resolve agents by verified owner ([#2615](https://github.com/block/buzz/pull/2615)) ([`c3084b36d9`](https://github.com/block/buzz/commit/c3084b36d975259f2dfeee8edc9131b40a8bce83)) - fix(security): enforce durable community ban on NIP-43 relay-admin kinds 9030-9033 ([#3128](https://github.com/block/buzz/pull/3128)) ([`e2e0079101`](https://github.com/block/buzz/commit/e2e007910114ddf7c5a4e93bb03f6afe13552e92)) - fix(security): authorize kind:9000 role changes in both directions ([#3017](https://github.com/block/buzz/pull/3017)) ([`00ecf2cac7`](https://github.com/block/buzz/commit/00ecf2cac7544d986b4eb111ad0a8b1d7560791f)) - feat(desktop): handle project work from Inbox ([#3117](https://github.com/block/buzz/pull/3117)) ([`c5c4f390b6`](https://github.com/block/buzz/commit/c5c4f390b6713256e2efb8394c59823ebad73db6)) - feat(relay): make per-owner community limit configurable via BUZZ_MAX_COMMUNITIES_PER_OWNER ([#2599](https://github.com/block/buzz/pull/2599)) ([`2a051a404d`](https://github.com/block/buzz/commit/2a051a404dcde42dddbff2a0b33f717ffe9cf999)) - feat(relay): add author-only-unless-shared read gate for kind 30175 ([#2768](https://github.com/block/buzz/pull/2768)) ([`ab3af82871`](https://github.com/block/buzz/commit/ab3af828714ab699dfc87644d234014987a4fe6b)) - fix(core): block IPv6 transition SSRF targets ([#2801](https://github.com/block/buzz/pull/2801)) ([`c26bf5945d`](https://github.com/block/buzz/commit/c26bf5945d8f2ef19746a78e80a7c1dae2ef3db9)) - fix(workflow): bypass system proxies for webhooks ([#2800](https://github.com/block/buzz/pull/2800)) ([`60a171b19e`](https://github.com/block/buzz/commit/60a171b19efd515d9213b535d52a2bcbec3ff2fe)) - fix(audit): hash created_at at the precision Postgres stores ([#2638](https://github.com/block/buzz/pull/2638)) ([`264a56a226`](https://github.com/block/buzz/commit/264a56a2260ac87350bfe1f5d3ec3d89615eb47c)) - feat(desktop): make pull request reviews actionable ([#2510](https://github.com/block/buzz/pull/2510)) ([`9081ab0ec9`](https://github.com/block/buzz/commit/9081ab0ec9c5d91548c7f5ff52eba6cca4788dd0)) - fix(relay): decompress gzip-encoded git smart-HTTP request bodies ([#2670](https://github.com/block/buzz/pull/2670)) ([`5ca36e7b91`](https://github.com/block/buzz/commit/5ca36e7b919097733868764d8e0073e99c3206c3)) - fix(sharing): preserve agent/team snapshot tEXt chunks through media sanitization ([#2438](https://github.com/block/buzz/pull/2438)) ([`b096b0a15a`](https://github.com/block/buzz/commit/b096b0a15af4c4566365c5b1efe7f39b700222ed)) - fix(relay): send 1012 restart close to all clients on graceful drain ([#2575](https://github.com/block/buzz/pull/2575)) ([`1911c69aa2`](https://github.com/block/buzz/commit/1911c69aa2912c1408bd6b21759b657458fb43af)) - fix(media): sanitize animated image uploads ([#2524](https://github.com/block/buzz/pull/2524)) ([`8f8f5fa5a4`](https://github.com/block/buzz/commit/8f8f5fa5a4b2463cdc6c2a527acb7086150cdaae)) - fix(channels): strip leading hash prefixes from names ([#2250](https://github.com/block/buzz/pull/2250)) ([`d0ab3fdb05`](https://github.com/block/buzz/commit/d0ab3fdb054e0cfedbf21e4c5143ad6c671c10cc)) - feat(relay): make Redis pool size configurable, default 16 ([#2521](https://github.com/block/buzz/pull/2521)) ([`bcc3e13069`](https://github.com/block/buzz/commit/bcc3e1306946528102bb26be9a7c41299e2f8e00)) - feat(desktop+acp): spawn a harness per (agent, community) pair at GUI startup — warm sockets, lazy LLM pool ([#2122](https://github.com/block/buzz/pull/2122)) ([`61cc738ee8`](https://github.com/block/buzz/commit/61cc738ee8991e92563136de4b77e54cb9756420)) - feat(media): add S3-truth per-community storage sweep ([#2044](https://github.com/block/buzz/pull/2044)) ([`bd37a4d584`](https://github.com/block/buzz/commit/bd37a4d584fefc1d13ad8abadf6e890e66183072)) - feat(relay): log NIP-98 pubkey attribution on HTTP bridge requests ([#2206](https://github.com/block/buzz/pull/2206)) ([`7e34bee62c`](https://github.com/block/buzz/commit/7e34bee62cacaa9d8a96c14d5892a471b59a1983)) - Revert "feat(relay): inventory unreachable Git objects" ([#2275](https://github.com/block/buzz/pull/2275)) ([`0fb820f9bf`](https://github.com/block/buzz/commit/0fb820f9bfbd7e19e48f9826e332920c2ee2c229)) - feat(relay): inventory unreachable Git objects ([#2264](https://github.com/block/buzz/pull/2264)) ([`3afc9dae15`](https://github.com/block/buzz/commit/3afc9dae159262220c4149e9c8add50772869318)) - relay: add author_type label to buzz_events_stored_total ([#2243](https://github.com/block/buzz/pull/2243)) ([`b9f54c43fe`](https://github.com/block/buzz/commit/b9f54c43fe2bcd0eb8fb3b76914e9aa0c31f6927)) - fix(git): make project branch workflows reliable ([#2213](https://github.com/block/buzz/pull/2213)) ([`166f27be4b`](https://github.com/block/buzz/commit/166f27be4bc1abf2d465493bf2137353045399dc)) - feat(cli): manage repository protection rules ([#2193](https://github.com/block/buzz/pull/2193)) ([`f94324598d`](https://github.com/block/buzz/commit/f94324598d84b2db9a05a3fa1f855970c4c5b575)) - feat(cli): add agents archive/unarchive/archived subcommands ([#2173](https://github.com/block/buzz/pull/2173)) ([`7d7992067b`](https://github.com/block/buzz/commit/7d7992067b2914b582b7e6d31a6174603b480b4b)) - fix(mobile): sanitize Android image uploads ([#2188](https://github.com/block/buzz/pull/2188)) ([`ee21da90bd`](https://github.com/block/buzz/commit/ee21da90bd6b1da6bfaaf22ba00749398aaa9640)) - fix(cli): paginate channel directory queries ([#2181](https://github.com/block/buzz/pull/2181)) ([`03fe19d603`](https://github.com/block/buzz/commit/03fe19d6033094ae2ec4c89c26eb23174ef53daa)) - fix(mobile): image upload fails due to unstripped metadata ([#2185](https://github.com/block/buzz/pull/2185)) ([`37f15b2001`](https://github.com/block/buzz/commit/37f15b20019169363b697aee41c99573b7bc3f24)) - perf(relay): compact Git packs before manifest limits ([#2172](https://github.com/block/buzz/pull/2172)) ([`80e0ab16b0`](https://github.com/block/buzz/commit/80e0ab16b03c656ec8def18bedc27eaf29c02867)) - perf(relay): cache Git pack hydration ([#2169](https://github.com/block/buzz/pull/2169)) ([`a4d82ec722`](https://github.com/block/buzz/commit/a4d82ec7226e685a933dbd829b6bb8bce0787b4e)) - fix(relay): bound and observe Git read operations ([#2167](https://github.com/block/buzz/pull/2167)) ([`5f7c93d9c1`](https://github.com/block/buzz/commit/5f7c93d9c12ce7894288ae47f3fe223fcff2dce3)) - relay: gate push enqueue on live leases; batch matcher pipeline (T1b/T1a-repair/T2b) ([#2145](https://github.com/block/buzz/pull/2145)) ([`e43b2d5aac`](https://github.com/block/buzz/commit/e43b2d5aac0d1f2b6b623b04f7af5a51f77da8c6)) - relay: add audit logging disable switch ([#2134](https://github.com/block/buzz/pull/2134)) ([`bf5acabdde`](https://github.com/block/buzz/commit/bf5acabdde44aa133bdcbafcf9e1a4ff752c3302)) - relay: skip TTL deadline bump for known-permanent channels (T1a write-amp) ([#2125](https://github.com/block/buzz/pull/2125)) ([`2e936d439c`](https://github.com/block/buzz/commit/2e936d439ce29182b48086f9f8a7a3ffe3b9b345)) - fix(git): carry NIP-OA delegation in auth event ([#2120](https://github.com/block/buzz/pull/2120)) ([`c12257d57a`](https://github.com/block/buzz/commit/c12257d57a54d5c1e16435440b02beb5d1c057b8)) - Route lag-tolerant reads to an optional Postgres read replica ([#2084](https://github.com/block/buzz/pull/2084)) ([`29c48883d3`](https://github.com/block/buzz/commit/29c48883d30e6feed75e33490571ca96082c6282)) - fix: recover community access visibility ([#2074](https://github.com/block/buzz/pull/2074)) ([`ca384d082d`](https://github.com/block/buzz/commit/ca384d082d9804ec53a3fd12ccbf4a0846b21d92)) - feat: proxy feedback-scoped admin attachments ([#2059](https://github.com/block/buzz/pull/2059)) ([`d7f918e3cb`](https://github.com/block/buzz/commit/d7f918e3cbcc4d30f222d0f4ae836de808f859a2)) - feat: add read-only deployment moderation dashboard ([#1999](https://github.com/block/buzz/pull/1999)) ([`68e670e001`](https://github.com/block/buzz/commit/68e670e001d2bed2cf141095926feaf482c3bed8)) - Bug-bash round 2: table scroll, Goose instructions, workflow mention wake ([#2034](https://github.com/block/buzz/pull/2034)) ([`64b8fea6dc`](https://github.com/block/buzz/commit/64b8fea6dce3be684aa0bac5dbd701e46dc7e432)) - Strip media metadata on clients and reject it at the relay ([#2006](https://github.com/block/buzz/pull/2006)) ([`5cfd69cb0c`](https://github.com/block/buzz/commit/5cfd69cb0cf1dc63d718454defe3b8a8aaf5f15b)) - [codex] Hold Git concurrency permits through streaming (BUZZ-SEC-018) ([#1916](https://github.com/block/buzz/pull/1916)) ([`7baea42abb`](https://github.com/block/buzz/commit/7baea42abbbb794e6e5ab0e9df11e2d1b0550d0b)) - [codex] Enforce shared relay admission limits (BUZZ-SEC-019) ([#1917](https://github.com/block/buzz/pull/1917)) ([`73fc0ec6cf`](https://github.com/block/buzz/commit/73fc0ec6cf58a79bfc65e42faba457bf49c2d232)) - [codex] Block banned actors from moderation commands (BUZZ-SEC-007) ([#1915](https://github.com/block/buzz/pull/1915)) ([`caa195ca58`](https://github.com/block/buzz/commit/caa195ca58ea49cf8ed9c3ede55d6a2e4ed37096)) - [codex] Fix relay WebSocket admission limits ([#1682](https://github.com/block/buzz/pull/1682)) ([`d3ce971fc7`](https://github.com/block/buzz/commit/d3ce971fc75a34162d5498c27ac4a1c30236630a)) - feat: add invite QR and mobile direct join ([#1957](https://github.com/block/buzz/pull/1957)) ([`648cbf3610`](https://github.com/block/buzz/commit/648cbf36109d97be6bd8530e77073d1c7e6008a0)) - fix(join-policy): require legal consent on hosted invites ([#1987](https://github.com/block/buzz/pull/1987)) ([`2e1577f76f`](https://github.com/block/buzz/commit/2e1577f76f5105ddacda7be884518574ca8d6b96)) - [codex] Prevent actor-tag UI impersonation ([#1931](https://github.com/block/buzz/pull/1931)) ([`c540ec9678`](https://github.com/block/buzz/commit/c540ec967869ef0f4eef90439bf70929fc74f7f6)) - Scope relay runtime state by community ([#1658](https://github.com/block/buzz/pull/1658)) ([`d52dedb06f`](https://github.com/block/buzz/commit/d52dedb06fc2c7692c6d9225c7a08b41a509633a)) - Apply optional relay join policy across join flows ([#1894](https://github.com/block/buzz/pull/1894)) ([`6c2d667575`](https://github.com/block/buzz/commit/6c2d667575cbc372ba42d26134448660fb1d2ee9)) - feat(media): require auth for relay media reads ([#1926](https://github.com/block/buzz/pull/1926)) ([`f308762852`](https://github.com/block/buzz/commit/f3087628524951de91028c9d263bcd0d0a727fab)) - feat(relay): add community unarchive endpoint ([#1908](https://github.com/block/buzz/pull/1908)) ([`6b9641db2b`](https://github.com/block/buzz/commit/6b9641db2b4709b71622b7ef0b799117a0605ca6)) - feat(relay): gate Git web GUI separately ([#1901](https://github.com/block/buzz/pull/1901)) ([`34dc7dec75`](https://github.com/block/buzz/commit/34dc7dec75285ab6f2107ce5cad170b80b92206a)) - mesh: upgrade runtime, enforce membership, add shared compute provider ([#1656](https://github.com/block/buzz/pull/1656)) ([`54638ff4bb`](https://github.com/block/buzz/commit/54638ff4bb5af2d3d3759b44118b43052f814bb1)) - Route Git scratch through configured volume ([#1884](https://github.com/block/buzz/pull/1884)) ([`2318b3096c`](https://github.com/block/buzz/commit/2318b3096c585f8d31bd43e27dc5d6305c5fe20d)) - feat(relay): gate usage metrics behind stable leader ([#1814](https://github.com/block/buzz/pull/1814)) ([`59e9821503`](https://github.com/block/buzz/commit/59e9821503a2fe23fc4630aa0f36bb252ae4566f)) - Relay mesh: cross-pod tunnel + huddle transport (buzz-relay-mesh) ([#1670](https://github.com/block/buzz/pull/1670)) ([`ccb021d713`](https://github.com/block/buzz/commit/ccb021d71339009aabedc383c8f3d8e5c23e1e42)) - feat(push): deliver accepted relay events as wakes ([#1866](https://github.com/block/buzz/pull/1866)) ([`bffbc5f22c`](https://github.com/block/buzz/commit/bffbc5f22cc80e9a07dedc622798347d598a215c)) - fix(db): resolve duplicate migration version ([#1863](https://github.com/block/buzz/pull/1863)) ([`08ad38a07f`](https://github.com/block/buzz/commit/08ad38a07f0c49bb3f20b775b8f534f1cfa529c3)) - Add private product feedback sidecar ([#1857](https://github.com/block/buzz/pull/1857)) ([`af190c93e1`](https://github.com/block/buzz/commit/af190c93e1048af64c3fbfb3831c689cb703997c)) - feat(relay): add durable community archival ([#1834](https://github.com/block/buzz/pull/1834)) ([`2b15a72675`](https://github.com/block/buzz/commit/2b15a726750dbd7437711050cd3241b679dff317)) - feat(push): add public APNs gateway ([#1770](https://github.com/block/buzz/pull/1770)) ([`1c006822e4`](https://github.com/block/buzz/commit/1c006822e4484d68e33fce14f9139c2f70ce9d66)) - feat(relay): add atomic community ownership transfer ([#1845](https://github.com/block/buzz/pull/1845)) ([`52e42ccb9f`](https://github.com/block/buzz/commit/52e42ccb9fc85445814614c72d40f346e986152b)) - Bound NIP-RS retention and search indexing ([#1771](https://github.com/block/buzz/pull/1771)) ([`1b4703021d`](https://github.com/block/buzz/commit/1b4703021dbfd37dc31845223dba9ba182e4647f)) - Add optional standalone pairing relay to Helm chart ([#1799](https://github.com/block/buzz/pull/1799)) ([`9b47c8548f`](https://github.com/block/buzz/commit/9b47c8548fd061fbb806ea8b9ddee831c19cf80e)) - fix(relay): publish membership snapshot on provisioning ([#1761](https://github.com/block/buzz/pull/1761)) ([`0950d392b7`](https://github.com/block/buzz/commit/0950d392b7a862694c95cbea1cec45985ee42996)) - feat(relay): per-community usage metrics ([#1723](https://github.com/block/buzz/pull/1723)) ([`620822899a`](https://github.com/block/buzz/commit/620822899a6373fa3a17a87815cd7cade25ed332)) - refactor(desktop): remove vestigial MCP toolsets config ([#1776](https://github.com/block/buzz/pull/1776)) ([`dfec75b3c0`](https://github.com/block/buzz/commit/dfec75b3c0b8080529e4d9089d4ed80e3902aaed)) **To release:** merge this PR. The tag and build will happen automatically. Signed-off-by: Will Pfleger --- Cargo.lock | 2 +- crates/buzz-relay/CHANGELOG.md | 109 +++++++++++++++++++++++++++++++++ crates/buzz-relay/Cargo.toml | 2 +- 3 files changed, 111 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 83d2b9e3e3..f7c42e625a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1180,7 +1180,7 @@ dependencies = [ [[package]] name = "buzz-relay" -version = "0.2.0" +version = "0.2.1" dependencies = [ "anyhow", "async-compression", diff --git a/crates/buzz-relay/CHANGELOG.md b/crates/buzz-relay/CHANGELOG.md index c0d6ab9ccd..7ee7e9a303 100644 --- a/crates/buzz-relay/CHANGELOG.md +++ b/crates/buzz-relay/CHANGELOG.md @@ -1,5 +1,114 @@ # Changelog +## relay-v0.2.1 + +- fix(sdk): preserve self-mention p tags in message and forum event builders ([#4975](https://github.com/block/buzz/pull/4975)) ([`78c87ae20e`](https://github.com/block/buzz/commit/78c87ae20e182fffdd99744d6c9ff99df82b159c)) +- feat(desktop): adding rich link previews to messages ([#3818](https://github.com/block/buzz/pull/3818)) ([`1922d49cb2`](https://github.com/block/buzz/commit/1922d49cb200a3382a91ec253f530b44dfda5f55)) +- feat(relay): accept kind:30179 private managed-agent events at ingest ([#5133](https://github.com/block/buzz/pull/5133)) ([`ad923353a2`](https://github.com/block/buzz/commit/ad923353a24b784df13a7c88757d6b24ebe36299)) +- fix(media): require authenticated reads ([#4610](https://github.com/block/buzz/pull/4610)) ([`769ac70b74`](https://github.com/block/buzz/commit/769ac70b741e3ad6809bff14eba29d3dd2cbd318)) +- feat(identity): recover desktop identity from a signed-in phone ([#4845](https://github.com/block/buzz/pull/4845)) ([`6eb65919f1`](https://github.com/block/buzz/commit/6eb65919f1eabd46b3850c15eefab31092dd500b)) +- ci: prove the relay-driven mesh lifecycle — discover, join, infer, deny — with real nodes ([#3862](https://github.com/block/buzz/pull/3862)) ([`38bf642fcf`](https://github.com/block/buzz/commit/38bf642fcfa7a9fc1e06d6cf87d66ae94da29341)) +- relay: fuzz WebSocket 1012 restart-close timing on graceful drain (BUZZ_DRAIN_JITTER_MS) ([#4542](https://github.com/block/buzz/pull/4542)) ([`e14fff74d0`](https://github.com/block/buzz/commit/e14fff74d00623acd30945eec5be366e25b0cf09)) +- fix(reactions): support max-length custom emoji ([#3833](https://github.com/block/buzz/pull/3833)) ([`2ea9385015`](https://github.com/block/buzz/commit/2ea9385015fb922de2adf0a53e86fc5a21d07b90)) +- fix(channels): restrict private-channel invitations ([#4612](https://github.com/block/buzz/pull/4612)) ([`efe1893dd3`](https://github.com/block/buzz/commit/efe1893dd372cfb92ed2e8a3ada2ed7b62c9477a)) +- fix(workflow): bind trigger author to the signed event ([#4607](https://github.com/block/buzz/pull/4607)) ([`885bed35ee`](https://github.com/block/buzz/commit/885bed35eee3f933c48d333c8979fdbc038e98b9)) +- fix(git): revoke access for banned relay members ([#4608](https://github.com/block/buzz/pull/4608)) ([`997b8caaa4`](https://github.com/block/buzz/commit/997b8caaa4c9e5af69dd8a496b4995d09a69f694)) +- Define private managed agent wire protocol ([#4593](https://github.com/block/buzz/pull/4593)) ([`067c085f37`](https://github.com/block/buzz/commit/067c085f37d9dcb2f598b0e2a6b6653903364783)) +- perf(relay): index channel-id lookups and skip trace-only reads ([#4647](https://github.com/block/buzz/pull/4647)) ([`bc9e6528a7`](https://github.com/block/buzz/commit/bc9e6528a7ba6007c5a25f6a0aca9c05d72e9d2c)) +- Polish mobile inbox and media flows ([#4512](https://github.com/block/buzz/pull/4512)) ([`feccf4eabc`](https://github.com/block/buzz/commit/feccf4eabc23fdba94ce3537a194357ed17b197c)) +- fix(git): allow deleting the default branch ([#4297](https://github.com/block/buzz/pull/4297)) ([`fc598f5f8d`](https://github.com/block/buzz/commit/fc598f5f8d70728d11d0712b9fa8e3acc44ea4c3)) +- feat(projects): add buzz projects CLI commands (NIP-MP kind:30621) ([#4020](https://github.com/block/buzz/pull/4020)) ([`b7bb15122e`](https://github.com/block/buzz/commit/b7bb15122e8a2053b545dc2210afc167f6c7a626)) +- perf(relay): serve relay-membership checks from the read replica ([#4124](https://github.com/block/buzz/pull/4124)) ([`ac4fa13b8e`](https://github.com/block/buzz/commit/ac4fa13b8e4d947071d57deb6918dcf12bf74961)) +- fix(relay): allow open relays to set their NIP-11 workspace icon (kind:9033) ([#3998](https://github.com/block/buzz/pull/3998)) ([`5765fc74b7`](https://github.com/block/buzz/commit/5765fc74b77224f0207ddd4b41736a5ff18d333d)) +- feat(relay): accept kind:30621 multi-repo projects at ingest ([#3171](https://github.com/block/buzz/pull/3171)) ([`cb9701cd30`](https://github.com/block/buzz/commit/cb9701cd30fb344bf134585634a09007f3155bfb)) +- feat(relay): raise hosted community limit to five ([#3829](https://github.com/block/buzz/pull/3829)) ([`10d5a26414`](https://github.com/block/buzz/commit/10d5a26414dc90dc89fd27de74b21e105d4fa622)) +- fix(relay): align NIP-11 max_limit with REQ ceiling ([#3635](https://github.com/block/buzz/pull/3635)) ([`23f0c26b1c`](https://github.com/block/buzz/commit/23f0c26b1ceba8e07bf3c160a1e08c7bda82ccd9)) +- feat(relay): gate kind 30178 team-catalog reads behind the shared tag ([#3358](https://github.com/block/buzz/pull/3358)) ([`114d40d9d3`](https://github.com/block/buzz/commit/114d40d9d37f05eff83ee90347ed93fb3da512c5)) +- fix(db): isolate usage metrics advisory-lock test on scratch DB ([#3670](https://github.com/block/buzz/pull/3670)) ([`dba97eecd9`](https://github.com/block/buzz/commit/dba97eecd9d8659c9c816cd6666fa6d687b6bca1)) +- perf(presence): reduce heartbeat frequency ([#3783](https://github.com/block/buzz/pull/3783)) ([`bf139e8d0b`](https://github.com/block/buzz/commit/bf139e8d0bdba10df9a5adbf16843140e0a78a59)) +- feat(mesh): upgrade embedded mesh to v0.74 and harden shared compute (split 1/2 of #3467) ([#3741](https://github.com/block/buzz/pull/3741)) ([`4933672eb4`](https://github.com/block/buzz/commit/4933672eb4589e7208b312829ebddcd10dfa9dd3)) +- feat(replica): portable heartbeat-token fence with snapshot-local reader routing ([#3268](https://github.com/block/buzz/pull/3268)) ([`63496cc1d4`](https://github.com/block/buzz/commit/63496cc1d4c6f1b7c613801bdcc694169dcf391a)) +- fix(git): channel binding tooling + author remediation for unbound repos ([#3626](https://github.com/block/buzz/pull/3626)) ([`788b3c002b`](https://github.com/block/buzz/commit/788b3c002bd2509455444f57f8a03a054b4b496a)) +- feat: configure S3 URL addressing style ([#3400](https://github.com/block/buzz/pull/3400)) ([`7012d86d52`](https://github.com/block/buzz/commit/7012d86d52fd188b27c7beedeaa132d9c1f61fa8)) +- feat(tracing): correlate trace IDs in relay logs ([#3608](https://github.com/block/buzz/pull/3608)) ([`005b5b819a`](https://github.com/block/buzz/commit/005b5b819a98ce85d4d80cd81b258fb6f9b8d51e)) +- fix(relay): avoid subscription lock inversion ([#3413](https://github.com/block/buzz/pull/3413)) ([`22be8bb351`](https://github.com/block/buzz/commit/22be8bb35177e27efc2dca2534df9a8dd871eae0)) +- feat(cli): add users set-status command for NIP-38 profile status ([#3253](https://github.com/block/buzz/pull/3253)) ([`60158fce3e`](https://github.com/block/buzz/commit/60158fce3e670f11bb35d42627857ccaea50ff06)) +- feat(relay): make Postgres pool size configurable, default 50 ([#3191](https://github.com/block/buzz/pull/3191)) ([`2ce2d71cc3`](https://github.com/block/buzz/commit/2ce2d71cc38a9657eaf344c10e07f155b8a18615)) +- feat(tracing): add datastore tracing plumbing ([#2760](https://github.com/block/buzz/pull/2760)) ([`e94b9aeda0`](https://github.com/block/buzz/commit/e94b9aeda0b2272d36e3744e78680be69295b8b5)) +- feat(invites): add use-limited invite links ([#3141](https://github.com/block/buzz/pull/3141)) ([`d500c2d5cf`](https://github.com/block/buzz/commit/d500c2d5cf5d9aabe0ca4ebebfcafdbe5f5b7fd3)) +- feat(admin): show reported message content in report detail ([#3149](https://github.com/block/buzz/pull/3149)) ([`f069a85503`](https://github.com/block/buzz/commit/f069a8550373328babe4239ed614fcdf884721e2)) +- resolve findings ([#3150](https://github.com/block/buzz/pull/3150)) ([`9b0f744804`](https://github.com/block/buzz/commit/9b0f744804697b802f7afb88947194702765c78d)) +- Revert "fix(cli,relay): resolve agents by verified owner" ([#3168](https://github.com/block/buzz/pull/3168)) ([`a041e2d21e`](https://github.com/block/buzz/commit/a041e2d21e292a271fdfc26f0cdcdd0456f815c5)) +- fix(cli,relay): resolve agents by verified owner ([#2615](https://github.com/block/buzz/pull/2615)) ([`c3084b36d9`](https://github.com/block/buzz/commit/c3084b36d975259f2dfeee8edc9131b40a8bce83)) +- fix(security): enforce durable community ban on NIP-43 relay-admin kinds 9030-9033 ([#3128](https://github.com/block/buzz/pull/3128)) ([`e2e0079101`](https://github.com/block/buzz/commit/e2e007910114ddf7c5a4e93bb03f6afe13552e92)) +- fix(security): authorize kind:9000 role changes in both directions ([#3017](https://github.com/block/buzz/pull/3017)) ([`00ecf2cac7`](https://github.com/block/buzz/commit/00ecf2cac7544d986b4eb111ad0a8b1d7560791f)) +- feat(desktop): handle project work from Inbox ([#3117](https://github.com/block/buzz/pull/3117)) ([`c5c4f390b6`](https://github.com/block/buzz/commit/c5c4f390b6713256e2efb8394c59823ebad73db6)) +- feat(relay): make per-owner community limit configurable via BUZZ_MAX_COMMUNITIES_PER_OWNER ([#2599](https://github.com/block/buzz/pull/2599)) ([`2a051a404d`](https://github.com/block/buzz/commit/2a051a404dcde42dddbff2a0b33f717ffe9cf999)) +- feat(relay): add author-only-unless-shared read gate for kind 30175 ([#2768](https://github.com/block/buzz/pull/2768)) ([`ab3af82871`](https://github.com/block/buzz/commit/ab3af828714ab699dfc87644d234014987a4fe6b)) +- fix(core): block IPv6 transition SSRF targets ([#2801](https://github.com/block/buzz/pull/2801)) ([`c26bf5945d`](https://github.com/block/buzz/commit/c26bf5945d8f2ef19746a78e80a7c1dae2ef3db9)) +- fix(workflow): bypass system proxies for webhooks ([#2800](https://github.com/block/buzz/pull/2800)) ([`60a171b19e`](https://github.com/block/buzz/commit/60a171b19efd515d9213b535d52a2bcbec3ff2fe)) +- fix(audit): hash created_at at the precision Postgres stores ([#2638](https://github.com/block/buzz/pull/2638)) ([`264a56a226`](https://github.com/block/buzz/commit/264a56a2260ac87350bfe1f5d3ec3d89615eb47c)) +- feat(desktop): make pull request reviews actionable ([#2510](https://github.com/block/buzz/pull/2510)) ([`9081ab0ec9`](https://github.com/block/buzz/commit/9081ab0ec9c5d91548c7f5ff52eba6cca4788dd0)) +- fix(relay): decompress gzip-encoded git smart-HTTP request bodies ([#2670](https://github.com/block/buzz/pull/2670)) ([`5ca36e7b91`](https://github.com/block/buzz/commit/5ca36e7b919097733868764d8e0073e99c3206c3)) +- fix(sharing): preserve agent/team snapshot tEXt chunks through media sanitization ([#2438](https://github.com/block/buzz/pull/2438)) ([`b096b0a15a`](https://github.com/block/buzz/commit/b096b0a15af4c4566365c5b1efe7f39b700222ed)) +- fix(relay): send 1012 restart close to all clients on graceful drain ([#2575](https://github.com/block/buzz/pull/2575)) ([`1911c69aa2`](https://github.com/block/buzz/commit/1911c69aa2912c1408bd6b21759b657458fb43af)) +- fix(media): sanitize animated image uploads ([#2524](https://github.com/block/buzz/pull/2524)) ([`8f8f5fa5a4`](https://github.com/block/buzz/commit/8f8f5fa5a4b2463cdc6c2a527acb7086150cdaae)) +- fix(channels): strip leading hash prefixes from names ([#2250](https://github.com/block/buzz/pull/2250)) ([`d0ab3fdb05`](https://github.com/block/buzz/commit/d0ab3fdb054e0cfedbf21e4c5143ad6c671c10cc)) +- feat(relay): make Redis pool size configurable, default 16 ([#2521](https://github.com/block/buzz/pull/2521)) ([`bcc3e13069`](https://github.com/block/buzz/commit/bcc3e1306946528102bb26be9a7c41299e2f8e00)) +- feat(desktop+acp): spawn a harness per (agent, community) pair at GUI startup — warm sockets, lazy LLM pool ([#2122](https://github.com/block/buzz/pull/2122)) ([`61cc738ee8`](https://github.com/block/buzz/commit/61cc738ee8991e92563136de4b77e54cb9756420)) +- feat(media): add S3-truth per-community storage sweep ([#2044](https://github.com/block/buzz/pull/2044)) ([`bd37a4d584`](https://github.com/block/buzz/commit/bd37a4d584fefc1d13ad8abadf6e890e66183072)) +- feat(relay): log NIP-98 pubkey attribution on HTTP bridge requests ([#2206](https://github.com/block/buzz/pull/2206)) ([`7e34bee62c`](https://github.com/block/buzz/commit/7e34bee62cacaa9d8a96c14d5892a471b59a1983)) +- Revert "feat(relay): inventory unreachable Git objects" ([#2275](https://github.com/block/buzz/pull/2275)) ([`0fb820f9bf`](https://github.com/block/buzz/commit/0fb820f9bfbd7e19e48f9826e332920c2ee2c229)) +- feat(relay): inventory unreachable Git objects ([#2264](https://github.com/block/buzz/pull/2264)) ([`3afc9dae15`](https://github.com/block/buzz/commit/3afc9dae159262220c4149e9c8add50772869318)) +- relay: add author_type label to buzz_events_stored_total ([#2243](https://github.com/block/buzz/pull/2243)) ([`b9f54c43fe`](https://github.com/block/buzz/commit/b9f54c43fe2bcd0eb8fb3b76914e9aa0c31f6927)) +- fix(git): make project branch workflows reliable ([#2213](https://github.com/block/buzz/pull/2213)) ([`166f27be4b`](https://github.com/block/buzz/commit/166f27be4bc1abf2d465493bf2137353045399dc)) +- feat(cli): manage repository protection rules ([#2193](https://github.com/block/buzz/pull/2193)) ([`f94324598d`](https://github.com/block/buzz/commit/f94324598d84b2db9a05a3fa1f855970c4c5b575)) +- feat(cli): add agents archive/unarchive/archived subcommands ([#2173](https://github.com/block/buzz/pull/2173)) ([`7d7992067b`](https://github.com/block/buzz/commit/7d7992067b2914b582b7e6d31a6174603b480b4b)) +- fix(mobile): sanitize Android image uploads ([#2188](https://github.com/block/buzz/pull/2188)) ([`ee21da90bd`](https://github.com/block/buzz/commit/ee21da90bd6b1da6bfaaf22ba00749398aaa9640)) +- fix(cli): paginate channel directory queries ([#2181](https://github.com/block/buzz/pull/2181)) ([`03fe19d603`](https://github.com/block/buzz/commit/03fe19d6033094ae2ec4c89c26eb23174ef53daa)) +- fix(mobile): image upload fails due to unstripped metadata ([#2185](https://github.com/block/buzz/pull/2185)) ([`37f15b2001`](https://github.com/block/buzz/commit/37f15b20019169363b697aee41c99573b7bc3f24)) +- perf(relay): compact Git packs before manifest limits ([#2172](https://github.com/block/buzz/pull/2172)) ([`80e0ab16b0`](https://github.com/block/buzz/commit/80e0ab16b03c656ec8def18bedc27eaf29c02867)) +- perf(relay): cache Git pack hydration ([#2169](https://github.com/block/buzz/pull/2169)) ([`a4d82ec722`](https://github.com/block/buzz/commit/a4d82ec7226e685a933dbd829b6bb8bce0787b4e)) +- fix(relay): bound and observe Git read operations ([#2167](https://github.com/block/buzz/pull/2167)) ([`5f7c93d9c1`](https://github.com/block/buzz/commit/5f7c93d9c12ce7894288ae47f3fe223fcff2dce3)) +- relay: gate push enqueue on live leases; batch matcher pipeline (T1b/T1a-repair/T2b) ([#2145](https://github.com/block/buzz/pull/2145)) ([`e43b2d5aac`](https://github.com/block/buzz/commit/e43b2d5aac0d1f2b6b623b04f7af5a51f77da8c6)) +- relay: add audit logging disable switch ([#2134](https://github.com/block/buzz/pull/2134)) ([`bf5acabdde`](https://github.com/block/buzz/commit/bf5acabdde44aa133bdcbafcf9e1a4ff752c3302)) +- relay: skip TTL deadline bump for known-permanent channels (T1a write-amp) ([#2125](https://github.com/block/buzz/pull/2125)) ([`2e936d439c`](https://github.com/block/buzz/commit/2e936d439ce29182b48086f9f8a7a3ffe3b9b345)) +- fix(git): carry NIP-OA delegation in auth event ([#2120](https://github.com/block/buzz/pull/2120)) ([`c12257d57a`](https://github.com/block/buzz/commit/c12257d57a54d5c1e16435440b02beb5d1c057b8)) +- Route lag-tolerant reads to an optional Postgres read replica ([#2084](https://github.com/block/buzz/pull/2084)) ([`29c48883d3`](https://github.com/block/buzz/commit/29c48883d30e6feed75e33490571ca96082c6282)) +- fix: recover community access visibility ([#2074](https://github.com/block/buzz/pull/2074)) ([`ca384d082d`](https://github.com/block/buzz/commit/ca384d082d9804ec53a3fd12ccbf4a0846b21d92)) +- feat: proxy feedback-scoped admin attachments ([#2059](https://github.com/block/buzz/pull/2059)) ([`d7f918e3cb`](https://github.com/block/buzz/commit/d7f918e3cbcc4d30f222d0f4ae836de808f859a2)) +- feat: add read-only deployment moderation dashboard ([#1999](https://github.com/block/buzz/pull/1999)) ([`68e670e001`](https://github.com/block/buzz/commit/68e670e001d2bed2cf141095926feaf482c3bed8)) +- Bug-bash round 2: table scroll, Goose instructions, workflow mention wake ([#2034](https://github.com/block/buzz/pull/2034)) ([`64b8fea6dc`](https://github.com/block/buzz/commit/64b8fea6dce3be684aa0bac5dbd701e46dc7e432)) +- Strip media metadata on clients and reject it at the relay ([#2006](https://github.com/block/buzz/pull/2006)) ([`5cfd69cb0c`](https://github.com/block/buzz/commit/5cfd69cb0cf1dc63d718454defe3b8a8aaf5f15b)) +- [codex] Hold Git concurrency permits through streaming (BUZZ-SEC-018) ([#1916](https://github.com/block/buzz/pull/1916)) ([`7baea42abb`](https://github.com/block/buzz/commit/7baea42abbbb794e6e5ab0e9df11e2d1b0550d0b)) +- [codex] Enforce shared relay admission limits (BUZZ-SEC-019) ([#1917](https://github.com/block/buzz/pull/1917)) ([`73fc0ec6cf`](https://github.com/block/buzz/commit/73fc0ec6cf58a79bfc65e42faba457bf49c2d232)) +- [codex] Block banned actors from moderation commands (BUZZ-SEC-007) ([#1915](https://github.com/block/buzz/pull/1915)) ([`caa195ca58`](https://github.com/block/buzz/commit/caa195ca58ea49cf8ed9c3ede55d6a2e4ed37096)) +- [codex] Fix relay WebSocket admission limits ([#1682](https://github.com/block/buzz/pull/1682)) ([`d3ce971fc7`](https://github.com/block/buzz/commit/d3ce971fc75a34162d5498c27ac4a1c30236630a)) +- feat: add invite QR and mobile direct join ([#1957](https://github.com/block/buzz/pull/1957)) ([`648cbf3610`](https://github.com/block/buzz/commit/648cbf36109d97be6bd8530e77073d1c7e6008a0)) +- fix(join-policy): require legal consent on hosted invites ([#1987](https://github.com/block/buzz/pull/1987)) ([`2e1577f76f`](https://github.com/block/buzz/commit/2e1577f76f5105ddacda7be884518574ca8d6b96)) +- [codex] Prevent actor-tag UI impersonation ([#1931](https://github.com/block/buzz/pull/1931)) ([`c540ec9678`](https://github.com/block/buzz/commit/c540ec967869ef0f4eef90439bf70929fc74f7f6)) +- Scope relay runtime state by community ([#1658](https://github.com/block/buzz/pull/1658)) ([`d52dedb06f`](https://github.com/block/buzz/commit/d52dedb06fc2c7692c6d9225c7a08b41a509633a)) +- Apply optional relay join policy across join flows ([#1894](https://github.com/block/buzz/pull/1894)) ([`6c2d667575`](https://github.com/block/buzz/commit/6c2d667575cbc372ba42d26134448660fb1d2ee9)) +- feat(media): require auth for relay media reads ([#1926](https://github.com/block/buzz/pull/1926)) ([`f308762852`](https://github.com/block/buzz/commit/f3087628524951de91028c9d263bcd0d0a727fab)) +- feat(relay): add community unarchive endpoint ([#1908](https://github.com/block/buzz/pull/1908)) ([`6b9641db2b`](https://github.com/block/buzz/commit/6b9641db2b4709b71622b7ef0b799117a0605ca6)) +- feat(relay): gate Git web GUI separately ([#1901](https://github.com/block/buzz/pull/1901)) ([`34dc7dec75`](https://github.com/block/buzz/commit/34dc7dec75285ab6f2107ce5cad170b80b92206a)) +- mesh: upgrade runtime, enforce membership, add shared compute provider ([#1656](https://github.com/block/buzz/pull/1656)) ([`54638ff4bb`](https://github.com/block/buzz/commit/54638ff4bb5af2d3d3759b44118b43052f814bb1)) +- Route Git scratch through configured volume ([#1884](https://github.com/block/buzz/pull/1884)) ([`2318b3096c`](https://github.com/block/buzz/commit/2318b3096c585f8d31bd43e27dc5d6305c5fe20d)) +- feat(relay): gate usage metrics behind stable leader ([#1814](https://github.com/block/buzz/pull/1814)) ([`59e9821503`](https://github.com/block/buzz/commit/59e9821503a2fe23fc4630aa0f36bb252ae4566f)) +- Relay mesh: cross-pod tunnel + huddle transport (buzz-relay-mesh) ([#1670](https://github.com/block/buzz/pull/1670)) ([`ccb021d713`](https://github.com/block/buzz/commit/ccb021d71339009aabedc383c8f3d8e5c23e1e42)) +- feat(push): deliver accepted relay events as wakes ([#1866](https://github.com/block/buzz/pull/1866)) ([`bffbc5f22c`](https://github.com/block/buzz/commit/bffbc5f22cc80e9a07dedc622798347d598a215c)) +- fix(db): resolve duplicate migration version ([#1863](https://github.com/block/buzz/pull/1863)) ([`08ad38a07f`](https://github.com/block/buzz/commit/08ad38a07f0c49bb3f20b775b8f534f1cfa529c3)) +- Add private product feedback sidecar ([#1857](https://github.com/block/buzz/pull/1857)) ([`af190c93e1`](https://github.com/block/buzz/commit/af190c93e1048af64c3fbfb3831c689cb703997c)) +- feat(relay): add durable community archival ([#1834](https://github.com/block/buzz/pull/1834)) ([`2b15a72675`](https://github.com/block/buzz/commit/2b15a726750dbd7437711050cd3241b679dff317)) +- feat(push): add public APNs gateway ([#1770](https://github.com/block/buzz/pull/1770)) ([`1c006822e4`](https://github.com/block/buzz/commit/1c006822e4484d68e33fce14f9139c2f70ce9d66)) +- feat(relay): add atomic community ownership transfer ([#1845](https://github.com/block/buzz/pull/1845)) ([`52e42ccb9f`](https://github.com/block/buzz/commit/52e42ccb9fc85445814614c72d40f346e986152b)) +- Bound NIP-RS retention and search indexing ([#1771](https://github.com/block/buzz/pull/1771)) ([`1b4703021d`](https://github.com/block/buzz/commit/1b4703021dbfd37dc31845223dba9ba182e4647f)) +- Add optional standalone pairing relay to Helm chart ([#1799](https://github.com/block/buzz/pull/1799)) ([`9b47c8548f`](https://github.com/block/buzz/commit/9b47c8548fd061fbb806ea8b9ddee831c19cf80e)) +- fix(relay): publish membership snapshot on provisioning ([#1761](https://github.com/block/buzz/pull/1761)) ([`0950d392b7`](https://github.com/block/buzz/commit/0950d392b7a862694c95cbea1cec45985ee42996)) +- feat(relay): per-community usage metrics ([#1723](https://github.com/block/buzz/pull/1723)) ([`620822899a`](https://github.com/block/buzz/commit/620822899a6373fa3a17a87815cd7cade25ed332)) +- refactor(desktop): remove vestigial MCP toolsets config ([#1776](https://github.com/block/buzz/pull/1776)) ([`dfec75b3c0`](https://github.com/block/buzz/commit/dfec75b3c0b8080529e4d9089d4ed80e3902aaed)) + + ## relay-v0.2.0 - feat: relay invite links (mint + claim + landing page + deep link) ([#1668](https://github.com/block/buzz/pull/1668)) ([`2e529aab7`](https://github.com/block/buzz/commit/2e529aab759a18c1bb81e447f3696fe99db53a27)) diff --git a/crates/buzz-relay/Cargo.toml b/crates/buzz-relay/Cargo.toml index cbad2a3b29..65fe32b6b3 100644 --- a/crates/buzz-relay/Cargo.toml +++ b/crates/buzz-relay/Cargo.toml @@ -4,7 +4,7 @@ default-run = "buzz-relay" # Independent version: buzz-relay ships as a pinnable artifact # (ghcr.io/block/buzz), released on its own cadence via `just release-relay`. # It does NOT inherit the workspace version. -version = "0.2.0" +version = "0.2.1" edition.workspace = true rust-version.workspace = true license.workspace = true From fbf89e3bed9adebc033a26b7c43362c004e816a2 Mon Sep 17 00:00:00 2001 From: Will Pfleger Date: Sat, 8 Aug 2026 12:59:41 -0400 Subject: [PATCH 05/18] fix(desktop): prevent horizontal clipping in Prompt Context modal (#5324) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Prompt Context modal (observer feed → check icon under sent messages) was clipping all content and card right-padding at the dialog edge. **Root cause**: `PromptContextDialog` renders inside `DialogContent`, which is a CSS grid. The child flex wrapper had default `min-width: auto`, so the widest unbreakable token in the content (64-char hex event IDs, `Tags: [[...]]` JSON) set the grid track width, blowing it past `max-w-xl`. `overflow-hidden` then clipped everything at the dialog edge — including the section cards' right padding. **Fix**: - `AgentSessionTranscriptList.tsx`: add `min-w-0` to the `flex max-h-[85vh] flex-col` wrapper so the grid item can shrink below its max-content width. - `PromptSectionAccordion.tsx`: replace `wrap-break-word` with `wrap-anywhere` on the body text (open and collapsed states) and the title. `overflow-wrap: anywhere` reduces min-content width, which `break-word` does not, letting long tokens wrap inside the cards rather than inflating the track. The `line-clamp-2` collapsed preview is preserved unchanged. Signed-off-by: Will Pfleger Co-authored-by: Duncan --- .../src/features/agents/ui/AgentSessionTranscriptList.tsx | 2 +- desktop/src/features/agents/ui/PromptSectionAccordion.tsx | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/desktop/src/features/agents/ui/AgentSessionTranscriptList.tsx b/desktop/src/features/agents/ui/AgentSessionTranscriptList.tsx index 29bfd7dbab..d24c8fab79 100644 --- a/desktop/src/features/agents/ui/AgentSessionTranscriptList.tsx +++ b/desktop/src/features/agents/ui/AgentSessionTranscriptList.tsx @@ -747,7 +747,7 @@ function PromptContextDialog({ return ( -
+
Prompt context {setupText ? ( diff --git a/desktop/src/features/agents/ui/PromptSectionAccordion.tsx b/desktop/src/features/agents/ui/PromptSectionAccordion.tsx index 0b5e58cc6c..ad5346db15 100644 --- a/desktop/src/features/agents/ui/PromptSectionAccordion.tsx +++ b/desktop/src/features/agents/ui/PromptSectionAccordion.tsx @@ -47,7 +47,7 @@ export function PromptSectionAccordion({
{section.title} @@ -56,8 +56,8 @@ export function PromptSectionAccordion({ className={cn( "mt-1 text-xs leading-5 text-foreground/70", open - ? "whitespace-pre-wrap wrap-break-word" - : "line-clamp-2 wrap-break-word", + ? "whitespace-pre-wrap wrap-anywhere" + : "line-clamp-2 wrap-anywhere", )} > {body.length > 0 ? ( From f029deafae6ad3b63e13c29104f3be76122cb1df Mon Sep 17 00:00:00 2001 From: Will Pfleger Date: Sat, 8 Aug 2026 13:00:09 -0400 Subject: [PATCH 06/18] fix(desktop): welcome banner overlap and missing dismiss control (#5330) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Problem The `WelcomeComposerGuidanceLayer` in the `#Welcome` channel was positioned with `absolute inset-x-0 bottom-full z-[-1]` — outside the `composerWrapperRef` measurement boundary. `useComposerHeightPadding` observes `composerWrapperRef`'s block size to set `paddingBottom` on the timeline scroll container, but the absolutely-positioned layer didn't contribute to that size. The banner sat directly on top of the newest message, blocking the thread affordance on that message, and had no manual dismiss control. ## Fix **Overlap**: Changed `WelcomeComposerGuidanceLayer` from `absolute inset-x-0 bottom-full z-[-1]` to `relative` (in normal flow). As a normal-flow child of `composer-dock`, the layer's full height is now measured by the ResizeObserver and fed into the timeline's `paddingBottom`, so the newest message is always fully visible and its thread affordance is always clickable while the banner shows. **Dismiss**: Added an `X` close button (`data-testid="welcome-composer-dismiss-button"`) on the prompt state. Clicking fires `onDismiss`, which drives `dismissing → hidden` immediately (same slide-down animation as the auto-dismiss path) and marks the channel ID as completed in the session ref so the banner does not reappear on channel re-entry within the session. **Refactor**: Extracted the banner state machine (refs, timers, `useEffect`s, and callbacks) from `ChannelPane.tsx` into `useWelcomeComposerBanner.ts`. This keeps `ChannelPane.tsx` well under the 1000-line file-size ratchet and makes the state machine independently testable. ## Changed files - `desktop/src/features/channels/ui/WelcomeComposerBanner.tsx` — `WelcomeComposerGuidanceLayer` positioning fix; `onDismiss` prop; dismiss button; `overflow-hidden` / `mb-0` / `flex-1` cleanup - `desktop/src/features/channels/ui/ChannelPane.tsx` — remove inline banner state machine, use `useWelcomeComposerBanner` hook, pass `onDismiss` - `desktop/src/features/channels/ui/useWelcomeComposerBanner.ts` — new hook owning all banner state --------- Signed-off-by: Will Pfleger Co-authored-by: Hayt <41ea58f1e64c243627e8acde7c89be667052ee6e17d8f021c1195be4324ebf04@buzz.block.builderlab.xyz> --- .../src/features/channels/ui/ChannelPane.tsx | 72 ++------------ .../channels/ui/WelcomeComposerBanner.tsx | 53 ++++++---- .../channels/ui/useWelcomeComposerBanner.ts | 99 +++++++++++++++++++ desktop/tests/e2e/onboarding.spec.ts | 84 +++++++++++++--- 4 files changed, 209 insertions(+), 99 deletions(-) create mode 100644 desktop/src/features/channels/ui/useWelcomeComposerBanner.ts diff --git a/desktop/src/features/channels/ui/ChannelPane.tsx b/desktop/src/features/channels/ui/ChannelPane.tsx index 7ea63f2339..13790d779f 100644 --- a/desktop/src/features/channels/ui/ChannelPane.tsx +++ b/desktop/src/features/channels/ui/ChannelPane.tsx @@ -43,12 +43,8 @@ import { ChannelComposerActivityAccessory } from "@/features/channels/ui/Channel import { containsWelcomePersonaMention, WelcomeComposerGuidanceLayer, - WELCOME_COMPOSER_BANNER_DISMISS_DURATION_SECONDS, - WELCOME_COMPOSER_BANNER_HIDE_BUFFER_MS, - WELCOME_COMPOSER_BANNER_SUCCESS_SETTLE_MS, - WELCOME_PERSONA_ROTATION_MS, - type WelcomeComposerBannerState, } from "@/features/channels/ui/WelcomeComposerBanner"; +import { useWelcomeComposerBanner } from "@/features/channels/ui/useWelcomeComposerBanner"; import { mentionsKnownAgent } from "@/features/channels/ui/ChannelPane.helpers"; import { HuddleStartingView, HuddleTranscriptIntro } from "@/features/huddle"; import { useChannelIntro } from "@/features/channels/ui/useChannelIntro"; @@ -168,11 +164,6 @@ export const ChannelPane = React.memo(function ChannelPane({ const timelineScrollRef = React.useRef(null); const messageTimelineRef = React.useRef(null); const composerWrapperRef = React.useRef(null); - const completedWelcomeBannerChannelIdsRef = React.useRef(new Set()); - const welcomeComposerDismissTimerRef = React.useRef(null); - const welcomeComposerHideTimerRef = React.useRef(null); - const [welcomeComposerBannerState, setWelcomeComposerBannerState] = - React.useState("prompt"); const { goChannel } = useAppNavigation(); const prepareDmSendChannel = usePrepareDmSendChannel( activeChannel, @@ -221,36 +212,11 @@ export const ChannelPane = React.memo(function ChannelPane({ "css-variable", () => messageTimelineRef.current?.settleAtBottom() ?? false, ); - const clearWelcomeComposerDismissTimer = React.useCallback(() => { - if (welcomeComposerDismissTimerRef.current !== null) { - window.clearTimeout(welcomeComposerDismissTimerRef.current); - welcomeComposerDismissTimerRef.current = null; - } - if (welcomeComposerHideTimerRef.current !== null) { - window.clearTimeout(welcomeComposerHideTimerRef.current); - welcomeComposerHideTimerRef.current = null; - } - }, []); - React.useEffect( - () => () => clearWelcomeComposerDismissTimer(), - [clearWelcomeComposerDismissTimer], - ); - React.useEffect(() => { - clearWelcomeComposerDismissTimer(); - if ( - activeChannelId && - isActiveWelcomeChannel && - completedWelcomeBannerChannelIdsRef.current.has(activeChannelId) - ) { - setWelcomeComposerBannerState("hidden"); - return; - } - setWelcomeComposerBannerState("prompt"); - }, [ - activeChannelId, - clearWelcomeComposerDismissTimer, - isActiveWelcomeChannel, - ]); + const { + bannerState: welcomeComposerBannerState, + completeBanner: completeWelcomeComposerBanner, + dismissBanner: handleDismissWelcomeBanner, + } = useWelcomeComposerBanner(activeChannelId, isActiveWelcomeChannel); const isEditInThread = editTarget != null && threadHeadMessage != null && @@ -330,31 +296,6 @@ export const ChannelPane = React.memo(function ChannelPane({ return pubkeys; }, [activityAgents, agentPubkeys, agentSessionAgents]); - const completeWelcomeComposerBanner = React.useCallback(() => { - if (!activeChannelId || !isActiveWelcomeChannel) { - return; - } - - clearWelcomeComposerDismissTimer(); - completedWelcomeBannerChannelIdsRef.current.add(activeChannelId); - setWelcomeComposerBannerState("complete"); - welcomeComposerDismissTimerRef.current = window.setTimeout(() => { - setWelcomeComposerBannerState("dismissing"); - welcomeComposerDismissTimerRef.current = null; - welcomeComposerHideTimerRef.current = window.setTimeout( - () => { - setWelcomeComposerBannerState("hidden"); - welcomeComposerHideTimerRef.current = null; - }, - WELCOME_COMPOSER_BANNER_DISMISS_DURATION_SECONDS * 1000 + - WELCOME_COMPOSER_BANNER_HIDE_BUFFER_MS, - ); - }, WELCOME_PERSONA_ROTATION_MS + WELCOME_COMPOSER_BANNER_SUCCESS_SETTLE_MS); - }, [ - activeChannelId, - clearWelcomeComposerDismissTimer, - isActiveWelcomeChannel, - ]); const handleSendMessage = React.useCallback( async ( content: string, @@ -739,6 +680,7 @@ export const ChannelPane = React.memo(function ChannelPane({ > {isActiveWelcomeChannel && !timeoutState.active ? ( diff --git a/desktop/src/features/channels/ui/WelcomeComposerBanner.tsx b/desktop/src/features/channels/ui/WelcomeComposerBanner.tsx index f75b8dbeb9..f050dd4b9f 100644 --- a/desktop/src/features/channels/ui/WelcomeComposerBanner.tsx +++ b/desktop/src/features/channels/ui/WelcomeComposerBanner.tsx @@ -1,6 +1,6 @@ import * as React from "react"; import { AnimatePresence, motion, useReducedMotion } from "motion/react"; -import { Bot, Check } from "lucide-react"; +import { Bot, Check, X } from "lucide-react"; import { ComposerDockGlassBackdrop } from "@/features/messages/ui/ComposerDockBackdrop"; import { cn } from "@/shared/lib/cn"; @@ -291,9 +291,15 @@ type WelcomeComposerBannerProps = { * banner during this window. */ settingUp?: boolean; + /** + * Called when the user dismisses the banner manually via the close button. + * Only rendered while `state === "prompt"`. + */ + onDismiss?: () => void; }; export function WelcomeComposerBanner({ + onDismiss, settingUp = false, state, }: WelcomeComposerBannerProps) { @@ -307,7 +313,7 @@ export function WelcomeComposerBanner({ animate={{ height: state === "dismissing" ? 0 : "auto", }} - className="overflow-visible" + className="overflow-hidden" initial={false} transition={{ duration: @@ -326,7 +332,7 @@ export function WelcomeComposerBanner({ : 0, }} className={cn( - "relative z-[1] mx-5 -mb-3 flex items-center gap-2 rounded-t-2xl border border-b-0 px-4 pb-5 pt-2.5 text-sm leading-5 transition-colors", + "relative z-[1] mx-5 mb-0 flex items-center gap-2 rounded-t-2xl border border-b-0 px-4 pb-5 pt-2.5 text-sm leading-5 transition-colors", state !== "prompt" ? "border-emerald-500/30 bg-emerald-500/15 text-foreground" : "border-border/60 bg-muted/55 text-muted-foreground", @@ -376,7 +382,7 @@ export function WelcomeComposerBanner({ {state !== "prompt" ? ( )} + {state === "prompt" && onDismiss && !settingUp ? ( + + ) : null} @@ -422,22 +439,22 @@ type WelcomeComposerGuidanceLayerProps = WelcomeComposerBannerProps & { export function WelcomeComposerGuidanceLayer({ children, + onDismiss, settingUp, state, }: WelcomeComposerGuidanceLayerProps) { return ( -
-
- - {children} - -
+
+ + {children} +
); } diff --git a/desktop/src/features/channels/ui/useWelcomeComposerBanner.ts b/desktop/src/features/channels/ui/useWelcomeComposerBanner.ts new file mode 100644 index 0000000000..eb09eddd0e --- /dev/null +++ b/desktop/src/features/channels/ui/useWelcomeComposerBanner.ts @@ -0,0 +1,99 @@ +import * as React from "react"; + +import { + WELCOME_COMPOSER_BANNER_DISMISS_DURATION_SECONDS, + WELCOME_COMPOSER_BANNER_HIDE_BUFFER_MS, + WELCOME_COMPOSER_BANNER_SUCCESS_SETTLE_MS, + WELCOME_PERSONA_ROTATION_MS, + type WelcomeComposerBannerState, +} from "@/features/channels/ui/WelcomeComposerBanner"; + +/** + * Manages the Welcome-channel composer hint banner's state machine. + * + * Tracks which channels have been completed within the session so the banner + * stays hidden on re-entry. Exposes three transitions: + * - `completeBanner`: agent-mention path — plays the "Nice work." success + * animation before auto-dismissing. + * - `dismissBanner`: manual X-button path — immediately begins the slide-down + * dismiss animation. + */ +export function useWelcomeComposerBanner( + activeChannelId: string | null, + isActiveWelcomeChannel: boolean, +): { + bannerState: WelcomeComposerBannerState; + completeBanner: () => void; + dismissBanner: () => void; +} { + const completedChannelIdsRef = React.useRef(new Set()); + const dismissTimerRef = React.useRef(null); + const hideTimerRef = React.useRef(null); + const [bannerState, setBannerState] = + React.useState("prompt"); + + const clearTimers = React.useCallback(() => { + if (dismissTimerRef.current !== null) { + window.clearTimeout(dismissTimerRef.current); + dismissTimerRef.current = null; + } + if (hideTimerRef.current !== null) { + window.clearTimeout(hideTimerRef.current); + hideTimerRef.current = null; + } + }, []); + + React.useEffect(() => () => clearTimers(), [clearTimers]); + + React.useEffect(() => { + clearTimers(); + if ( + activeChannelId && + isActiveWelcomeChannel && + completedChannelIdsRef.current.has(activeChannelId) + ) { + setBannerState("hidden"); + return; + } + setBannerState("prompt"); + }, [activeChannelId, clearTimers, isActiveWelcomeChannel]); + + const scheduleHide = React.useCallback(() => { + hideTimerRef.current = window.setTimeout( + () => { + setBannerState("hidden"); + hideTimerRef.current = null; + }, + WELCOME_COMPOSER_BANNER_DISMISS_DURATION_SECONDS * 1000 + + WELCOME_COMPOSER_BANNER_HIDE_BUFFER_MS, + ); + }, []); + + const completeBanner = React.useCallback(() => { + if (!activeChannelId || !isActiveWelcomeChannel) { + return; + } + + clearTimers(); + completedChannelIdsRef.current.add(activeChannelId); + setBannerState("complete"); + dismissTimerRef.current = window.setTimeout(() => { + setBannerState("dismissing"); + dismissTimerRef.current = null; + scheduleHide(); + }, WELCOME_PERSONA_ROTATION_MS + WELCOME_COMPOSER_BANNER_SUCCESS_SETTLE_MS); + }, [activeChannelId, clearTimers, isActiveWelcomeChannel, scheduleHide]); + + const dismissBanner = React.useCallback(() => { + if (!activeChannelId || !isActiveWelcomeChannel) { + return; + } + + clearTimers(); + completedChannelIdsRef.current.add(activeChannelId); + setBannerState("dismissing"); + scheduleHide(); + }, [activeChannelId, clearTimers, isActiveWelcomeChannel, scheduleHide]); + + return { bannerState, completeBanner, dismissBanner }; +} diff --git a/desktop/tests/e2e/onboarding.spec.ts b/desktop/tests/e2e/onboarding.spec.ts index e5217da3d3..5e0e6a4fa2 100644 --- a/desktop/tests/e2e/onboarding.spec.ts +++ b/desktop/tests/e2e/onboarding.spec.ts @@ -207,6 +207,7 @@ async function expectWelcomeComposerBannerLayout(page: Page) { .locator("div") .boundingBox(); const guidanceLayer = page.getByTestId("welcome-composer-guidance-layer"); + const guidanceLayerBox = await guidanceLayer.boundingBox(); const guidanceBackdrop = page.getByTestId( "welcome-composer-guidance-backdrop", ); @@ -217,6 +218,7 @@ async function expectWelcomeComposerBannerLayout(page: Page) { !personaMentionBox || !composerBox || !dockBackdropBox || + !guidanceLayerBox || !guidanceBackdropBox ) { throw new Error("Could not measure welcome composer banner layout"); @@ -226,23 +228,20 @@ async function expectWelcomeComposerBannerLayout(page: Page) { await composer.getByTestId("welcome-composer-guide-banner").count(), ).toBe(0); expect(bannerBox.y).toBeLessThan(composerBox.y); - expect(bannerBox.y + bannerBox.height).toBeGreaterThan(composerBox.y); - expect(Math.abs(dockBackdropBox.y - composerBox.y)).toBeLessThanOrEqual(1); + // Banner is in normal flow above the composer, no overlap. + expect(bannerBox.y + bannerBox.height).toBeLessThanOrEqual(composerBox.y); + // The dock backdrop is absolute inset-y-0 inside composer-dock, which now + // contains the guidance layer + composer in flow, so its top aligns with the + // guidance layer top (not the composer top). + expect(Math.abs(dockBackdropBox.y - guidanceLayerBox.y)).toBeLessThanOrEqual( + 1, + ); expect(guidanceBackdropBox.y).toBeLessThanOrEqual(bannerBox.y); - expect( - Math.abs( - guidanceBackdropBox.y + guidanceBackdropBox.height - composerBox.y, - ), - ).toBeLessThanOrEqual(1); - const [guidanceZIndex, backdropZIndex] = await Promise.all([ - guidanceLayer.evaluate((element) => - Number(window.getComputedStyle(element).zIndex), - ), - page - .getByTestId("composer-dock-backdrop") - .evaluate((element) => Number(window.getComputedStyle(element).zIndex)), - ]); - expect(guidanceZIndex).toBeLessThan(backdropZIndex); + // The guidance backdrop extends bottom-3 (12px) short of the banner's bottom, + // visually connecting up to the composer. + expect(guidanceBackdropBox.y + guidanceBackdropBox.height).toBeLessThan( + composerBox.y, + ); expect( await page .getByTestId("channel-composer-overlay") @@ -3170,6 +3169,59 @@ test("finishing onboarding creates starter channels and focuses welcome-everyone await expectWelcomeComposerBannerCompletesAfterPersonaMention(page); }); +test("welcome-everywhere banner: X dismiss removes the guidance surface", async ({ + page, +}) => { + await seedActiveIdentity(page, BLANK_TYLER_IDENTITY); + await installMockBridge(page, undefined, { skipOnboardingSeed: true }); + await page.goto("/"); + + await page.getByTestId("onboarding-display-name").fill("Morty QA"); + await completeProfileOnboarding(page); + + const banner = page.getByTestId("welcome-composer-guide-banner"); + const guidanceLayer = page.getByTestId("welcome-composer-guidance-layer"); + const dismissButton = page.getByTestId("welcome-composer-dismiss-button"); + + // Banner and guidance layer are visible in the prompt state. + await expect(banner).toBeVisible(); + await expect(guidanceLayer).toBeVisible(); + await expect(dismissButton).toBeVisible(); + + await dismissButton.click(); + + // After dismiss the entire guidance surface must be gone. + await expect(banner).toHaveCount(0, { timeout: 2_000 }); + await expect(guidanceLayer).toHaveCount(0); +}); + +test("welcome-everywhere banner: dismiss persists after channel re-entry", async ({ + page, +}) => { + await seedActiveIdentity(page, BLANK_TYLER_IDENTITY); + await installMockBridge(page, undefined, { skipOnboardingSeed: true }); + await page.goto("/"); + + await page.getByTestId("onboarding-display-name").fill("Morty QA"); + await completeProfileOnboarding(page); + + const banner = page.getByTestId("welcome-composer-guide-banner"); + + await expect(banner).toBeVisible(); + await page.getByTestId("welcome-composer-dismiss-button").click(); + await expect(banner).toHaveCount(0, { timeout: 2_000 }); + + // Leave the Welcome channel. + await page.getByTestId("channel-general").click(); + await expect(page.getByTestId("chat-title")).toContainText("general"); + await expect(banner).toHaveCount(0); + + // Return — banner must stay hidden. + await page.getByTestId("channel-welcome-everyone").click(); + await expect(page.getByTestId("chat-title")).toContainText("Welcome"); + await expect(banner).toHaveCount(0); +}); + test("initial profile read failures still hold incomplete users in onboarding", async ({ page, }) => { From 5bf78671f45178f8de02ba18d3d321cbbf19cd1f Mon Sep 17 00:00:00 2001 From: Tyler <109685178+tlongwell-block@users.noreply.github.com> Date: Sat, 8 Aug 2026 17:29:06 -0400 Subject: [PATCH 07/18] fix(agent): retry LLM completion on malformed 2xx JSON body (#5351) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Problem A provider can return HTTP 200 with a **truncated JSON body** — cleanly closed connection, correct framing, content cut off mid-value. Both LLM HTTP loops treated this as a terminal error on the first attempt: `AgentError::Llm("json: EOF while parsing a value")`, surfaced as code -32000 at the ACP boundary, killing the agent turn before it produced anything. Observed live in a tb2.1 bench trial (write-compressor, tb21-twins-1): deepseek via OpenRouter returned a truncated body, the agent died mid-prompt with 0 turns completed, and the trial scored 0 on a provider hiccup. Meanwhile the same loops already retry timeouts, 429s, 5xxs, 499s, and mid-body stream stalls — a truncated-but-complete body was the one transient upstream fault that fell through to terminal. ## Fix In both `post()` and `openrouter_post()` (`crates/buzz-agent/src/llm.rs`): when the fully-received success body fails `serde_json::from_slice`, `continue` the **existing** retry loop instead of returning terminal — same `MAX_RETRIES` (3) bound, same `backoff_with_jitter`. On exhaustion, the error goes through `terminal_llm_error` so it carries cumulative duration + attempt count like every other retried failure (previously the `json:` error carried neither). `post_anthropic` routes through `post()`, so Anthropic/OpenAI/Databricks/mesh and OpenRouter are all covered. ## Why this cannot re-run a tool call Hard requirement: tool calls are not idempotent, and this change must not introduce any possibility of replaying one. 1. **The retry lives inside the HTTP POST helper, below the parse boundary.** Tool calls are only ever extracted from a *successfully parsed* response value (`parse_openai`/`parse_anthropic`/`parse_responses`, all downstream of these helpers' `Ok` return). A malformed body never parses, therefore no tool call was ever extracted from it, therefore nothing downstream of it ever dispatched. 2. **What is re-sent is the completion request itself** — the identical `body_bytes` captured once at function entry. Sending a completion request executes no tools; it asks the model for the next message. 3. **Same safety class as existing behavior.** The loop already re-sends this identical request on 429/5xx/timeout/stream-stall; this adds one more transient-fault arm to the same loop with the same bytes. ## Tests Three new tests mirroring the existing 499/dropped-connection fixtures (raw `TcpListener` stubs): - `post_retries_malformed_json_body_and_succeeds` — truncated 200 body on attempt 1, valid JSON on attempt 2; asserts success and **exactly 2** server-side requests - `post_exhausts_retries_on_persistent_malformed_json` — always-truncated body; asserts exactly `MAX_RETRIES` attempts and a terminal error carrying `json:` + cumulative/attempt context - `openrouter_post_retries_malformed_json_body_and_succeeds` — same recovery through OpenRouter's separate loop Full `cargo test -p buzz-agent` green at e7a5d7bb (430 lib + all integration targets, 0 failures); `cargo fmt` + `clippy --all-targets` clean. Originating conversation: buzz-benchmarking channel, thread 397a992d. Signed-off-by: Eva <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz> Co-authored-by: Eva <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz> --- crates/buzz-agent/src/llm.rs | 286 ++++++++++++++++++++++++++++++++++- 1 file changed, 283 insertions(+), 3 deletions(-) diff --git a/crates/buzz-agent/src/llm.rs b/crates/buzz-agent/src/llm.rs index dc9501aeef..c8c0a8550f 100644 --- a/crates/buzz-agent/src/llm.rs +++ b/crates/buzz-agent/src/llm.rs @@ -2203,8 +2203,33 @@ where } } } - return serde_json::from_slice(&buf) - .map_err(|e| PostError::Agent(AgentError::Llm(format!("json: {e}")))); + // A 2xx body that fails to parse (e.g. a provider flushing a + // truncated JSON document and closing the stream cleanly) is a + // transient upstream fault, not a request problem: retry it like a + // 5xx. Safe to re-send — a malformed body produced no parsed + // response, so no tool call was ever extracted from it, and the + // retried request is the identical completion POST captured in + // `body_bytes` at function entry. + match serde_json::from_slice(&buf) { + Ok(value) => return Ok(value), + Err(e) => { + if attempt + 1 < MAX_RETRIES { + tracing::warn!( + attempt = attempt + 1, + max_attempts = MAX_RETRIES, + error = %e, + "llm: malformed response body, retrying" + ); + backoff_with_jitter(attempt).await; + continue; + } + return Err(PostError::Agent(terminal_llm_error( + call_start.elapsed(), + attempt + 1, + &format!("json: {e}"), + ))); + } + } } // Unreachable in practice: every iteration either returns or continues. // A fallthrough here would mean MAX_RETRIES was 0, which is rejected at @@ -2610,7 +2635,31 @@ async fn openrouter_post( } } } - return serde_json::from_slice(&buf).map_err(|e| AgentError::Llm(format!("json: {e}"))); + // Same malformed-body retry as the shared `post()` terminal: a + // truncated 2xx JSON body is transient upstream trouble, and + // re-sending is provably tool-safe — nothing was parsed, so no tool + // call could have been extracted, and the retry re-uses the + // identical `body_bytes` completion request. + match serde_json::from_slice(&buf) { + Ok(value) => return Ok(value), + Err(e) => { + if attempt + 1 < MAX_RETRIES { + tracing::warn!( + attempt = attempt + 1, + max_attempts = MAX_RETRIES, + error = %e, + "llm: openrouter malformed response body, retrying" + ); + backoff_with_jitter(attempt).await; + continue; + } + return Err(terminal_llm_error( + call_start.elapsed(), + attempt + 1, + &format!("json: {e}"), + )); + } + } } Err(terminal_llm_error( call_start.elapsed(), @@ -4791,6 +4840,237 @@ mod tests { ); } + /// Regression (write-compressor, tb21-twins-1): a provider returning + /// HTTP 200 with a *truncated* JSON body (cleanly closed, correct + /// framing, unparseable content) previously surfaced as a terminal + /// `AgentError::Llm("json: EOF while parsing a value ...")` on the very + /// first attempt, killing the agent turn. A malformed body is transient + /// upstream trouble and must be retried like a 5xx. Re-sending is + /// tool-safe: nothing was parsed, so no tool call was extracted from the + /// bad body, and the retry replays the identical completion request. + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn post_retries_malformed_json_body_and_succeeds() { + use std::sync::atomic::{AtomicU32, Ordering}; + use std::sync::Arc; + use tokio::io::{AsyncReadExt, AsyncWriteExt}; + use tokio::net::TcpListener; + + let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); + let url = format!("http://{}/v1/x", listener.local_addr().unwrap()); + let accepts = Arc::new(AtomicU32::new(0)); + let accepts_srv = accepts.clone(); + + tokio::spawn(async move { + loop { + let (mut sock, _) = match listener.accept().await { + Ok(p) => p, + Err(_) => return, + }; + let n = accepts_srv.fetch_add(1, Ordering::SeqCst); + let mut buf = Vec::new(); + let mut tmp = [0u8; 4096]; + while !buf.windows(4).any(|w| w == b"\r\n\r\n") { + match sock.read(&mut tmp).await { + Ok(0) | Err(_) => return, + Ok(k) => buf.extend_from_slice(&tmp[..k]), + } + } + if n == 0 { + // First attempt: 200 OK with a truncated JSON document. + // Content-Length matches the bytes actually sent, so the + // body read completes cleanly — the fault is purely that + // the JSON is cut off mid-value. + let body = "{\"choices\":[{\"mess"; + let resp = format!( + "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\ + Content-Length: {}\r\nConnection: close\r\n\r\n{}", + body.len(), + body, + ); + let _ = sock.write_all(resp.as_bytes()).await; + let _ = sock.shutdown().await; + continue; + } + // Subsequent attempts: complete valid JSON. + let body = "{\"ok\":true}"; + let resp = format!( + "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\ + Content-Length: {}\r\nConnection: close\r\n\r\n{}", + body.len(), + body, + ); + let _ = sock.write_all(resp.as_bytes()).await; + let _ = sock.shutdown().await; + } + }); + + let client = Client::builder() + .timeout(Duration::from_secs(5)) + .build() + .unwrap(); + let out = post( + &client, + &url, + &serde_json::json!({}), + false, + Duration::from_secs(5), + |b| b, + ) + .await + .expect("post should succeed after retrying the malformed body"); + assert_eq!(out, serde_json::json!({ "ok": true })); + assert_eq!( + accepts.load(Ordering::SeqCst), + 2, + "server must see exactly 2 attempts (malformed body retried once)" + ); + } + + /// A persistently malformed 200 body exhausts MAX_RETRIES and surfaces + /// the terminal error with the `json:` detail plus cumulative + /// duration/attempt count — never an early first-attempt death. + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn post_exhausts_retries_on_persistent_malformed_json() { + use std::sync::atomic::{AtomicU32, Ordering}; + use std::sync::Arc; + use tokio::io::{AsyncReadExt, AsyncWriteExt}; + use tokio::net::TcpListener; + + let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); + let url = format!("http://{}/v1/x", listener.local_addr().unwrap()); + let accepts = Arc::new(AtomicU32::new(0)); + let accepts_srv = accepts.clone(); + + tokio::spawn(async move { + loop { + let (mut sock, _) = match listener.accept().await { + Ok(p) => p, + Err(_) => return, + }; + accepts_srv.fetch_add(1, Ordering::SeqCst); + let mut buf = Vec::new(); + let mut tmp = [0u8; 4096]; + while !buf.windows(4).any(|w| w == b"\r\n\r\n") { + match sock.read(&mut tmp).await { + Ok(0) | Err(_) => return, + Ok(k) => buf.extend_from_slice(&tmp[..k]), + } + } + let body = "{\"choices\":[{\"mess"; + let resp = format!( + "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\ + Content-Length: {}\r\nConnection: close\r\n\r\n{}", + body.len(), + body, + ); + let _ = sock.write_all(resp.as_bytes()).await; + let _ = sock.shutdown().await; + } + }); + + let client = Client::builder() + .timeout(Duration::from_secs(5)) + .build() + .unwrap(); + let err = post( + &client, + &url, + &serde_json::json!({}), + false, + Duration::from_secs(5), + |b| b, + ) + .await + .unwrap_err(); + match &err { + PostError::Agent(AgentError::Llm(msg)) => { + assert!( + msg.contains("json:"), + "expected the json parse detail, got: {msg}" + ); + assert!( + msg.contains("cumulative") && msg.contains("3 attempts"), + "expected cumulative duration + exact attempt count, got: {msg}" + ); + } + other => panic!("expected PostError::Agent(AgentError::Llm), got: {other:?}"), + } + assert_eq!( + accepts.load(Ordering::SeqCst), + MAX_RETRIES, + "server must see exactly MAX_RETRIES attempts — malformed bodies must be retried" + ); + } + + /// Same regression coverage for `openrouter_post`, which carries its own + /// retry loop: a truncated 200 body on the first attempt is retried and + /// the call succeeds on the second. + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn openrouter_post_retries_malformed_json_body_and_succeeds() { + use std::sync::atomic::{AtomicU32, Ordering}; + use std::sync::Arc; + use tokio::io::{AsyncReadExt, AsyncWriteExt}; + use tokio::net::TcpListener; + + let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); + let url = format!("http://{}/v1/x", listener.local_addr().unwrap()); + let accepts = Arc::new(AtomicU32::new(0)); + let accepts_srv = accepts.clone(); + + tokio::spawn(async move { + loop { + let (mut sock, _) = match listener.accept().await { + Ok(p) => p, + Err(_) => return, + }; + let n = accepts_srv.fetch_add(1, Ordering::SeqCst); + let mut buf = Vec::new(); + let mut tmp = [0u8; 4096]; + while !buf.windows(4).any(|w| w == b"\r\n\r\n") { + match sock.read(&mut tmp).await { + Ok(0) | Err(_) => return, + Ok(k) => buf.extend_from_slice(&tmp[..k]), + } + } + if n == 0 { + let body = "{\"choices\":[{\"mess"; + let resp = format!( + "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\ + Content-Length: {}\r\nConnection: close\r\n\r\n{}", + body.len(), + body, + ); + let _ = sock.write_all(resp.as_bytes()).await; + let _ = sock.shutdown().await; + continue; + } + let body = r#"{"choices":[{"message":{"role":"assistant","content":"ok"},"finish_reason":"stop"}]}"#; + let resp = format!( + "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\ + Content-Length: {}\r\nConnection: close\r\n\r\n{}", + body.len(), + body, + ); + let _ = sock.write_all(resp.as_bytes()).await; + let _ = sock.shutdown().await; + } + }); + + let client = Client::builder() + .timeout(Duration::from_secs(5)) + .build() + .unwrap(); + let out = openrouter_post(&client, &url, &json!({}), "key", Duration::from_secs(5)) + .await + .expect("openrouter_post should succeed after retrying the malformed body"); + assert!(out.is_object(), "expected a JSON object: {out:?}"); + assert_eq!( + accepts.load(Ordering::SeqCst), + 2, + "server must see exactly 2 attempts (malformed body retried once)" + ); + } + /// A body-read timeout on the first attempt triggers a retry under an /// escalated budget, and the call succeeds on the second attempt. /// From 97aa9e31856edb9d8abcdcb33c472027f5588890 Mon Sep 17 00:00:00 2001 From: Wes Date: Sun, 9 Aug 2026 10:05:47 -0600 Subject: [PATCH 08/18] fix(desktop): preserve Welcome banner dismissal (#5406) ## Summary - remove the complete Welcome guidance surface when dismissal reaches `hidden` - preserve dismissal across the private and starter Welcome channels for the active identity - assert the starter channel's actual `welcome-everyone` title on re-entry ## Why PR #5330 introduced two deterministic Desktop E2E failures: - the inner banner unmounted, but `welcome-composer-guidance-layer` remained - the re-entry test expected case-sensitive `Welcome` while navigating to `welcome-everyone` The state hook also scoped completion to channel IDs while `ChannelPane` remounts during navigation. The Welcome guidance is one experience spanning both Welcome channels, so completion now survives that remount while remaining identity-scoped. ## Validation At `b577eb42edffe889f63566f2457eacea720f3593`: - `pnpm -C desktop typecheck` - focused Biome check for all four changed files - E2E build - both `welcome-everywhere banner` integration tests repeated three times: **6/6 passed** - mandatory pre-push desktop check, typecheck, and full desktop unit suite: **4,535 passed** - `git diff --check` Signed-off-by: Wes Co-authored-by: Carl --- .../src/features/channels/ui/ChannelPane.tsx | 6 ++- .../channels/ui/WelcomeComposerBanner.tsx | 4 ++ .../channels/ui/useWelcomeComposerBanner.ts | 39 +++++++++++++------ desktop/tests/e2e/onboarding.spec.ts | 4 +- 4 files changed, 39 insertions(+), 14 deletions(-) diff --git a/desktop/src/features/channels/ui/ChannelPane.tsx b/desktop/src/features/channels/ui/ChannelPane.tsx index 13790d779f..410b05a2cc 100644 --- a/desktop/src/features/channels/ui/ChannelPane.tsx +++ b/desktop/src/features/channels/ui/ChannelPane.tsx @@ -216,7 +216,11 @@ export const ChannelPane = React.memo(function ChannelPane({ bannerState: welcomeComposerBannerState, completeBanner: completeWelcomeComposerBanner, dismissBanner: handleDismissWelcomeBanner, - } = useWelcomeComposerBanner(activeChannelId, isActiveWelcomeChannel); + } = useWelcomeComposerBanner( + activeChannelId, + isActiveWelcomeChannel, + currentPubkey ?? null, + ); const isEditInThread = editTarget != null && threadHeadMessage != null && diff --git a/desktop/src/features/channels/ui/WelcomeComposerBanner.tsx b/desktop/src/features/channels/ui/WelcomeComposerBanner.tsx index f050dd4b9f..9a8db082ed 100644 --- a/desktop/src/features/channels/ui/WelcomeComposerBanner.tsx +++ b/desktop/src/features/channels/ui/WelcomeComposerBanner.tsx @@ -443,6 +443,10 @@ export function WelcomeComposerGuidanceLayer({ settingUp, state, }: WelcomeComposerGuidanceLayerProps) { + if (state === "hidden") { + return null; + } + return (
(); + /** * Manages the Welcome-channel composer hint banner's state machine. * - * Tracks which channels have been completed within the session so the banner - * stays hidden on re-entry. Exposes three transitions: + * Remembers completion across the Welcome experience per identity for this app + * session, so the hint stays hidden while moving between the private and + * starter Welcome channels without leaking dismissal to another identity. * - `completeBanner`: agent-mention path — plays the "Nice work." success * animation before auto-dismissing. * - `dismissBanner`: manual X-button path — immediately begins the slide-down @@ -21,12 +24,12 @@ import { export function useWelcomeComposerBanner( activeChannelId: string | null, isActiveWelcomeChannel: boolean, + identityPubkey: string | null, ): { bannerState: WelcomeComposerBannerState; completeBanner: () => void; dismissBanner: () => void; } { - const completedChannelIdsRef = React.useRef(new Set()); const dismissTimerRef = React.useRef(null); const hideTimerRef = React.useRef(null); const [bannerState, setBannerState] = @@ -48,15 +51,15 @@ export function useWelcomeComposerBanner( React.useEffect(() => { clearTimers(); if ( - activeChannelId && isActiveWelcomeChannel && - completedChannelIdsRef.current.has(activeChannelId) + identityPubkey && + completedWelcomeComposerIdentityPubkeys.has(identityPubkey) ) { setBannerState("hidden"); return; } setBannerState("prompt"); - }, [activeChannelId, clearTimers, isActiveWelcomeChannel]); + }, [clearTimers, identityPubkey, isActiveWelcomeChannel]); const scheduleHide = React.useCallback(() => { hideTimerRef.current = window.setTimeout( @@ -70,30 +73,42 @@ export function useWelcomeComposerBanner( }, []); const completeBanner = React.useCallback(() => { - if (!activeChannelId || !isActiveWelcomeChannel) { + if (!activeChannelId || !isActiveWelcomeChannel || !identityPubkey) { return; } clearTimers(); - completedChannelIdsRef.current.add(activeChannelId); + completedWelcomeComposerIdentityPubkeys.add(identityPubkey); setBannerState("complete"); dismissTimerRef.current = window.setTimeout(() => { setBannerState("dismissing"); dismissTimerRef.current = null; scheduleHide(); }, WELCOME_PERSONA_ROTATION_MS + WELCOME_COMPOSER_BANNER_SUCCESS_SETTLE_MS); - }, [activeChannelId, clearTimers, isActiveWelcomeChannel, scheduleHide]); + }, [ + activeChannelId, + clearTimers, + identityPubkey, + isActiveWelcomeChannel, + scheduleHide, + ]); const dismissBanner = React.useCallback(() => { - if (!activeChannelId || !isActiveWelcomeChannel) { + if (!activeChannelId || !isActiveWelcomeChannel || !identityPubkey) { return; } clearTimers(); - completedChannelIdsRef.current.add(activeChannelId); + completedWelcomeComposerIdentityPubkeys.add(identityPubkey); setBannerState("dismissing"); scheduleHide(); - }, [activeChannelId, clearTimers, isActiveWelcomeChannel, scheduleHide]); + }, [ + activeChannelId, + clearTimers, + identityPubkey, + isActiveWelcomeChannel, + scheduleHide, + ]); return { bannerState, completeBanner, dismissBanner }; } diff --git a/desktop/tests/e2e/onboarding.spec.ts b/desktop/tests/e2e/onboarding.spec.ts index 5e0e6a4fa2..403edbcda1 100644 --- a/desktop/tests/e2e/onboarding.spec.ts +++ b/desktop/tests/e2e/onboarding.spec.ts @@ -3218,7 +3218,9 @@ test("welcome-everywhere banner: dismiss persists after channel re-entry", async // Return — banner must stay hidden. await page.getByTestId("channel-welcome-everyone").click(); - await expect(page.getByTestId("chat-title")).toContainText("Welcome"); + await expect(page.getByTestId("chat-title")).toContainText( + "welcome-everyone", + ); await expect(banner).toHaveCount(0); }); From e668c6bb4913e36e58d7f947dbaf982e704e9132 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 9 Aug 2026 09:07:46 -0700 Subject: [PATCH 09/18] chore(deps): update rust crate clap to v4.6.6 (#4465) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [clap](https://redirect.github.com/clap-rs/clap) | dependencies | patch | `4.6.1` → `4.6.6` | --- > [!WARNING] > Some dependencies could not be looked up. Check the [Dependency Dashboard](../issues/1) for more information. --- ### Release Notes
clap-rs/clap (clap) ### [`v4.6.6`](https://redirect.github.com/clap-rs/clap/compare/clap_complete-v4.6.5...clap_complete-v4.6.6) [Compare Source](https://redirect.github.com/clap-rs/clap/compare/v4.6.5...v4.6.6) ### [`v4.6.5`](https://redirect.github.com/clap-rs/clap/compare/clap_complete-v4.6.4...clap_complete-v4.6.5) [Compare Source](https://redirect.github.com/clap-rs/clap/compare/v4.6.4...v4.6.5) ### [`v4.6.4`](https://redirect.github.com/clap-rs/clap/blob/HEAD/CHANGELOG.md#464---2026-07-21) [Compare Source](https://redirect.github.com/clap-rs/clap/compare/v4.6.3...v4.6.4) ##### Internal - Update to syn v3 ### [`v4.6.3`](https://redirect.github.com/clap-rs/clap/blob/HEAD/CHANGELOG.md#463---2026-07-20) [Compare Source](https://redirect.github.com/clap-rs/clap/compare/v4.6.2...v4.6.3) ##### Fixes - *(derive)* Allow `"literal".function()` as attribute values ### [`v4.6.2`](https://redirect.github.com/clap-rs/clap/blob/HEAD/CHANGELOG.md#462---2026-07-15) [Compare Source](https://redirect.github.com/clap-rs/clap/compare/v4.6.1...v4.6.2) ##### Fixes - *(help)* Say `alias` when there is only one
--- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - Between 12:00 AM and 03:59 AM, only on Monday (`* 0-3 * * 1`) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Enabled. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://redirect.github.com/renovatebot/renovate/discussions) if that's undesired. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/block/buzz). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.lock | 57 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f7c42e625a..86061df402 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -117,7 +117,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -128,7 +128,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -1557,9 +1557,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.6.1" +version = "4.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" +checksum = "473c7e07f409a8d772161724aa8db6a765a2532a70f9667eeb7b49d3d02fbdca" dependencies = [ "clap_builder", "clap_derive", @@ -1567,9 +1567,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.6.0" +version = "4.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +checksum = "7b48fea5a88e9ae728a2dcbedbfc0e730f7d60da42e1cb049a83c9fb8b789889" dependencies = [ "anstream", "anstyle", @@ -1579,14 +1579,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.6.1" +version = "4.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" +checksum = "d012d2b9d65aca7f18f4d9878a045bc17899bba951561ba5ec3c2ba1eed9a061" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.3", ] [[package]] @@ -1637,7 +1637,7 @@ version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -2285,7 +2285,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccc2776f0c61eca1ca32528f85548abd1a4be8fb53d1b21c013e4f18da1e7090" dependencies = [ "data-encoding", - "syn 2.0.117", + "syn 1.0.109", ] [[package]] @@ -2496,7 +2496,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -2734,7 +2734,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -3140,7 +3140,7 @@ dependencies = [ "libc", "log", "rustversion", - "windows-link 0.2.1", + "windows-link 0.1.3", "windows-result 0.4.1", ] @@ -5902,7 +5902,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -8042,7 +8042,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.12.1", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -8101,7 +8101,7 @@ dependencies = [ "security-framework 3.7.0", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -8373,7 +8373,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b55fb86dfd3a2f5f76ea78310a88f96c4ea21a3031f8d212443d56123fd0521" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -8868,7 +8868,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -9380,6 +9380,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "sync_wrapper" version = "1.0.2" @@ -9485,7 +9496,7 @@ dependencies = [ "getrandom 0.4.3", "once_cell", "rustix 1.1.4", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -9498,7 +9509,7 @@ dependencies = [ "parking_lot", "rustix 1.1.4", "signal-hook", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -10234,7 +10245,7 @@ checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e" dependencies = [ "memoffset", "tempfile", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -10812,7 +10823,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] From 7dd8791d0765e9f15fed3299b6948e2babbfd763 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 9 Aug 2026 09:08:08 -0700 Subject: [PATCH 10/18] chore(deps): update rust crate async-compression to v0.4.43 (#4456) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [async-compression](https://redirect.github.com/Nullus157/async-compression) | dependencies | patch | `0.4.42` → `0.4.43` | --- > [!WARNING] > Some dependencies could not be looked up. Check the [Dependency Dashboard](../issues/1) for more information. --- ### Release Notes
Nullus157/async-compression (async-compression) ### [`v0.4.43`](https://redirect.github.com/Nullus157/async-compression/releases/tag/async-compression-v0.4.43) [Compare Source](https://redirect.github.com/Nullus157/async-compression/compare/async-compression-v0.4.42...async-compression-v0.4.43) ##### Other - Fix hang when decoding a corrupt subsequent zstd frame ([#​470](https://redirect.github.com/Nullus157/async-compression/pull/470))
--- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - Between 12:00 AM and 03:59 AM, only on Monday (`* 0-3 * * 1`) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Enabled. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://redirect.github.com/renovatebot/renovate/discussions) if that's undesired. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/block/buzz). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 86061df402..4a91803ddc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -235,9 +235,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.42" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79b3f8a79cccc2898f31920fc69f304859b3bd567490f75ebf51ae1c792a9ac" +checksum = "3976abdc8fe7d1133d43d304afd42abdf5bc3e1319d263d223bde07b5efc4be8" dependencies = [ "compression-codecs", "compression-core", From d7cc724fa5391b23e7fac99fc65dc28b79e4c5c4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 9 Aug 2026 09:08:38 -0700 Subject: [PATCH 11/18] chore(deps): update rust crate diffy to v0.5.1 (#4466) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [diffy](https://redirect.github.com/bmwill/diffy) | dependencies | patch | `0.5.0` → `0.5.1` | --- > [!WARNING] > Some dependencies could not be looked up. Check the [Dependency Dashboard](../issues/1) for more information. --- ### Release Notes
bmwill/diffy (diffy) ### [`v0.5.1`](https://redirect.github.com/bmwill/diffy/blob/HEAD/CHANGELOG.md#051---2026-07-18) [Compare Source](https://redirect.github.com/bmwill/diffy/compare/0.5.0...0.5.1) ##### Fixed - [#​85](https://redirect.github.com/bmwill/diffy/pull/85) Merge conflict markers are now always placed on their own lines. Previously, a conflicting hunk at the end of a file without a trailing newline glued the next marker onto its last content line, producing unparseable output. This matches `git merge-file --diff3` behavior.
--- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - Between 12:00 AM and 03:59 AM, only on Monday (`* 0-3 * * 1`) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Enabled. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://redirect.github.com/renovatebot/renovate/discussions) if that's undesired. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/block/buzz). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4a91803ddc..8577ef3d29 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2448,9 +2448,9 @@ checksum = "ab03c107fafeb3ee9f5925686dbb7a73bc76e3932abb0d2b365cb64b169cf04c" [[package]] name = "diffy" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05264ab2aab4fb952fc4b0f3f6eff1ddfb4563064053a4ea174d91537584a769" +checksum = "10aec8f7f9393bd6a4f2762be0ceb012d3cbe2478987258cc9960de148561914" dependencies = [ "hashbrown 0.17.1", ] From 12b1f566480d4feddc171739097f9359d3f255c1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 9 Aug 2026 09:08:58 -0700 Subject: [PATCH 12/18] chore(deps): update rust crate async-trait to v0.1.91 (#4458) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Type | Update | Change | Pending | |---|---|---|---|---| | [async-trait](https://redirect.github.com/dtolnay/async-trait) | dependencies | patch | `0.1.89` → `0.1.91` | `0.1.92` | --- > [!WARNING] > Some dependencies could not be looked up. Check the [Dependency Dashboard](../issues/1) for more information. --- ### Release Notes
dtolnay/async-trait (async-trait) ### [`v0.1.91`](https://redirect.github.com/dtolnay/async-trait/compare/0.1.90...0.1.91) [Compare Source](https://redirect.github.com/dtolnay/async-trait/compare/0.1.90...0.1.91) ### [`v0.1.90`](https://redirect.github.com/dtolnay/async-trait/releases/tag/0.1.90) [Compare Source](https://redirect.github.com/dtolnay/async-trait/compare/0.1.89...0.1.90) - Update to syn 3
--- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - Between 12:00 AM and 03:59 AM, only on Monday (`* 0-3 * * 1`) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Enabled. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://redirect.github.com/renovatebot/renovate/discussions) if that's undesired. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/block/buzz). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8577ef3d29..15f4dc4b4c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -329,13 +329,13 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.89" +version = "0.1.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +checksum = "ae36dc4177970ef04fde5178d3e2429882def40e57a451f919c098f72baa6cec" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.3", ] [[package]] From 08de85c592106ea2ffe22ba16e3a0fc10687db54 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 9 Aug 2026 09:09:26 -0700 Subject: [PATCH 13/18] chore(deps): update rust crate arc-swap to v1.9.2 (#4448) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [arc-swap](https://redirect.github.com/vorner/arc-swap) | dependencies | patch | `1.9.1` → `1.9.2` | --- > [!WARNING] > Some dependencies could not be looked up. Check the [Dependency Dashboard](../issues/1) for more information. --- ### Release Notes
vorner/arc-swap (arc-swap) ### [`v1.9.2`](https://redirect.github.com/vorner/arc-swap/blob/HEAD/CHANGELOG.md#192) - Document RefCnt must not panic ([#​208](https://redirect.github.com/vorner/arc-swap/issues/208)).
--- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - Between 12:00 AM and 03:59 AM, only on Monday (`* 0-3 * * 1`) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Enabled. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://redirect.github.com/renovatebot/renovate/discussions) if that's undesired. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/block/buzz). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 15f4dc4b4c..4423ed78c6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -172,9 +172,9 @@ dependencies = [ [[package]] name = "arc-swap" -version = "1.9.1" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a3a1fd6f75306b68087b831f025c712524bcb19aad54e557b1129cfa0a2b207" +checksum = "c049c0be4daef0b145cb3555416b3b8ef5b7888a38aea1a3a155801fe7b0810b" dependencies = [ "rustversion", ] From e1ff91ecc1269682a50c17da2c0708d1448b336f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 9 Aug 2026 09:09:50 -0700 Subject: [PATCH 14/18] chore(deps): update rust crate anyhow to v1.0.104 (#4447) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [anyhow](https://redirect.github.com/dtolnay/anyhow) | dependencies | patch | `1.0.103` → `1.0.104` | | [anyhow](https://redirect.github.com/dtolnay/anyhow) | workspace.dependencies | patch | `1.0.103` → `1.0.104` | --- > [!WARNING] > Some dependencies could not be looked up. Check the [Dependency Dashboard](../issues/1) for more information. --- ### Release Notes
dtolnay/anyhow (anyhow) ### [`v1.0.104`](https://redirect.github.com/dtolnay/anyhow/releases/tag/1.0.104) [Compare Source](https://redirect.github.com/dtolnay/anyhow/compare/1.0.103...1.0.104) - Update `syn` dev-dependency to version 3
--- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - Between 12:00 AM and 03:59 AM, only on Monday (`* 0-3 * * 1`) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Enabled. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://redirect.github.com/renovatebot/renovate/discussions) if that's undesired. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/block/buzz). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- desktop/src-tauri/Cargo.lock | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4423ed78c6..ac4ea620bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -133,9 +133,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.103" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" [[package]] name = "appattest" diff --git a/desktop/src-tauri/Cargo.lock b/desktop/src-tauri/Cargo.lock index c66bf4cb54..ad7cfed53d 100644 --- a/desktop/src-tauri/Cargo.lock +++ b/desktop/src-tauri/Cargo.lock @@ -226,9 +226,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.103" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" [[package]] name = "approx" From 856cdb848b0a849e33620887b145b7e598dfd95c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 9 Aug 2026 09:11:26 -0700 Subject: [PATCH 15/18] chore(deps): update all non-major dependencies (#3049) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | Type | Update | |---|---|---|---|---|---| | [@isomorphic-git/lightning-fs](https://redirect.github.com/isomorphic-git/lightning-fs) | [`4.6.2` → `4.6.3`](https://renovatebot.com/diffs/npm/@isomorphic-git%2flightning-fs/4.6.2/4.6.3) | ![age](https://developer.mend.io/api/mc/badges/age/npm/@isomorphic-git%2flightning-fs/4.6.3?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@isomorphic-git%2flightning-fs/4.6.2/4.6.3?slim=true) | dependencies | patch | | [@vitejs/plugin-react](https://redirect.github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-react#readme) ([source](https://redirect.github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react)) | [`6.0.3` → `6.0.5`](https://renovatebot.com/diffs/npm/@vitejs%2fplugin-react/6.0.3/6.0.5) | ![age](https://developer.mend.io/api/mc/badges/age/npm/@vitejs%2fplugin-react/6.0.5?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@vitejs%2fplugin-react/6.0.3/6.0.5?slim=true) | devDependencies | patch | | [@vitejs/plugin-react](https://redirect.github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-react#readme) ([source](https://redirect.github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react)) | [`6.0.3` → `6.0.5`](https://renovatebot.com/diffs/npm/@vitejs%2fplugin-react/6.0.3/6.0.5) | ![age](https://developer.mend.io/api/mc/badges/age/npm/@vitejs%2fplugin-react/6.0.5?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@vitejs%2fplugin-react/6.0.3/6.0.5?slim=true) | dependencies | patch | | [dorny/paths-filter](https://redirect.github.com/dorny/paths-filter) | `v4.0.2` → `v4.0.3` | ![age](https://developer.mend.io/api/mc/badges/age/github-tags/dorny%2fpaths-filter/v4.0.3?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/github-tags/dorny%2fpaths-filter/v4.0.2/v4.0.3?slim=true) | action | patch | | [isomorphic-git](https://isomorphic-git.org/) ([source](https://redirect.github.com/isomorphic-git/isomorphic-git)) | [`1.38.7` → `1.38.10`](https://renovatebot.com/diffs/npm/isomorphic-git/1.38.7/1.38.10) | ![age](https://developer.mend.io/api/mc/badges/age/npm/isomorphic-git/1.38.10?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/isomorphic-git/1.38.7/1.38.10?slim=true) | dependencies | patch | | [postcss](https://postcss.org/) ([source](https://redirect.github.com/postcss/postcss)) | [`8.5.19` → `8.5.26`](https://renovatebot.com/diffs/npm/postcss/8.5.19/8.5.26) | ![age](https://developer.mend.io/api/mc/badges/age/npm/postcss/8.5.26?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/postcss/8.5.19/8.5.26?slim=true) | devDependencies | patch | --- > [!WARNING] > Some dependencies could not be looked up. Check the [Dependency Dashboard](../issues/1) for more information. --- ### Release Notes
isomorphic-git/lightning-fs (@​isomorphic-git/lightning-fs) ### [`v4.6.3`](https://redirect.github.com/isomorphic-git/lightning-fs/releases/tag/v4.6.3) [Compare Source](https://redirect.github.com/isomorphic-git/lightning-fs/compare/v4.6.2...v4.6.3) ##### Bug Fixes - IDB interface ([#​127](https://redirect.github.com/isomorphic-git/lightning-fs/issues/127)) ([035e472](https://redirect.github.com/isomorphic-git/lightning-fs/commit/035e4725b9e6aa72d10cadc5ace20dec7ac76afb))
vitejs/vite-plugin-react (@​vitejs/plugin-react) ### [`v6.0.5`](https://redirect.github.com/vitejs/vite-plugin-react/blob/HEAD/packages/plugin-react/CHANGELOG.md#605-2026-07-30) [Compare Source](https://redirect.github.com/vitejs/vite-plugin-react/compare/f4b549822ec239799d746c030abb0b9a7d8f0a04...68c0cb8796ce18bd049c3d05c5210eaf0617eac0) ##### Fixed the react compiler preset filter to be linear ([#​1353](https://redirect.github.com/vitejs/vite-plugin-react/pull/1353)) The improved filter in v6.0.3 was non-linear and caused a performance regression ([#​1349](https://redirect.github.com/vitejs/vite-plugin-react/issues/1349)). The filter was changed to be linear to avoid that. ### [`v6.0.4`](https://redirect.github.com/vitejs/vite-plugin-react/blob/HEAD/packages/plugin-react/CHANGELOG.md#604-2026-07-22) [Compare Source](https://redirect.github.com/vitejs/vite-plugin-react/compare/640fd358a0e82393acfce4e92e19a6ac6e1641a7...f4b549822ec239799d746c030abb0b9a7d8f0a04) ##### Fixed `$RefreshSig$ is not defined` error when running `vite dev` with `NODE_ENV=production` When running `vite dev` with `NODE_ENV=production`, the app errored with `$RefreshSig$ is not defined`. This error is now fixed.
dorny/paths-filter (dorny/paths-filter) ### [`v4.0.3`](https://redirect.github.com/dorny/paths-filter/blob/HEAD/CHANGELOG.md#v403) [Compare Source](https://redirect.github.com/dorny/paths-filter/compare/v4.0.2...v4.0.3) - [Document safe handling of file list outputs in workflows](https://redirect.github.com/dorny/paths-filter/pull/326) - [Escape multi-line filenames in list-files shell and csv output](https://redirect.github.com/advisories/GHSA-7hc6-8hq5-9q2m) - [Add 'some-with-excludes' predicate quantifier](https://redirect.github.com/dorny/paths-filter/pull/322) - [Add contents permission to PR example](https://redirect.github.com/dorny/paths-filter/pull/248) - [Scope base-ignored warning to API path](https://redirect.github.com/dorny/paths-filter/pull/319) - [Update outputs in readme to account for the 'every' predicate-quantifier](https://redirect.github.com/dorny/paths-filter/pull/247)
isomorphic-git/isomorphic-git (isomorphic-git) ### [`v1.38.10`](https://redirect.github.com/isomorphic-git/isomorphic-git/releases/tag/v1.38.10) [Compare Source](https://redirect.github.com/isomorphic-git/isomorphic-git/compare/v1.38.9...v1.38.10) ##### Bug Fixes - **statusMatrix:** do not traverse symlinks in GitWalkerFs ([#​1215](https://redirect.github.com/isomorphic-git/isomorphic-git/issues/1215)) ([#​2382](https://redirect.github.com/isomorphic-git/isomorphic-git/issues/2382)) ([90ea101](https://redirect.github.com/isomorphic-git/isomorphic-git/commit/90ea101d329daa84b99cc0140a6275896ebbaf68)) ### [`v1.38.9`](https://redirect.github.com/isomorphic-git/isomorphic-git/releases/tag/v1.38.9) [Compare Source](https://redirect.github.com/isomorphic-git/isomorphic-git/compare/v1.38.8...v1.38.9) ##### Bug Fixes - Preserve binary files when writing conflicted working tree ([#​2380](https://redirect.github.com/isomorphic-git/isomorphic-git/issues/2380)) ([b41b1ab](https://redirect.github.com/isomorphic-git/isomorphic-git/commit/b41b1abc3df87326e639b49d0694915540d6dfb5)) ### [`v1.38.8`](https://redirect.github.com/isomorphic-git/isomorphic-git/releases/tag/v1.38.8) [Compare Source](https://redirect.github.com/isomorphic-git/isomorphic-git/compare/v1.38.7...v1.38.8) ##### Bug Fixes - unsafe symlink from cherry pick ([#​2377](https://redirect.github.com/isomorphic-git/isomorphic-git/issues/2377)) ([4664c8e](https://redirect.github.com/isomorphic-git/isomorphic-git/commit/4664c8e1147c3c7ba87c027e92093d28607ef4c0))
postcss/postcss (postcss) ### [`v8.5.26`](https://redirect.github.com/postcss/postcss/blob/HEAD/CHANGELOG.md#8526) [Compare Source](https://redirect.github.com/postcss/postcss/compare/8.5.25...8.5.26) - Fixed `list.split()` regression (by [@​lazerg](https://redirect.github.com/lazerg)). - Track symlinks in path protection in source map loading (by [@​drengir1](https://redirect.github.com/drengir1)). ### [`v8.5.25`](https://redirect.github.com/postcss/postcss/blob/HEAD/CHANGELOG.md#8525) [Compare Source](https://redirect.github.com/postcss/postcss/compare/8.5.24...8.5.25) - Fixed 8.5.17 visitor regression. - Fixed `list.split()` for non-string values (by [@​amir-rezaei](https://redirect.github.com/amir-rezaei)). ### [`v8.5.24`](https://redirect.github.com/postcss/postcss/blob/HEAD/CHANGELOG.md#8524) [Compare Source](https://redirect.github.com/postcss/postcss/compare/8.5.23...8.5.24) - Preserve the BOM after the processing (by [@​hdimer](https://redirect.github.com/hdimer)). ### [`v8.5.23`](https://redirect.github.com/postcss/postcss/blob/HEAD/CHANGELOG.md#8523) [Compare Source](https://redirect.github.com/postcss/postcss/compare/8.5.22...8.5.23) - Do not load source map without `opts.from` for security reasons. ### [`v8.5.22`](https://redirect.github.com/postcss/postcss/blob/HEAD/CHANGELOG.md#8522) [Compare Source](https://redirect.github.com/postcss/postcss/compare/8.5.21...8.5.22) - Fixed custom property losing semicolon before a comment (by [@​sarathfrancis90](https://redirect.github.com/sarathfrancis90)). ### [`v8.5.21`](https://redirect.github.com/postcss/postcss/blob/HEAD/CHANGELOG.md#8521) [Compare Source](https://redirect.github.com/postcss/postcss/compare/8.5.20...8.5.21) - Fixed childless at-rule losing semicolon before comment (by [@​sarathfrancis90](https://redirect.github.com/sarathfrancis90)). - Fixed docs (by [@​isker](https://redirect.github.com/isker)). ### [`v8.5.20`](https://redirect.github.com/postcss/postcss/blob/HEAD/CHANGELOG.md#8520) [Compare Source](https://redirect.github.com/postcss/postcss/compare/8.5.19...8.5.20) - Fixed missing space if `AtRule#params` is set after (by [@​sarathfrancis90](https://redirect.github.com/sarathfrancis90)). - Fixed mixing AST error on warnings (by [@​MahinAnowar](https://redirect.github.com/MahinAnowar)).
--- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - Between 12:00 AM and 03:59 AM, only on Monday (`* 0-3 * * 1`) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Enabled. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://redirect.github.com/renovatebot/renovate/discussions) if that's undesired. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/block/buzz). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- pnpm-lock.yaml | 51 ++++++++++++++++++++++++++-------------- 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 299fc9efe7..c0a81d86ae 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ jobs: - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: fetch-depth: 2 - - uses: dorny/paths-filter@7b450fff21473bca461d4b92ce414b9d0420d706 # v4.0.2 + - uses: dorny/paths-filter@ceb8a2b8f2d89434be7ff52d3de7ec3738c5cc9d # v4.0.3 id: filter with: token: '' diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2420f4f37f..7dbbc99633 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -28,7 +28,7 @@ importers: dependencies: '@vitejs/plugin-react': specifier: ^6.0.0 - version: 6.0.3(vite@8.0.16(@types/node@25.6.0)(jiti@2.7.0)(yaml@2.9.0)) + version: 6.0.5(vite@8.0.16(@types/node@25.6.0)(jiti@2.7.0)(yaml@2.9.0)) react: specifier: ^19.1.0 version: 19.2.8 @@ -273,7 +273,7 @@ importers: version: 19.2.3(@types/react@19.2.17) '@vitejs/plugin-react': specifier: ^6.0.0 - version: 6.0.3(vite@8.0.16(@types/node@25.6.0)(jiti@2.7.0)(yaml@2.9.0)) + version: 6.0.5(vite@8.0.16(@types/node@25.6.0)(jiti@2.7.0)(yaml@2.9.0)) jsdom: specifier: ^27.4.0 version: 27.4.0(@noble/hashes@2.2.0) @@ -282,7 +282,7 @@ importers: version: 2.23.12(typescript@6.0.3) postcss: specifier: ^8.5.8 - version: 8.5.19 + version: 8.5.26 tailwindcss: specifier: ^4.3.0 version: 4.3.0 @@ -303,7 +303,7 @@ importers: version: 5.2.8 '@isomorphic-git/lightning-fs': specifier: ^4.6.2 - version: 4.6.2 + version: 4.6.3 '@radix-ui/react-slot': specifier: ^1.2.4 version: 1.3.3(@types/react@19.2.17)(react@19.2.8) @@ -330,7 +330,7 @@ importers: version: 2.1.1 isomorphic-git: specifier: ^1.38.3 - version: 1.38.7(patch_hash=e9b414a60d4cf1d8aa18f7a779483984e821989967c235662566e94ef0238d3f) + version: 1.38.10(patch_hash=e9b414a60d4cf1d8aa18f7a779483984e821989967c235662566e94ef0238d3f) lucide-react: specifier: ^1.0.0 version: 1.16.0(react@19.2.8) @@ -376,10 +376,10 @@ importers: version: 19.2.3(@types/react@19.2.17) '@vitejs/plugin-react': specifier: ^6.0.0 - version: 6.0.3(vite@8.0.16(@types/node@25.6.0)(jiti@2.7.0)(yaml@2.9.0)) + version: 6.0.5(vite@8.0.16(@types/node@25.6.0)(jiti@2.7.0)(yaml@2.9.0)) postcss: specifier: ^8.5.8 - version: 8.5.19 + version: 8.5.26 tailwindcss: specifier: ^4.3.0 version: 4.3.0 @@ -675,8 +675,8 @@ packages: '@isomorphic-git/idb-keyval@3.3.2': resolution: {integrity: sha512-r8/AdpiS0/WJCNR/t/gsgL+M8NMVj/ek7s60uz3LmpCaTF2mEVlZJlB01ZzalgYzRLXwSPC92o+pdzjM7PN/pA==} - '@isomorphic-git/lightning-fs@4.6.2': - resolution: {integrity: sha512-RS/oa1UBnoUFe56bsjOEgoUUReYKQzYUlQnbERRRNv9s9KmjyWuuylPV+YgsWirR2oONKaipWYMebVQ8SAe55Q==} + '@isomorphic-git/lightning-fs@4.6.3': + resolution: {integrity: sha512-uIXSSqutetjk+qHlswb5aKTzw7zOJ851R6r53szkkprtZ8Wp4A8gPNf7meeKS7uLDJaFvKhFTY7KISh3ULRojg==} hasBin: true '@jridgewell/gen-mapping@0.3.13': @@ -2109,8 +2109,8 @@ packages: resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} deprecated: Potential CWE-502 - Update to 1.3.1 or higher - '@vitejs/plugin-react@6.0.3': - resolution: {integrity: sha512-vmFvco5/QuC2f9Oj+wTk0+9XeDFkHxSamwZKYc7MxYwKICfvUvlMhqKI0VuICPltGqh1neqBKDvO4kes1ya8vg==} + '@vitejs/plugin-react@6.0.5': + resolution: {integrity: sha512-BOVzne/NL162sMdResB25mUv+vWMF5NoAjNf09TeGlE7ZpszZWSD3winycicLJw72yeVsoCn/2kOhEuCvEShMA==} engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: '@rolldown/plugin-babel': ^0.1.7 || ^0.2.0 @@ -2650,8 +2650,8 @@ packages: resolution: {integrity: sha512-yNeeynhhtIVRBk12tBV4eHNxwB42HzR4Q3Ea7vCOiJhImGaAIdIMrbJtacQlBizGLjUPw+akkFI5Dn9T70XoVQ==} engines: {node: '>=18'} - isomorphic-git@1.38.7: - resolution: {integrity: sha512-2J2rCV7gTgcpscEDT7PjU5shbsKKI10E4RqBlPDI3LmMXDjSKsN2w1jTIKiay14v87sPDfXjJkgp/Rrxc0zlSg==} + isomorphic-git@1.38.10: + resolution: {integrity: sha512-nJSSq7ypu97vM33rSdxXyPzSWksCberjKspzXhFEcBHdVyxdNkWByAzJ/AURV1jIlfv8pLq37lGdIEt7ORj17Q==} engines: {node: '>=14.17'} hasBin: true @@ -3002,6 +3002,11 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + nanoid@3.3.17: + resolution: {integrity: sha512-xQLf0A3HOMlgHq0n247/LRuAOYmB7dXJ/DvAxGvsSBij45XtBSmQycu+F8ODbHwns/XyFZagyL1+J0Offw1E0g==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + node-releases@2.0.46: resolution: {integrity: sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ==} engines: {node: '>=18'} @@ -3102,6 +3107,10 @@ packages: resolution: {integrity: sha512-Mz8SaolMd8nB+G13WkORcxQKHZ/NE4xXevtkJHVuG+guo9/wYKlIMTKAqGdEmYOXR2ijPjTYNHssizdaVSUNdQ==} engines: {node: ^10 || ^12 || >=14} + postcss@8.5.26: + resolution: {integrity: sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==} + engines: {node: ^10 || ^12 || >=14} + prettier@3.8.3: resolution: {integrity: sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==} engines: {node: '>=14'} @@ -4004,7 +4013,7 @@ snapshots: '@isomorphic-git/idb-keyval@3.3.2': {} - '@isomorphic-git/lightning-fs@4.6.2': + '@isomorphic-git/lightning-fs@4.6.3': dependencies: '@isomorphic-git/idb-keyval': 3.3.2 isomorphic-textencoder: 1.0.1 @@ -4907,7 +4916,7 @@ snapshots: '@alloc/quick-lru': 5.2.0 '@tailwindcss/node': 4.3.0 '@tailwindcss/oxide': 4.3.0 - postcss: 8.5.19 + postcss: 8.5.26 tailwindcss: 4.3.0 '@tailwindcss/typography@0.5.20(tailwindcss@4.3.0)': @@ -5349,7 +5358,7 @@ snapshots: '@ungap/structured-clone@1.3.0': {} - '@vitejs/plugin-react@6.0.3(vite@8.0.16(@types/node@25.6.0)(jiti@2.7.0)(yaml@2.9.0))': + '@vitejs/plugin-react@6.0.5(vite@8.0.16(@types/node@25.6.0)(jiti@2.7.0)(yaml@2.9.0))': dependencies: '@rolldown/pluginutils': 1.0.1 vite: 8.0.16(@types/node@25.6.0)(jiti@2.7.0)(yaml@2.9.0) @@ -5843,7 +5852,7 @@ snapshots: isbot@5.1.40: {} - isomorphic-git@1.38.7(patch_hash=e9b414a60d4cf1d8aa18f7a779483984e821989967c235662566e94ef0238d3f): + isomorphic-git@1.38.10(patch_hash=e9b414a60d4cf1d8aa18f7a779483984e821989967c235662566e94ef0238d3f): dependencies: async-lock: 1.4.1 clean-git-ref: 2.0.1 @@ -6384,6 +6393,8 @@ snapshots: nanoid@3.3.16: {} + nanoid@3.3.17: {} + node-releases@2.0.46: {} nostr-tools@2.23.12(typescript@6.0.3): @@ -6477,6 +6488,12 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + postcss@8.5.26: + dependencies: + nanoid: 3.3.17 + picocolors: 1.1.1 + source-map-js: 1.2.1 + prettier@3.8.3: {} pretty-format@27.5.1: From c923e89a4b6d43ae0c507dbb5e58f2bdd9ab7888 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 9 Aug 2026 09:11:47 -0700 Subject: [PATCH 16/18] chore(deps): update dependency @tanstack/react-virtual to v3.14.9 (#4439) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [@tanstack/react-virtual](https://tanstack.com/virtual) ([source](https://redirect.github.com/TanStack/virtual/tree/HEAD/packages/react-virtual)) | [`3.14.8` → `3.14.9`](https://renovatebot.com/diffs/npm/@tanstack%2freact-virtual/3.14.8/3.14.9) | ![age](https://developer.mend.io/api/mc/badges/age/npm/@tanstack%2freact-virtual/3.14.9?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@tanstack%2freact-virtual/3.14.8/3.14.9?slim=true) | --- > [!WARNING] > Some dependencies could not be looked up. Check the [Dependency Dashboard](../issues/1) for more information. --- ### Release Notes
TanStack/virtual (@​tanstack/react-virtual) ### [`v3.14.9`](https://redirect.github.com/TanStack/virtual/blob/HEAD/packages/react-virtual/CHANGELOG.md#3149) [Compare Source](https://redirect.github.com/TanStack/virtual/compare/@tanstack/react-virtual@3.14.8...@tanstack/react-virtual@3.14.9) ##### Patch Changes - Updated dependencies \[[`a5417b4`](https://redirect.github.com/TanStack/virtual/commit/a5417b4b0d3c82876747bb9635db7239c28d3e44)]: - [@​tanstack/virtual-core](https://redirect.github.com/tanstack/virtual-core)@​3.17.7
--- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - Between 12:00 AM and 03:59 AM, only on Monday (`* 0-3 * * 1`) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Enabled. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://redirect.github.com/renovatebot/renovate/discussions) if that's undesired. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/block/buzz). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- pnpm-lock.yaml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7dbbc99633..db22d8e2bd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -140,7 +140,7 @@ importers: version: 1.170.7(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@tanstack/react-virtual': specifier: ^3.14.2 - version: 3.14.8(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 3.14.9(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@tauri-apps/api': specifier: ~2.11 version: 2.11.0 @@ -1720,8 +1720,8 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@tanstack/react-virtual@3.14.8': - resolution: {integrity: sha512-O39GJQpAYEJcIu3uN1//YtmhjSEOyw75vg9CKCatBDPiD5hKtZQoJHfferyrB/LdOD3UWaoMLWtdEjarwIwdDw==} + '@tanstack/react-virtual@3.14.9': + resolution: {integrity: sha512-qZyr0FZDP8rDC4WBhsryIZmAd9bveJvFGUJJtskWaew6/0dTRS6wZxnR6VQ5bY2KwL3LjerrHqQLk3a0GKcPXQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -1762,8 +1762,8 @@ packages: '@tanstack/store@0.9.3': resolution: {integrity: sha512-8reSzl/qGWGGVKhBoxXPMWzATSbZLZFWhwBAFO9NAyp0TxzfBP0mIrGb8CP8KrQTmvzXlR/vFPPUrHTLBGyFyw==} - '@tanstack/virtual-core@3.17.6': - resolution: {integrity: sha512-h0/Ebo18CkOrChlQIhNtQkM5ySUnh/GumQ/D1st3hG2HWUPEF+ILUc2k29UtivCi/9G7w7G3/f7Xyd5cCFbKBw==} + '@tanstack/virtual-core@3.17.7': + resolution: {integrity: sha512-bp+v10y65sp2H7WpWfIMyxTNfl8ZVfxFTLRjPIFRryi6FV/J33z4IS53WO4pTk36KlvJ4iLiQz+oaydDC1xbcA==} '@tanstack/virtual-file-routes@1.162.0': resolution: {integrity: sha512-uhOeFyxLcU41HzvrxsGpiWdcMbScY1EDgbZ5K7DVRMYInbLYWAC0EA/kx9wXAoSM8q82bUG2hRl8+EAjE6XAbA==} @@ -4949,9 +4949,9 @@ snapshots: react-dom: 19.2.8(react@19.2.8) use-sync-external-store: 1.6.0(react@19.2.8) - '@tanstack/react-virtual@3.14.8(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@tanstack/react-virtual@3.14.9(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@tanstack/virtual-core': 3.17.6 + '@tanstack/virtual-core': 3.17.7 react: 19.2.8 react-dom: 19.2.8(react@19.2.8) @@ -5012,7 +5012,7 @@ snapshots: '@tanstack/store@0.9.3': {} - '@tanstack/virtual-core@3.17.6': {} + '@tanstack/virtual-core@3.17.7': {} '@tanstack/virtual-file-routes@1.162.0': {} From d2ebaa95a7d2565fb217fdfae56bafb9509be444 Mon Sep 17 00:00:00 2001 From: Wes Date: Sun, 9 Aug 2026 10:39:21 -0600 Subject: [PATCH 17/18] ci(security): allow retired relay pool advisory (#5404) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - temporarily allow the informational `RUSTSEC-2026-0243` advisory for the retired `nostr-relay-pool` crate - document the exact MeshLLM → `nostr-sdk 0.44.1` transitive path and removal condition - keep every other advisory and the global dependency policy enforced ## Why an exception RustSec provides no patched `nostr-relay-pool` release because the standalone crate was absorbed into `nostr-sdk >= 0.45`. Buzz inherits it through pinned MeshLLM v0.74. A direct test bump to `nostr-sdk 0.45.1` removed the retired crate but produced 13 MeshLLM API compilation errors, so the durable fix requires an upstream source migration rather than a lockfile update. This narrow exception restores the required Security check while that migration is completed. It must be removed once MeshLLM adopts `nostr-sdk >= 0.45`. ## Validation - `bin/cargo-deny --locked check --config deny.toml advisories` - `bin/cargo-deny --locked check` - `git diff --check origin/main...HEAD` - mandatory pre-push Rust and desktop/Tauri checks ## Scope One four-line `deny.toml` addition. No Rust source, lockfile, runtime, or release behavior changes. Signed-off-by: Wes Co-authored-by: Carl --- deny.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/deny.toml b/deny.toml index d3c5fcd4bc..c432a20ea4 100644 --- a/deny.toml +++ b/deny.toml @@ -15,6 +15,10 @@ ignore = [ # remove these when upstream catches up. { id = "RUSTSEC-2026-0194", reason = "transitive via rust-s3 and mesh-llm→plist; trusted-input XML only; no upstream fix available yet" }, { id = "RUSTSEC-2026-0195", reason = "transitive via rust-s3 and mesh-llm→plist; trusted-input XML only; no upstream fix available yet" }, + # nostr-relay-pool 0.44.3 — informational/unmaintained, not a vulnerability. + # Transitive via mesh-llm 0.74 → nostr-sdk 0.44.1. Remove after mesh-llm + # migrates to nostr-sdk >= 0.45, which absorbed the standalone relay pool. + { id = "RUSTSEC-2026-0243", reason = "transitive via mesh-llm; upstream nostr-sdk 0.45 migration requires API changes" }, ] [licenses] From 119a84897f225c1e3213a09cd149abb37dcb3abc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 9 Aug 2026 09:52:17 -0700 Subject: [PATCH 18/18] chore(deps): update react monorepo (#4441) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [@types/react](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/react) ([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react)) | [`19.2.17` → `19.2.18`](https://renovatebot.com/diffs/npm/@types%2freact/19.2.17/19.2.18) | ![age](https://developer.mend.io/api/mc/badges/age/npm/@types%2freact/19.2.18?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@types%2freact/19.2.17/19.2.18?slim=true) | | [@types/react-dom](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/react-dom) ([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom)) | [`19.2.3` → `19.2.4`](https://renovatebot.com/diffs/npm/@types%2freact-dom/19.2.3/19.2.4) | ![age](https://developer.mend.io/api/mc/badges/age/npm/@types%2freact-dom/19.2.4?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@types%2freact-dom/19.2.3/19.2.4?slim=true) | --- > [!WARNING] > Some dependencies could not be looked up. Check the [Dependency Dashboard](../issues/1) for more information. --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - Between 12:00 AM and 03:59 AM, only on Monday (`* 0-3 * * 1`) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Enabled. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://redirect.github.com/renovatebot/renovate/discussions) if that's undesired. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/block/buzz). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Wes --- pnpm-lock.yaml | 820 ++++++++++++++++++++++++------------------------- 1 file changed, 410 insertions(+), 410 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index db22d8e2bd..78a39628dc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -47,13 +47,13 @@ importers: version: 6.9.1 '@testing-library/react': specifier: ^16.3.2 - version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@types/react': specifier: ^19.1.8 - version: 19.2.17 + version: 19.2.18 '@types/react-dom': specifier: ^19.1.6 - version: 19.2.3(@types/react@19.2.17) + version: 19.2.4(@types/react@19.2.18) jsdom: specifier: ^27.3.0 version: 27.4.0(@noble/hashes@2.2.0) @@ -92,46 +92,46 @@ importers: version: 0.10.35 '@radix-ui/react-alert-dialog': specifier: ^1.1.15 - version: 1.1.23(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 1.1.23(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-avatar': specifier: ^1.1.11 - version: 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 1.1.12(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-checkbox': specifier: ^1.3.3 - version: 1.3.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 1.3.11(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-context-menu': specifier: ^2.2.16 - version: 2.2.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 2.2.16(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-dialog': specifier: ^1.1.15 - version: 1.1.23(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 1.1.23(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-dropdown-menu': specifier: ^2.1.16 - version: 2.1.24(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 2.1.24(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-focus-scope': specifier: ^1.1.8 - version: 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 1.1.16(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-popover': specifier: ^1.1.15 - version: 1.1.23(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 1.1.23(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-separator': specifier: ^1.1.8 - version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 1.1.15(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-slot': specifier: ^1.2.4 - version: 1.3.3(@types/react@19.2.17)(react@19.2.8) + version: 1.3.3(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-switch': specifier: ^1.2.6 - version: 1.2.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 1.2.6(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-tabs': specifier: ^1.1.13 - version: 1.1.21(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 1.1.21(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-toggle': specifier: ^1.1.10 - version: 1.1.18(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 1.1.18(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@radix-ui/react-tooltip': specifier: ^1.2.8 - version: 1.2.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 1.2.16(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@tanstack/react-query': specifier: ^5.90.21 version: 5.100.14(react@19.2.8) @@ -170,7 +170,7 @@ importers: version: 3.22.5 '@tiptap/react': specifier: ^3.22.3 - version: 3.22.5(@floating-ui/dom@1.8.0)(@tiptap/core@3.22.5(@tiptap/pm@3.22.5))(@tiptap/pm@3.22.5)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 3.22.5(@floating-ui/dom@1.8.0)(@tiptap/core@3.22.5(@tiptap/pm@3.22.5))(@tiptap/pm@3.22.5)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@tiptap/starter-kit': specifier: ^3.22.3 version: 3.22.5 @@ -212,7 +212,7 @@ importers: version: 19.2.8(react@19.2.8) react-markdown: specifier: ^10.1.0 - version: 10.1.0(@types/react@19.2.17)(react@19.2.8) + version: 10.1.0(@types/react@19.2.18)(react@19.2.8) remark-breaks: specifier: ^4.0.0 version: 4.0.0 @@ -264,13 +264,13 @@ importers: version: 2.11.4 '@testing-library/react': specifier: ^16.3.2 - version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@types/react': specifier: ^19.1.8 - version: 19.2.17 + version: 19.2.18 '@types/react-dom': specifier: ^19.1.6 - version: 19.2.3(@types/react@19.2.17) + version: 19.2.4(@types/react@19.2.18) '@vitejs/plugin-react': specifier: ^6.0.0 version: 6.0.5(vite@8.0.16(@types/node@25.6.0)(jiti@2.7.0)(yaml@2.9.0)) @@ -306,10 +306,10 @@ importers: version: 4.6.3 '@radix-ui/react-slot': specifier: ^1.2.4 - version: 1.3.3(@types/react@19.2.17)(react@19.2.8) + version: 1.3.3(@types/react@19.2.18)(react@19.2.8) '@radix-ui/react-tooltip': specifier: ^1.2.8 - version: 1.2.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 1.2.16(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@tailwindcss/typography': specifier: ^0.5.19 version: 0.5.20(tailwindcss@4.3.0) @@ -345,7 +345,7 @@ importers: version: 19.2.8(react@19.2.8) react-markdown: specifier: ^10.1.0 - version: 10.1.0(@types/react@19.2.17)(react@19.2.8) + version: 10.1.0(@types/react@19.2.18)(react@19.2.8) remark-gfm: specifier: ^4.0.1 version: 4.0.1 @@ -370,10 +370,10 @@ importers: version: 1.162.0 '@types/react': specifier: ^19.1.8 - version: 19.2.17 + version: 19.2.18 '@types/react-dom': specifier: ^19.1.6 - version: 19.2.3(@types/react@19.2.17) + version: 19.2.4(@types/react@19.2.18) '@vitejs/plugin-react': specifier: ^6.0.0 version: 6.0.5(vite@8.0.16(@types/node@25.6.0)(jiti@2.7.0)(yaml@2.9.0)) @@ -2088,13 +2088,13 @@ packages: '@types/node@25.6.0': resolution: {integrity: sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==} - '@types/react-dom@19.2.3': - resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} + '@types/react-dom@19.2.4': + resolution: {integrity: sha512-Bsc+QHgp+P/F02XDzNCY9jnZNCUuLki36KT7VKrTXXLdHf+vHMNZnW1rVu5DNW/rCK+fya3DATySbLM4yhtKUw==} peerDependencies: '@types/react': ^19.2.0 - '@types/react@19.2.17': - resolution: {integrity: sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==} + '@types/react@19.2.18': + resolution: {integrity: sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==} '@types/unist@2.0.11': resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} @@ -4068,677 +4068,677 @@ snapshots: '@radix-ui/primitive@1.1.7': {} - '@radix-ui/react-alert-dialog@1.1.23(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-alert-dialog@1.1.23(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 - '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-context': 1.2.2(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-dialog': 1.1.23(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-dialog': 1.1.23(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) - '@radix-ui/react-arrow@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-arrow@1.1.15(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) - '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) - '@radix-ui/react-avatar@1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-avatar@1.1.12(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-primitive': 2.1.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-use-is-hydrated': 0.1.1(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.5(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-use-is-hydrated': 0.1.1(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) - '@radix-ui/react-checkbox@1.3.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-checkbox@1.3.11(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 - '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-context': 1.2.2(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-use-size': 1.1.4(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-use-size': 1.1.4(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) - '@radix-ui/react-collection@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-collection@1.1.15(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-context': 1.2.2(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-slot': 1.3.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-slot': 1.3.3(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) - '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) - '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.17)(react@19.2.8)': + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.18)(react@19.2.8)': dependencies: react: 19.2.8 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - '@radix-ui/react-compose-refs@1.1.3(@types/react@19.2.17)(react@19.2.8)': + '@radix-ui/react-compose-refs@1.1.3(@types/react@19.2.18)(react@19.2.8)': dependencies: react: 19.2.8 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - '@radix-ui/react-compose-refs@1.1.5(@types/react@19.2.17)(react@19.2.8)': + '@radix-ui/react-compose-refs@1.1.5(@types/react@19.2.18)(react@19.2.8)': dependencies: react: 19.2.8 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - '@radix-ui/react-context-menu@2.2.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-context-menu@2.2.16(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) - '@radix-ui/react-context@1.1.2(@types/react@19.2.17)(react@19.2.8)': + '@radix-ui/react-context@1.1.2(@types/react@19.2.18)(react@19.2.8)': dependencies: react: 19.2.8 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - '@radix-ui/react-context@1.1.4(@types/react@19.2.17)(react@19.2.8)': + '@radix-ui/react-context@1.1.4(@types/react@19.2.18)(react@19.2.8)': dependencies: react: 19.2.8 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - '@radix-ui/react-context@1.2.2(@types/react@19.2.17)(react@19.2.8)': + '@radix-ui/react-context@1.2.2(@types/react@19.2.18)(react@19.2.8)': dependencies: react: 19.2.8 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - '@radix-ui/react-dialog@1.1.23(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-dialog@1.1.23(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 - '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-context': 1.2.2(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-focus-guards': 1.1.6(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-focus-scope': 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-id': 1.1.4(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-slot': 1.3.3(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-focus-guards': 1.1.6(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-focus-scope': 1.1.16(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-id': 1.1.4(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-slot': 1.3.3(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.18)(react@19.2.8) aria-hidden: 1.2.6 react: 19.2.8 react-dom: 19.2.8(react@19.2.8) - react-remove-scroll: 2.7.2(@types/react@19.2.17)(react@19.2.8) + react-remove-scroll: 2.7.2(@types/react@19.2.18)(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) - '@radix-ui/react-direction@1.1.1(@types/react@19.2.17)(react@19.2.8)': + '@radix-ui/react-direction@1.1.1(@types/react@19.2.18)(react@19.2.8)': dependencies: react: 19.2.8 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - '@radix-ui/react-direction@1.1.4(@types/react@19.2.17)(react@19.2.8)': + '@radix-ui/react-direction@1.1.4(@types/react@19.2.18)(react@19.2.8)': dependencies: react: 19.2.8 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - '@radix-ui/react-dismissable-layer@1.1.19(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-dismissable-layer@1.1.19(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 - '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-use-effect-event': 0.0.5(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-use-effect-event': 0.0.5(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) - '@radix-ui/react-dropdown-menu@2.1.24(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-dropdown-menu@2.1.24(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 - '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-context': 1.2.2(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-id': 1.1.4(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-menu': 2.1.24(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-id': 1.1.4(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-menu': 2.1.24(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) - '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.17)(react@19.2.8)': + '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.18)(react@19.2.8)': dependencies: react: 19.2.8 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - '@radix-ui/react-focus-guards@1.1.6(@types/react@19.2.17)(react@19.2.8)': + '@radix-ui/react-focus-guards@1.1.6(@types/react@19.2.18)(react@19.2.8)': dependencies: react: 19.2.8 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - '@radix-ui/react-focus-scope@1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-focus-scope@1.1.16(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) - '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) - '@radix-ui/react-id@1.1.1(@types/react@19.2.17)(react@19.2.8)': + '@radix-ui/react-id@1.1.1(@types/react@19.2.18)(react@19.2.8)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - '@radix-ui/react-id@1.1.4(@types/react@19.2.17)(react@19.2.8)': + '@radix-ui/react-id@1.1.4(@types/react@19.2.18)(react@19.2.8)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - '@radix-ui/react-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-menu@2.1.16(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.18)(react@19.2.8) aria-hidden: 1.2.6 react: 19.2.8 react-dom: 19.2.8(react@19.2.8) - react-remove-scroll: 2.7.2(@types/react@19.2.17)(react@19.2.8) + react-remove-scroll: 2.7.2(@types/react@19.2.18)(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) - '@radix-ui/react-menu@2.1.24(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-menu@2.1.24(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 - '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-context': 1.2.2(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-direction': 1.1.4(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-focus-guards': 1.1.6(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-focus-scope': 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-id': 1.1.4(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-popper': 1.3.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-roving-focus': 1.1.19(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-slot': 1.3.3(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-direction': 1.1.4(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-focus-guards': 1.1.6(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-focus-scope': 1.1.16(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-id': 1.1.4(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-popper': 1.3.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-roving-focus': 1.1.19(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-slot': 1.3.3(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.2.18)(react@19.2.8) aria-hidden: 1.2.6 react: 19.2.8 react-dom: 19.2.8(react@19.2.8) - react-remove-scroll: 2.7.2(@types/react@19.2.17)(react@19.2.8) + react-remove-scroll: 2.7.2(@types/react@19.2.18)(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) - '@radix-ui/react-popover@1.1.23(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-popover@1.1.23(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 - '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-context': 1.2.2(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-focus-guards': 1.1.6(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-focus-scope': 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-id': 1.1.4(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-popper': 1.3.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-slot': 1.3.3(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-focus-guards': 1.1.6(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-focus-scope': 1.1.16(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-id': 1.1.4(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-popper': 1.3.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-slot': 1.3.3(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.18)(react@19.2.8) aria-hidden: 1.2.6 react: 19.2.8 react-dom: 19.2.8(react@19.2.8) - react-remove-scroll: 2.7.2(@types/react@19.2.17)(react@19.2.8) + react-remove-scroll: 2.7.2(@types/react@19.2.18)(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) - '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@floating-ui/react-dom': 2.1.9(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.18)(react@19.2.8) '@radix-ui/rect': 1.1.1 react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) - '@radix-ui/react-popper@1.3.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-popper@1.3.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@floating-ui/react-dom': 2.1.9(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-arrow': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-context': 1.2.2(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-use-rect': 1.1.4(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-use-size': 1.1.4(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-arrow': 1.1.15(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-use-rect': 1.1.4(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-use-size': 1.1.4(@types/react@19.2.18)(react@19.2.8) '@radix-ui/rect': 1.1.3 react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) - '@radix-ui/react-portal@1.1.17(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-portal@1.1.17(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) - '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) - '@radix-ui/react-presence@1.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-presence@1.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) - '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) - '@radix-ui/react-primitive@2.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-primitive@2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-slot': 1.3.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-slot': 1.3.3(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) - '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) - '@radix-ui/react-primitive@2.1.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-primitive@2.1.5(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-slot': 1.2.5(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-slot': 1.2.5(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) - '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) - '@radix-ui/react-roving-focus@1.1.19(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-roving-focus@1.1.19(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 - '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-context': 1.2.2(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-direction': 1.1.4(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-id': 1.1.4(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-use-is-hydrated': 0.1.3(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-direction': 1.1.4(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-id': 1.1.4(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-use-is-hydrated': 0.1.3(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) - '@radix-ui/react-separator@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-separator@1.1.15(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) - '@radix-ui/react-slot@1.2.3(@types/react@19.2.17)(react@19.2.8)': + '@radix-ui/react-slot@1.2.3(@types/react@19.2.18)(react@19.2.8)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - '@radix-ui/react-slot@1.2.5(@types/react@19.2.17)(react@19.2.8)': + '@radix-ui/react-slot@1.2.5(@types/react@19.2.18)(react@19.2.8)': dependencies: - '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - '@radix-ui/react-slot@1.3.3(@types/react@19.2.17)(react@19.2.8)': + '@radix-ui/react-slot@1.3.3(@types/react@19.2.18)(react@19.2.8)': dependencies: - '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - '@radix-ui/react-switch@1.2.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-switch@1.2.6(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) - '@radix-ui/react-tabs@1.1.21(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-tabs@1.1.21(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 - '@radix-ui/react-context': 1.2.2(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-direction': 1.1.4(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-id': 1.1.4(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-roving-focus': 1.1.19(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-direction': 1.1.4(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-id': 1.1.4(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-roving-focus': 1.1.19(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) - '@radix-ui/react-toggle@1.1.18(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-toggle@1.1.18(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) - '@radix-ui/react-tooltip@1.2.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-tooltip@1.2.16(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 - '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-context': 1.2.2(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-id': 1.1.4(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-popper': 1.3.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@radix-ui/react-slot': 1.3.3(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-visually-hidden': 1.2.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-context': 1.2.2(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-id': 1.1.4(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-popper': 1.3.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-slot': 1.3.3(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-visually-hidden': 1.2.11(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) - '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.17)(react@19.2.8)': + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.18)(react@19.2.8)': dependencies: react: 19.2.8 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - '@radix-ui/react-use-callback-ref@1.1.2(@types/react@19.2.17)(react@19.2.8)': + '@radix-ui/react-use-callback-ref@1.1.2(@types/react@19.2.18)(react@19.2.8)': dependencies: react: 19.2.8 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - '@radix-ui/react-use-callback-ref@1.1.4(@types/react@19.2.17)(react@19.2.8)': + '@radix-ui/react-use-callback-ref@1.1.4(@types/react@19.2.18)(react@19.2.8)': dependencies: react: 19.2.8 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.17)(react@19.2.8)': + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.18)(react@19.2.8)': dependencies: - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - '@radix-ui/react-use-controllable-state@1.2.6(@types/react@19.2.17)(react@19.2.8)': + '@radix-ui/react-use-controllable-state@1.2.6(@types/react@19.2.18)(react@19.2.8)': dependencies: '@radix-ui/primitive': 1.1.7 - '@radix-ui/react-use-effect-event': 0.0.5(@types/react@19.2.17)(react@19.2.8) - '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-effect-event': 0.0.5(@types/react@19.2.18)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.17)(react@19.2.8)': + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.18)(react@19.2.8)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - '@radix-ui/react-use-effect-event@0.0.5(@types/react@19.2.17)(react@19.2.8)': + '@radix-ui/react-use-effect-event@0.0.5(@types/react@19.2.18)(react@19.2.8)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - '@radix-ui/react-use-is-hydrated@0.1.1(@types/react@19.2.17)(react@19.2.8)': + '@radix-ui/react-use-is-hydrated@0.1.1(@types/react@19.2.18)(react@19.2.8)': dependencies: react: 19.2.8 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - '@radix-ui/react-use-is-hydrated@0.1.3(@types/react@19.2.17)(react@19.2.8)': + '@radix-ui/react-use-is-hydrated@0.1.3(@types/react@19.2.18)(react@19.2.8)': dependencies: react: 19.2.8 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.17)(react@19.2.8)': + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.18)(react@19.2.8)': dependencies: react: 19.2.8 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - '@radix-ui/react-use-layout-effect@1.1.2(@types/react@19.2.17)(react@19.2.8)': + '@radix-ui/react-use-layout-effect@1.1.2(@types/react@19.2.18)(react@19.2.8)': dependencies: react: 19.2.8 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - '@radix-ui/react-use-layout-effect@1.1.4(@types/react@19.2.17)(react@19.2.8)': + '@radix-ui/react-use-layout-effect@1.1.4(@types/react@19.2.18)(react@19.2.8)': dependencies: react: 19.2.8 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - '@radix-ui/react-use-previous@1.1.1(@types/react@19.2.17)(react@19.2.8)': + '@radix-ui/react-use-previous@1.1.1(@types/react@19.2.18)(react@19.2.8)': dependencies: react: 19.2.8 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.17)(react@19.2.8)': + '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.18)(react@19.2.8)': dependencies: '@radix-ui/rect': 1.1.1 react: 19.2.8 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - '@radix-ui/react-use-rect@1.1.4(@types/react@19.2.17)(react@19.2.8)': + '@radix-ui/react-use-rect@1.1.4(@types/react@19.2.18)(react@19.2.8)': dependencies: '@radix-ui/rect': 1.1.3 react: 19.2.8 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - '@radix-ui/react-use-size@1.1.1(@types/react@19.2.17)(react@19.2.8)': + '@radix-ui/react-use-size@1.1.1(@types/react@19.2.18)(react@19.2.8)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - '@radix-ui/react-use-size@1.1.4(@types/react@19.2.17)(react@19.2.8)': + '@radix-ui/react-use-size@1.1.4(@types/react@19.2.18)(react@19.2.8)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.17)(react@19.2.8) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.18)(react@19.2.8) react: 19.2.8 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - '@radix-ui/react-visually-hidden@1.2.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@radix-ui/react-visually-hidden@1.2.11(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) '@radix-ui/rect@1.1.1': {} @@ -5101,15 +5101,15 @@ snapshots: picocolors: 1.1.1 redent: 3.0.0 - '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@babel/runtime': 7.29.7 '@testing-library/dom': 10.4.1 react: 19.2.8 react-dom: 19.2.8(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) '@tiptap/core@3.22.5(@tiptap/pm@3.22.5)': dependencies: @@ -5242,12 +5242,12 @@ snapshots: prosemirror-transform: 1.12.0 prosemirror-view: 1.41.8 - '@tiptap/react@3.22.5(@floating-ui/dom@1.8.0)(@tiptap/core@3.22.5(@tiptap/pm@3.22.5))(@tiptap/pm@3.22.5)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@tiptap/react@3.22.5(@floating-ui/dom@1.8.0)(@tiptap/core@3.22.5(@tiptap/pm@3.22.5))(@tiptap/pm@3.22.5)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: '@tiptap/core': 3.22.5(@tiptap/pm@3.22.5) '@tiptap/pm': 3.22.5 - '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) '@types/use-sync-external-store': 0.0.6 fast-equals: 5.4.0 react: 19.2.8 @@ -5342,11 +5342,11 @@ snapshots: dependencies: undici-types: 7.19.2 - '@types/react-dom@19.2.3(@types/react@19.2.17)': + '@types/react-dom@19.2.4(@types/react@19.2.18)': dependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - '@types/react@19.2.17': + '@types/react@19.2.18': dependencies: csstype: 3.2.3 @@ -6612,11 +6612,11 @@ snapshots: react-is@17.0.2: {} - react-markdown@10.1.0(@types/react@19.2.17)(react@19.2.8): + react-markdown@10.1.0(@types/react@19.2.18)(react@19.2.8): dependencies: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 - '@types/react': 19.2.17 + '@types/react': 19.2.18 devlop: 1.1.0 hast-util-to-jsx-runtime: 2.3.6 html-url-attributes: 3.0.1 @@ -6630,32 +6630,32 @@ snapshots: transitivePeerDependencies: - supports-color - react-remove-scroll-bar@2.3.8(@types/react@19.2.17)(react@19.2.8): + react-remove-scroll-bar@2.3.8(@types/react@19.2.18)(react@19.2.8): dependencies: react: 19.2.8 - react-style-singleton: 2.2.3(@types/react@19.2.17)(react@19.2.8) + react-style-singleton: 2.2.3(@types/react@19.2.18)(react@19.2.8) tslib: 2.8.1 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - react-remove-scroll@2.7.2(@types/react@19.2.17)(react@19.2.8): + react-remove-scroll@2.7.2(@types/react@19.2.18)(react@19.2.8): dependencies: react: 19.2.8 - react-remove-scroll-bar: 2.3.8(@types/react@19.2.17)(react@19.2.8) - react-style-singleton: 2.2.3(@types/react@19.2.17)(react@19.2.8) + react-remove-scroll-bar: 2.3.8(@types/react@19.2.18)(react@19.2.8) + react-style-singleton: 2.2.3(@types/react@19.2.18)(react@19.2.8) tslib: 2.8.1 - use-callback-ref: 1.3.3(@types/react@19.2.17)(react@19.2.8) - use-sidecar: 1.1.3(@types/react@19.2.17)(react@19.2.8) + use-callback-ref: 1.3.3(@types/react@19.2.18)(react@19.2.8) + use-sidecar: 1.1.3(@types/react@19.2.18)(react@19.2.8) optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - react-style-singleton@2.2.3(@types/react@19.2.17)(react@19.2.8): + react-style-singleton@2.2.3(@types/react@19.2.18)(react@19.2.8): dependencies: get-nonce: 1.0.1 react: 19.2.8 tslib: 2.8.1 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 react@19.2.8: {} @@ -6974,20 +6974,20 @@ snapshots: dependencies: pako: 1.0.11 - use-callback-ref@1.3.3(@types/react@19.2.17)(react@19.2.8): + use-callback-ref@1.3.3(@types/react@19.2.18)(react@19.2.8): dependencies: react: 19.2.8 tslib: 2.8.1 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 - use-sidecar@1.1.3(@types/react@19.2.17)(react@19.2.8): + use-sidecar@1.1.3(@types/react@19.2.18)(react@19.2.8): dependencies: detect-node-es: 1.1.0 react: 19.2.8 tslib: 2.8.1 optionalDependencies: - '@types/react': 19.2.17 + '@types/react': 19.2.18 use-sync-external-store@1.6.0(react@19.2.8): dependencies: