release: v0.8.48 — liveness watchdog fix, Qwen 3.7 removal, provider/docs sync

- Fix false 'Turn stalled' during long active turns with running tools.
  Add turn_last_activity_at tracking and active-tool awareness to
  reconcile_turn_liveness(). Three new tests cover the fix.

- Remove Qwen 3.7 Max OpenRouter preset from registry, picker, docs,
  and tests. Qwen 3.7 Max is a hosted model; the preset will return
  when an open-weight Qwen 3.7 release ships. MiniMax M3 remains as
  a full 1M-context multimodal route.

- Sync root CHANGELOG to crates/tui/CHANGELOG for crates.io packaging.
  Update docs/CONFIGURATION.md, docs/PROVIDERS.md, and README to
  reflect the Qwen 3.7 removal. Regenerate web facts timestamp.
This commit is contained in:
Hunter B
2026-05-31 21:45:31 -07:00
parent 2bd77edc15
commit e9eea70445
18 changed files with 140 additions and 609 deletions
+8 -2
View File
@@ -12,8 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- **Recent large OpenRouter model presets.** Added completions, aliases,
routing metadata, and docs for Arcee Trinity Large Thinking, Qwen 3.7
Max, Xiaomi MiMo v2.5, Qwen 3.6 open-weight models, Kimi K2.6,
routing metadata, and docs for Arcee Trinity Large Thinking,
MiniMax M3, Xiaomi MiMo v2.5, Qwen 3.6 open-weight models, Kimi K2.6,
GLM 5.1, Tencent Hy3, Gemma 4, and Nemotron (#2461).
- **Provider and web-search expansion.** Added Xiaomi MiMo provider support,
SiliconFlow, AtlasCloud static models, Volcengine Ark search, Baidu AI
@@ -34,6 +34,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
event envelopes, task migration/env isolation fixes, and state-message
parent IDs for future forks (#2383, #2358, #2367, #2252, #2272, #2308).
### Removed
- **Qwen 3.7 Max OpenRouter preset.** Removed from the model registry, docs,
and examples. Qwen 3.7 Max is a hosted model, not open-source; the preset
will return when an open-weight Qwen 3.7 release ships.
### Changed
- **Release hardening.** CI now runs clippy/docs checks, web frontend lint and
-1
View File
@@ -316,7 +316,6 @@ codewhale --provider wanjie-ark --model deepseek-reasoner
codewhale auth set --provider openrouter --api-key "YOUR_OPENROUTER_API_KEY"
codewhale --provider openrouter --model deepseek/deepseek-v4-pro
codewhale --provider openrouter --model arcee-ai/trinity-large-thinking
codewhale --provider openrouter --model qwen/qwen3.7-max
codewhale --provider openrouter --model minimax/minimax-m3
# Xiaomi MiMo
-15
View File
@@ -197,19 +197,6 @@ impl Default for ModelRegistry {
supports_tools: true,
supports_reasoning: true,
},
ModelInfo {
id: "qwen/qwen3.7-max".to_string(),
provider: ProviderKind::Openrouter,
aliases: vec![
"qwen3.7".to_string(),
"qwen-3.7".to_string(),
"qwen3-7".to_string(),
"qwen3.7-max".to_string(),
"qwen-3.7-max".to_string(),
],
supports_tools: true,
supports_reasoning: true,
},
ModelInfo {
id: "xiaomi/mimo-v2.5-pro".to_string(),
provider: ProviderKind::Openrouter,
@@ -745,8 +732,6 @@ mod tests {
for (alias, expected) in [
("trinity-large-thinking", "arcee-ai/trinity-large-thinking"),
("qwen3.7", "qwen/qwen3.7-max"),
("qwen3.7-max", "qwen/qwen3.7-max"),
("qwen3.6-35b-a3b", "qwen/qwen3.6-35b-a3b"),
("gemma-4-31b-it", "google/gemma-4-31b-it"),
("glm-5.1", "z-ai/glm-5.1"),
-10
View File
@@ -36,7 +36,6 @@ const OPENROUTER_GLM_5_1_MODEL: &str = "z-ai/glm-5.1";
const OPENROUTER_KIMI_K2_6_MODEL: &str = "moonshotai/kimi-k2.6";
const OPENROUTER_NEMOTRON_3_NANO_OMNI_MODEL: &str =
"nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free";
const OPENROUTER_QWEN_3_7_MAX_MODEL: &str = "qwen/qwen3.7-max";
const OPENROUTER_QWEN_3_6_35B_A3B_MODEL: &str = "qwen/qwen3.6-35b-a3b";
const OPENROUTER_QWEN_3_6_27B_MODEL: &str = "qwen/qwen3.6-27b";
const OPENROUTER_TENCENT_HY3_PREVIEW_MODEL: &str = "tencent/hy3-preview";
@@ -1525,13 +1524,6 @@ fn canonical_openrouter_recent_model_id(model: &str) -> Option<&'static str> {
OPENROUTER_NEMOTRON_3_NANO_OMNI_MODEL
| "nemotron-3-nano-omni"
| "nemotron-3-nano-omni-reasoning" => Some(OPENROUTER_NEMOTRON_3_NANO_OMNI_MODEL),
OPENROUTER_QWEN_3_7_MAX_MODEL
| "qwen3.7"
| "qwen-3.7"
| "qwen3-7"
| "qwen3.7-max"
| "qwen-3.7-max"
| "qwen3-7-max" => Some(OPENROUTER_QWEN_3_7_MAX_MODEL),
OPENROUTER_QWEN_3_6_35B_A3B_MODEL
| "qwen3.6-35b-a3b"
| "qwen-3.6-35b-a3b"
@@ -3845,8 +3837,6 @@ unix_socket_path = "/tmp/cw-hooks.sock"
"trinity-large-thinking",
OPENROUTER_ARCEE_TRINITY_LARGE_THINKING_MODEL,
),
("qwen3.7", OPENROUTER_QWEN_3_7_MAX_MODEL),
("qwen3.7-max", OPENROUTER_QWEN_3_7_MAX_MODEL),
("qwen3.6-35b-a3b", OPENROUTER_QWEN_3_6_35B_A3B_MODEL),
("mimo-v2.5-pro", OPENROUTER_XIAOMI_MIMO_V2_5_PRO_MODEL),
("kimi-k2.6", OPENROUTER_KIMI_K2_6_MODEL),
+8 -2
View File
@@ -12,8 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- **Recent large OpenRouter model presets.** Added completions, aliases,
routing metadata, and docs for Arcee Trinity Large Thinking, Qwen 3.7
Max, Xiaomi MiMo v2.5, Qwen 3.6 open-weight models, Kimi K2.6,
routing metadata, and docs for Arcee Trinity Large Thinking,
MiniMax M3, Xiaomi MiMo v2.5, Qwen 3.6 open-weight models, Kimi K2.6,
GLM 5.1, Tencent Hy3, Gemma 4, and Nemotron (#2461).
- **Provider and web-search expansion.** Added Xiaomi MiMo provider support,
SiliconFlow, AtlasCloud static models, Volcengine Ark search, Baidu AI
@@ -34,6 +34,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
event envelopes, task migration/env isolation fixes, and state-message
parent IDs for future forks (#2383, #2358, #2367, #2252, #2272, #2308).
### Removed
- **Qwen 3.7 Max OpenRouter preset.** Removed from the model registry, docs,
and examples. Qwen 3.7 Max is a hosted model, not open-source; the preset
will return when an open-weight Qwen 3.7 release ships.
### Changed
- **Release hardening.** CI now runs clippy/docs checks, web frontend lint and
-1
View File
@@ -3444,7 +3444,6 @@ mod alias_thinking_detection_tests {
"mimo-v2.5-pro should stream reasoning as thinking on Xiaomi MiMo"
);
for model in [
"qwen/qwen3.7-max",
"arcee-ai/trinity-large-thinking",
"minimax/minimax-m3",
"xiaomi/mimo-v2.5-pro",
-13
View File
@@ -56,7 +56,6 @@ pub const OPENROUTER_KIMI_K2_6_MODEL: &str = "moonshotai/kimi-k2.6";
pub const OPENROUTER_MINIMAX_M3_MODEL: &str = "minimax/minimax-m3";
pub const OPENROUTER_NEMOTRON_3_NANO_OMNI_MODEL: &str =
"nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free";
pub const OPENROUTER_QWEN_3_7_MAX_MODEL: &str = "qwen/qwen3.7-max";
pub const OPENROUTER_QWEN_3_6_35B_A3B_MODEL: &str = "qwen/qwen3.6-35b-a3b";
pub const OPENROUTER_QWEN_3_6_27B_MODEL: &str = "qwen/qwen3.6-27b";
pub const OPENROUTER_TENCENT_HY3_PREVIEW_MODEL: &str = "tencent/hy3-preview";
@@ -64,7 +63,6 @@ pub const OPENROUTER_XIAOMI_MIMO_V2_5_PRO_MODEL: &str = "xiaomi/mimo-v2.5-pro";
pub const OPENROUTER_XIAOMI_MIMO_V2_5_MODEL: &str = "xiaomi/mimo-v2.5";
pub const RECENT_OPENROUTER_LARGE_MODELS: &[&str] = &[
OPENROUTER_ARCEE_TRINITY_LARGE_THINKING_MODEL,
OPENROUTER_QWEN_3_7_MAX_MODEL,
OPENROUTER_MINIMAX_M3_MODEL,
OPENROUTER_XIAOMI_MIMO_V2_5_PRO_MODEL,
OPENROUTER_XIAOMI_MIMO_V2_5_MODEL,
@@ -516,13 +514,6 @@ fn canonical_openrouter_recent_model_id(model: &str) -> Option<&'static str> {
OPENROUTER_NEMOTRON_3_NANO_OMNI_MODEL
| "nemotron-3-nano-omni"
| "nemotron-3-nano-omni-reasoning" => Some(OPENROUTER_NEMOTRON_3_NANO_OMNI_MODEL),
OPENROUTER_QWEN_3_7_MAX_MODEL
| "qwen3.7"
| "qwen-3.7"
| "qwen3-7"
| "qwen3.7-max"
| "qwen-3.7-max"
| "qwen3-7-max" => Some(OPENROUTER_QWEN_3_7_MAX_MODEL),
OPENROUTER_QWEN_3_6_35B_A3B_MODEL
| "qwen3.6-35b-a3b"
| "qwen-3.6-35b-a3b"
@@ -6505,8 +6496,6 @@ api_key = "old-openrouter-key"
"trinity-large-thinking",
OPENROUTER_ARCEE_TRINITY_LARGE_THINKING_MODEL,
),
("qwen3.7", OPENROUTER_QWEN_3_7_MAX_MODEL),
("qwen3.7-max", OPENROUTER_QWEN_3_7_MAX_MODEL),
("qwen3.6-35b-a3b", OPENROUTER_QWEN_3_6_35B_A3B_MODEL),
("mimo-v2.5-pro", OPENROUTER_XIAOMI_MIMO_V2_5_PRO_MODEL),
("kimi-k2.6", OPENROUTER_KIMI_K2_6_MODEL),
@@ -6537,7 +6526,6 @@ api_key = "old-openrouter-key"
DEFAULT_OPENROUTER_MODEL,
DEFAULT_OPENROUTER_FLASH_MODEL,
OPENROUTER_ARCEE_TRINITY_LARGE_THINKING_MODEL,
OPENROUTER_QWEN_3_7_MAX_MODEL,
OPENROUTER_XIAOMI_MIMO_V2_5_PRO_MODEL,
OPENROUTER_MINIMAX_M3_MODEL,
OPENROUTER_QWEN_3_6_35B_A3B_MODEL,
@@ -8629,7 +8617,6 @@ model = "deepseek-ai/deepseek-v4-pro"
262_144,
262_144,
),
(OPENROUTER_QWEN_3_7_MAX_MODEL, 1_000_000, 65_536),
(OPENROUTER_XIAOMI_MIMO_V2_5_PRO_MODEL, 1_000_000, 131_072),
(OPENROUTER_MINIMAX_M3_MODEL, 1_000_000, 524_288),
] {
+5 -2
View File
@@ -6076,7 +6076,7 @@ mod terminal_mode_tests {
default_text_model: Some("deepseek/deepseek-v4-pro".to_string()),
providers: Some(crate::config::ProvidersConfig {
openrouter: crate::config::ProviderConfig {
model: Some("qwen/qwen3.7-max".to_string()),
model: Some("arcee-ai/trinity-large-thinking".to_string()),
..Default::default()
},
..Default::default()
@@ -6084,7 +6084,10 @@ mod terminal_mode_tests {
..Default::default()
};
assert_eq!(resolve_exec_model(&config, None), "qwen/qwen3.7-max");
assert_eq!(
resolve_exec_model(&config, None),
"arcee-ai/trinity-large-thinking"
);
assert_eq!(
resolve_exec_model(&config, Some("arcee-ai/trinity-large-thinking")),
"arcee-ai/trinity-large-thinking"
+2 -9
View File
@@ -253,8 +253,7 @@ fn known_context_window_for_model(model_lower: &str) -> Option<u32> {
| "moonshotai/kimi-k2.6:free" => Some(262_144),
"z-ai/glm-5.1" | "z-ai/glm-5v-turbo" => Some(202_752),
"minimax/minimax-m3" => Some(1_000_000),
"qwen/qwen3.7-max"
| "xiaomi/mimo-v2.5-pro"
"xiaomi/mimo-v2.5-pro"
| "xiaomi/mimo-v2.5"
| "mimo-v2.5-pro"
| "mimo-v2.5"
@@ -276,7 +275,7 @@ pub fn max_output_tokens_for_model(model: &str) -> Option<u32> {
"xiaomi/mimo-v2.5-pro" | "xiaomi/mimo-v2.5" | "mimo-v2.5-pro" | "mimo-v2.5" => {
Some(131_072)
}
"qwen/qwen3.7-max" | "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free" => Some(65_536),
"nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free" => Some(65_536),
"google/gemma-4-31b-it" => Some(16_384),
"google/gemma-4-31b-it:free" | "google/gemma-4-26b-a4b-it:free" => Some(32_768),
_ => None,
@@ -300,7 +299,6 @@ pub fn model_supports_reasoning(model: &str) -> bool {
| "moonshotai/kimi-k2.6:free"
| "minimax/minimax-m3"
| "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free"
| "qwen/qwen3.7-max"
| "qwen/qwen3.6-35b-a3b"
| "qwen/qwen3.6-27b"
| "tencent/hy3-preview"
@@ -500,7 +498,6 @@ mod tests {
fn recent_openrouter_large_models_have_static_windows() {
for (model, expected_window) in [
("arcee-ai/trinity-large-thinking", 262_144),
(concat!("qwen/", "qwen3.7-max"), 1_000_000),
(concat!("qwen/", "qwen3.6-35b-a3b"), 262_144),
(concat!("xiaomi/", "mimo-v2.5-pro"), 1_000_000),
("mimo-v2.5-pro", 1_000_000),
@@ -520,10 +517,6 @@ mod tests {
max_output_tokens_for_model("arcee-ai/trinity-large-thinking"),
Some(262_144)
);
assert_eq!(
max_output_tokens_for_model(concat!("qwen/", "qwen3.7-max")),
Some(65_536)
);
assert_eq!(
max_output_tokens_for_model(concat!("xiaomi/", "mimo-v2.5-pro")),
Some(131_072)
+5
View File
@@ -1445,6 +1445,10 @@ pub struct App {
pub submit_pending_steers_after_interrupt: bool,
/// Start time for current turn
pub turn_started_at: Option<Instant>,
/// Most recent engine event observed for the current turn. This is
/// separate from `turn_started_at` because the latter drives elapsed-time
/// UI and must not be reset during long but healthy turns.
pub turn_last_activity_at: Option<Instant>,
/// Sum of completed turn durations for this `App` instance (#448
/// follow-up). Drives the footer's `worked Nh Mm` chip so the
/// label reflects actual model work, not wall-clock since launch.
@@ -2055,6 +2059,7 @@ impl App {
rejected_steers: VecDeque::new(),
submit_pending_steers_after_interrupt: false,
turn_started_at: None,
turn_last_activity_at: None,
cumulative_turn_duration: std::time::Duration::ZERO,
balance_cell: std::sync::Arc::new(std::sync::Mutex::new(None)),
balance_initiated: false,
+2 -4
View File
@@ -331,7 +331,6 @@ fn picker_model_hint(id: &str) -> &'static str {
"faster model"
}
"arcee-ai/trinity-large-thinking" => "large thinking",
"qwen/qwen3.7-max" => "large Qwen",
"xiaomi/mimo-v2.5-pro" | "mimo-v2.5-pro" => "long context",
"minimax/minimax-m3" => "1M multimodal",
_ => "provider model",
@@ -640,14 +639,13 @@ mod tests {
let (mut app, _lock) = create_test_app();
app.api_provider = crate::config::ApiProvider::Openrouter;
app.model_ids_passthrough = true;
app.model = "qwen/qwen3.7-max".to_string();
app.model = "minimax/minimax-m3".to_string();
app.auto_model = false;
let view = ModelPickerView::new(&app);
let model_ids = view.visible_model_ids();
assert!(model_ids.contains(&"arcee-ai/trinity-large-thinking"));
assert!(model_ids.contains(&"qwen/qwen3.7-max"));
assert!(model_ids.contains(&"xiaomi/mimo-v2.5-pro"));
assert!(model_ids.contains(&"minimax/minimax-m3"));
assert!(
@@ -658,7 +656,7 @@ mod tests {
"MiniMax M3 should be visible in the first picker window on normal terminals"
);
assert!(!view.show_custom_model_row);
assert_eq!(view.resolved_model(), "qwen/qwen3.7-max");
assert_eq!(view.resolved_model(), "minimax/minimax-m3");
}
#[test]
+54 -4
View File
@@ -1158,6 +1158,7 @@ async fn run_event_loop(
} else if !app.is_loading && ignore_stale_stream_event_while_idle(&event) {
continue;
}
record_turn_activity(app, &event, Instant::now());
match event {
EngineEvent::MessageStarted { .. } => {
// Assistant text starting after parallel tool work
@@ -1474,7 +1475,9 @@ async fn run_event_loop(
app.streaming_state.reset();
app.streaming_message_index = None;
app.streaming_thinking_active_entry = None;
app.turn_started_at = Some(Instant::now());
let now = Instant::now();
app.turn_started_at = Some(now);
app.turn_last_activity_at = Some(now);
// Discoverability hint for users who don't know how
// to interrupt a long-running turn (#1367). Only
// surface when the status_message slot is empty so
@@ -1541,6 +1544,7 @@ async fn run_event_loop(
let turn_elapsed =
app.turn_started_at.map(|t| t.elapsed()).unwrap_or_default();
app.turn_started_at = None;
app.turn_last_activity_at = None;
// Roll the just-finished turn's elapsed time into the
// cumulative session work-time (#448 follow-up). The
// footer's `worked Nh Mm` chip reads this so the
@@ -4077,6 +4081,7 @@ fn reconcile_turn_liveness(app: &mut App, now: Instant, has_running_agents: bool
app.is_loading = false;
app.dispatch_started_at = None;
app.turn_started_at = None;
app.turn_last_activity_at = None;
app.push_status_toast(
"Turn dispatch timed out; the engine may have stopped. Please try again.",
StatusToastLevel::Error,
@@ -4097,6 +4102,7 @@ fn reconcile_turn_liveness(app: &mut App, now: Instant, has_running_agents: bool
app.is_loading = false;
app.dispatch_started_at = None;
app.turn_started_at = None;
app.turn_last_activity_at = None;
app.push_status_toast(
"Recovered from an inconsistent busy state.",
StatusToastLevel::Warning,
@@ -4111,9 +4117,13 @@ fn reconcile_turn_liveness(app: &mut App, now: Instant, has_running_agents: bool
&& matches!(app.runtime_turn_status.as_deref(), Some("in_progress"))
&& !has_running_agents
&& !app.is_compacting
&& app.turn_started_at.is_some_and(|started| {
now.saturating_duration_since(started) > TURN_STALL_WATCHDOG_TIMEOUT
})
&& !active_turn_has_running_tool(app)
&& app
.turn_last_activity_at
.or(app.turn_started_at)
.is_some_and(|last_activity| {
now.saturating_duration_since(last_activity) > TURN_STALL_WATCHDOG_TIMEOUT
})
{
// Finalize in-flight thinking / assistant / tool cells so the
// transcript doesn't show permanent spinners after recovery.
@@ -4126,6 +4136,7 @@ fn reconcile_turn_liveness(app: &mut App, now: Instant, has_running_agents: bool
app.is_loading = false;
app.turn_started_at = None;
app.turn_last_activity_at = None;
app.runtime_turn_status = None;
app.runtime_turn_id = None;
app.dispatch_started_at = None;
@@ -4142,6 +4153,44 @@ fn reconcile_turn_liveness(app: &mut App, now: Instant, has_running_agents: bool
false
}
fn record_turn_activity(app: &mut App, event: &EngineEvent, now: Instant) {
if matches!(event, EngineEvent::TurnStarted { .. }) {
app.turn_last_activity_at = Some(now);
return;
}
if app.is_loading || matches!(app.runtime_turn_status.as_deref(), Some("in_progress")) {
app.turn_last_activity_at = Some(now);
}
}
fn active_turn_has_running_tool(app: &App) -> bool {
app.active_cell.as_ref().is_some_and(|active| {
active.entries().iter().any(|cell| match cell {
HistoryCell::Tool(tool) => tool_cell_is_running(tool),
_ => false,
})
})
}
fn tool_cell_is_running(tool: &ToolCell) -> bool {
match tool {
ToolCell::Exec(cell) => cell.status == ToolStatus::Running,
ToolCell::Exploring(cell) => cell
.entries
.iter()
.any(|entry| entry.status == ToolStatus::Running),
ToolCell::PlanUpdate(cell) => cell.status == ToolStatus::Running,
ToolCell::PatchSummary(cell) => cell.status == ToolStatus::Running,
ToolCell::Review(cell) => cell.status == ToolStatus::Running,
ToolCell::DiffPreview(_) => false,
ToolCell::Mcp(cell) => cell.status == ToolStatus::Running,
ToolCell::ViewImage(_) => false,
ToolCell::WebSearch(cell) => cell.status == ToolStatus::Running,
ToolCell::Generic(cell) => cell.status == ToolStatus::Running,
}
}
/// Translate an `EngineEvent::Error` into UI state updates.
///
/// The engine's `recoverable` flag (mirrored on `ErrorEnvelope`) decides
@@ -6879,6 +6928,7 @@ fn mark_active_turn_cancelled_locally(app: &mut App) {
app.is_loading = false;
app.dispatch_started_at = None;
app.turn_started_at = None;
app.turn_last_activity_at = None;
app.streaming_state.reset();
app.runtime_turn_id = None;
app.runtime_turn_status = None;
+49
View File
@@ -2509,6 +2509,55 @@ fn turn_liveness_leaves_active_turn_running() {
assert!(app.status_toasts.is_empty());
}
#[test]
fn turn_liveness_uses_recent_turn_activity_not_turn_start() {
let mut app = create_test_app();
let now = Instant::now();
app.is_loading = true;
app.runtime_turn_status = Some("in_progress".to_string());
app.turn_started_at = Some(now - TURN_STALL_WATCHDOG_TIMEOUT - Duration::from_secs(30));
app.turn_last_activity_at = Some(now - Duration::from_secs(1));
let recovered = reconcile_turn_liveness(&mut app, now, false);
assert!(!recovered);
assert!(app.is_loading);
assert!(app.runtime_turn_status.is_some());
assert!(app.status_toasts.is_empty());
}
#[test]
fn turn_liveness_does_not_abort_running_tool() {
let mut app = create_test_app();
let now = Instant::now();
app.is_loading = true;
app.runtime_turn_status = Some("in_progress".to_string());
app.turn_started_at = Some(now - TURN_STALL_WATCHDOG_TIMEOUT - Duration::from_secs(30));
app.turn_last_activity_at = app.turn_started_at;
let mut active = ActiveCell::new();
active.push_tool(
"tool-1",
HistoryCell::Tool(ToolCell::Generic(GenericToolCell {
name: "edit_file".to_string(),
status: ToolStatus::Running,
input_summary: Some("path: CHANGELOG.md".to_string()),
output: None,
prompts: None,
spillover_path: None,
output_summary: None,
is_diff: false,
})),
);
app.active_cell = Some(active);
let recovered = reconcile_turn_liveness(&mut app, now, false);
assert!(!recovered);
assert!(app.is_loading);
assert!(app.active_cell.is_some());
assert!(app.status_toasts.is_empty());
}
#[test]
fn turn_liveness_recovers_stalled_in_progress_turn() {
let mut app = create_test_app();
+2 -2
View File
@@ -239,14 +239,14 @@ fn browser_open_command(url: &str) -> Result<Command> {
{
let mut command = Command::new("open");
command.arg(url);
return Ok(command);
Ok(command)
}
#[cfg(target_os = "linux")]
{
let mut command = Command::new("xdg-open");
command.arg(url);
return Ok(command);
Ok(command)
}
#[cfg(target_os = "windows")]
+1 -1
View File
@@ -590,7 +590,7 @@ If you are upgrading from older releases:
- `provider` (string, optional): `deepseek` (default), `nvidia-nim`, `openai`, `atlascloud`, `wanjie-ark`, `openrouter`, `xiaomi-mimo`, `novita`, `fireworks`, `siliconflow`, `moonshot`, `sglang`, `vllm`, or `ollama`. Legacy `deepseek-cn` configs are still accepted as an alias for `deepseek`; DeepSeek uses the same official host [`https://api.deepseek.com`](https://api-docs.deepseek.com/) worldwide. `nvidia-nim` targets NVIDIA's NIM-hosted DeepSeek endpoints through `https://integrate.api.nvidia.com/v1`; `openai` targets a generic OpenAI-compatible endpoint, defaulting to `https://api.openai.com/v1`; `atlascloud` targets AtlasCloud's OpenAI-compatible endpoint at `https://api.atlascloud.ai/v1`; `wanjie-ark` targets Wanjie Ark's OpenAI-compatible endpoint at `https://maas-openapi.wanjiedata.com/api/v1`; `openrouter` targets `https://openrouter.ai/api/v1`; `xiaomi-mimo` targets Xiaomi MiMo's OpenAI-compatible endpoint at `https://api.xiaomimimo.com/v1`; `novita` targets `https://api.novita.ai/v1`; `fireworks` targets `https://api.fireworks.ai/inference/v1`; `siliconflow` targets SiliconFlow, defaulting to `https://api.siliconflow.com/v1`; `moonshot` targets Moonshot/Kimi, defaulting to `https://api.moonshot.ai/v1`; `sglang` targets a self-hosted OpenAI-compatible endpoint, defaulting to `http://localhost:30000/v1`; `vllm` targets a self-hosted vLLM OpenAI-compatible endpoint, defaulting to `http://localhost:8000/v1`; `ollama` targets Ollama's OpenAI-compatible endpoint, defaulting to `http://localhost:11434/v1`.
- `api_key` (string, required for hosted providers): must be non-empty for DeepSeek/hosted providers (or set the provider API key env var). Self-hosted SGLang, vLLM, and Ollama can omit it.
- `base_url` (string, optional): defaults to `https://api.deepseek.com/beta` for DeepSeek's OpenAI-compatible Chat Completions API, including legacy `provider = "deepseek-cn"` configs. Other defaults are `https://integrate.api.nvidia.com/v1` for `nvidia-nim`, `https://api.openai.com/v1` for `openai`, `https://api.atlascloud.ai/v1` for `atlascloud`, `https://maas-openapi.wanjiedata.com/api/v1` for `wanjie-ark`, `https://openrouter.ai/api/v1` for `openrouter`, `https://api.xiaomimimo.com/v1` for `xiaomi-mimo`, `https://api.novita.ai/v1` for `novita`, `https://api.fireworks.ai/inference/v1` for `fireworks`, `https://api.siliconflow.com/v1` for `siliconflow`, `https://api.moonshot.ai/v1` for `moonshot`, `http://localhost:30000/v1` for `sglang`, `http://localhost:8000/v1` for `vllm`, and `http://localhost:11434/v1` for `ollama`. Set `https://api.deepseek.com` or `https://api.deepseek.com/v1` explicitly to opt out of DeepSeek beta features.
- `default_text_model` (string, optional): defaults to `deepseek-v4-pro` for DeepSeek and generic OpenAI-compatible endpoints, `deepseek-ai/deepseek-v4-pro` for NVIDIA NIM, `deepseek-ai/deepseek-v4-flash` for AtlasCloud, `deepseek-reasoner` for Wanjie Ark, `deepseek/deepseek-v4-pro` for OpenRouter and Novita, `mimo-v2.5-pro` for Xiaomi MiMo, `accounts/fireworks/models/deepseek-v4-pro` for Fireworks, `deepseek-ai/DeepSeek-V4-Pro` for SiliconFlow, `kimi-k2.6` for Moonshot, `deepseek-ai/DeepSeek-V4-Pro` for SGLang/vLLM, and `deepseek-coder:1.3b` for Ollama. Current public DeepSeek IDs are `deepseek-v4-pro` and `deepseek-v4-flash`, both with 1M context windows, 384K max output, and thinking mode enabled by default. Legacy `deepseek-chat` and `deepseek-reasoner` remain compatibility aliases for `deepseek-v4-flash` until July 24, 2026, except SiliconFlow maps `deepseek-reasoner` and `deepseek-r1` to its Pro model while `deepseek-chat` and `deepseek-v3` map to Flash. Provider-specific mappings translate `deepseek-v4-pro` / `deepseek-v4-flash` to each provider's model ID where supported. OpenRouter also recognizes recent large IDs such as `arcee-ai/trinity-large-thinking`, `qwen/qwen3.7-max`, `minimax/minimax-m3`, `xiaomi/mimo-v2.5-pro`, `qwen/qwen3.6-35b-a3b`, `google/gemma-4-31b-it`, and `moonshotai/kimi-k2.6`. Generic `openai`, `atlascloud`, `wanjie-ark`, `xiaomi-mimo`, and Ollama model IDs are passed through unchanged. OpenRouter and SiliconFlow provider configs with a custom `base_url` also preserve explicit model values, which lets OpenAI-compatible gateways accept bare model IDs. Use `/models` or `codewhale models` to discover live IDs from your configured endpoint. `CODEWHALE_MODEL` overrides this for a single process; `DEEPSEEK_MODEL` is the legacy alias.
- `default_text_model` (string, optional): defaults to `deepseek-v4-pro` for DeepSeek and generic OpenAI-compatible endpoints, `deepseek-ai/deepseek-v4-pro` for NVIDIA NIM, `deepseek-ai/deepseek-v4-flash` for AtlasCloud, `deepseek-reasoner` for Wanjie Ark, `deepseek/deepseek-v4-pro` for OpenRouter and Novita, `mimo-v2.5-pro` for Xiaomi MiMo, `accounts/fireworks/models/deepseek-v4-pro` for Fireworks, `deepseek-ai/DeepSeek-V4-Pro` for SiliconFlow, `kimi-k2.6` for Moonshot, `deepseek-ai/DeepSeek-V4-Pro` for SGLang/vLLM, and `deepseek-coder:1.3b` for Ollama. Current public DeepSeek IDs are `deepseek-v4-pro` and `deepseek-v4-flash`, both with 1M context windows, 384K max output, and thinking mode enabled by default. Legacy `deepseek-chat` and `deepseek-reasoner` remain compatibility aliases for `deepseek-v4-flash` until July 24, 2026, except SiliconFlow maps `deepseek-reasoner` and `deepseek-r1` to its Pro model while `deepseek-chat` and `deepseek-v3` map to Flash. Provider-specific mappings translate `deepseek-v4-pro` / `deepseek-v4-flash` to each provider's model ID where supported. OpenRouter also recognizes recent large IDs such as `arcee-ai/trinity-large-thinking`, `minimax/minimax-m3`, `xiaomi/mimo-v2.5-pro`, `qwen/qwen3.6-35b-a3b`, `google/gemma-4-31b-it`, and `moonshotai/kimi-k2.6`. Generic `openai`, `atlascloud`, `wanjie-ark`, `xiaomi-mimo`, and Ollama model IDs are passed through unchanged. OpenRouter and SiliconFlow provider configs with a custom `base_url` also preserve explicit model values, which lets OpenAI-compatible gateways accept bare model IDs. Use `/models` or `codewhale models` to discover live IDs from your configured endpoint. `CODEWHALE_MODEL` overrides this for a single process; `DEEPSEEK_MODEL` is the legacy alias.
- `reasoning_effort` (string, optional): `off`, `low`, `medium`, `high`, or `max`; defaults to the configured UI tier. DeepSeek Platform receives top-level `thinking` / `reasoning_effort` fields. NVIDIA NIM receives equivalent settings through `chat_template_kwargs`.
- `allow_shell` (bool, optional): defaults to `true` (sandboxed).
- `approval_policy` (string, optional): `on-request`, `untrusted`, or `never`. Runtime `approval_mode` editing in `/config` also accepts `on-request` and `untrusted` aliases.
+3 -5
View File
@@ -117,7 +117,7 @@ endpoint.
| `atlascloud` | `[providers.atlascloud]` | `ATLASCLOUD_API_KEY` | `ATLASCLOUD_BASE_URL`; default `https://api.atlascloud.ai/v1` | `deepseek-ai/deepseek-v4-flash`, `deepseek-ai/deepseek-v4-pro` | OpenAI-compatible hosted route. `ATLASCLOUD_MODEL` is accepted by the TUI config path, and the static `ModelRegistry` includes AtlasCloud fallback rows for CLI model resolution. |
| `wanjie-ark` | `[providers.wanjie_ark]` | `WANJIE_ARK_API_KEY`, `WANJIE_API_KEY`, `WANJIE_MAAS_API_KEY` | `WANJIE_ARK_BASE_URL`, `WANJIE_BASE_URL`, `WANJIE_MAAS_BASE_URL`; default `https://maas-openapi.wanjiedata.com/api/v1` | `deepseek-reasoner` | OpenAI-compatible hosted route. `WANJIE_ARK_MODEL`, `WANJIE_MODEL`, and `WANJIE_MAAS_MODEL` are accepted. |
| `volcengine` | `[providers.volcengine]` | `VOLCENGINE_API_KEY`, `VOLCENGINE_ARK_API_KEY`, `ARK_API_KEY` | `VOLCENGINE_BASE_URL`, `VOLCENGINE_ARK_BASE_URL`, `ARK_BASE_URL`; default `https://ark.cn-beijing.volces.com/api/coding/v3` | `DeepSeek-V4-Pro`, `DeepSeek-V4-Flash` | Volcengine/Volcano Engine Ark OpenAI-compatible coding endpoint. `VOLCENGINE_MODEL` and `VOLCENGINE_ARK_MODEL` are accepted. |
| `openrouter` | `[providers.openrouter]` | `OPENROUTER_API_KEY` | `OPENROUTER_BASE_URL`; default `https://openrouter.ai/api/v1` | `deepseek/deepseek-v4-pro`, `deepseek/deepseek-v4-flash`; recent large IDs include `arcee-ai/trinity-large-thinking`, `qwen/qwen3.7-max`, `minimax/minimax-m3`, `xiaomi/mimo-v2.5-pro`, `qwen/qwen3.6-35b-a3b`, `google/gemma-4-31b-it`, `z-ai/glm-5.1`, `moonshotai/kimi-k2.6` | Additive open-model routing layer. It does not replace DeepSeek; it lets users route supported model IDs through OpenRouter when they choose it. |
| `openrouter` | `[providers.openrouter]` | `OPENROUTER_API_KEY` | `OPENROUTER_BASE_URL`; default `https://openrouter.ai/api/v1` | `deepseek/deepseek-v4-pro`, `deepseek/deepseek-v4-flash`; recent large IDs include `arcee-ai/trinity-large-thinking`, `minimax/minimax-m3`, `xiaomi/mimo-v2.5-pro`, `qwen/qwen3.6-35b-a3b`, `google/gemma-4-31b-it`, `z-ai/glm-5.1`, `moonshotai/kimi-k2.6` | Additive open-model routing layer. It does not replace DeepSeek; it lets users route supported model IDs through OpenRouter when they choose it. |
| `xiaomi-mimo` | `[providers.xiaomi_mimo]` | `XIAOMI_MIMO_API_KEY`, `XIAOMI_API_KEY`, `MIMO_API_KEY` | `XIAOMI_MIMO_BASE_URL`, `MIMO_BASE_URL`; default `https://api.xiaomimimo.com/v1` | `mimo-v2.5-pro`, `mimo-v2.5` | Xiaomi MiMo OpenAI-compatible chat completions route. It sends `max_completion_tokens` and uses MiMo's `thinking` field for reasoning control. |
| `novita` | `[providers.novita]` | `NOVITA_API_KEY` | `NOVITA_BASE_URL`; default `https://api.novita.ai/v1` | `deepseek/deepseek-v4-pro`, `deepseek/deepseek-v4-flash` | OpenAI-compatible hosted route for DeepSeek model IDs. Use config or `CODEWHALE_MODEL` / `DEEPSEEK_MODEL` for model overrides. |
| `fireworks` | `[providers.fireworks]` | `FIREWORKS_API_KEY` | `FIREWORKS_BASE_URL`; default `https://api.fireworks.ai/inference/v1` | `accounts/fireworks/models/deepseek-v4-pro` | OpenAI-compatible hosted route. Use config or `CODEWHALE_MODEL` / `DEEPSEEK_MODEL` for model overrides. |
@@ -144,9 +144,7 @@ large models verified through OpenRouter's model metadata:
`qwen/qwen3.6-27b`, `minimax/minimax-m3`, `xiaomi/mimo-v2.5-pro`,
`xiaomi/mimo-v2.5`, `moonshotai/kimi-k2.6`, `z-ai/glm-5.1`, `tencent/hy3-preview`,
`google/gemma-4-31b-it`, `google/gemma-4-26b-a4b-it`, and
`nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free`. `qwen/qwen3.7-max`
is also included because it is a current user-requested large OpenRouter model,
but it is treated as a hosted Qwen model rather than documented as open-weight.
`nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free`.
`minimax/minimax-m3` was added from OpenRouter's May 31, 2026 listing as a 1M
context multimodal model for coding, tool use, and long-horizon agentic work.
@@ -165,7 +163,7 @@ endpoint when the endpoint supports model listing.
| `atlascloud` | `deepseek-ai/deepseek-v4-flash`, `deepseek-ai/deepseek-v4-pro` | yes | yes |
| `wanjie-ark` | `deepseek-reasoner` | yes | yes |
| `volcengine` | `DeepSeek-V4-Pro`, `DeepSeek-V4-Flash` | yes | yes |
| `openrouter` | `deepseek/deepseek-v4-pro`, `deepseek/deepseek-v4-flash`, `arcee-ai/trinity-large-thinking`, `qwen/qwen3.7-max`, `minimax/minimax-m3`, `xiaomi/mimo-v2.5-pro`, `xiaomi/mimo-v2.5`, `qwen/qwen3.6-35b-a3b`, `qwen/qwen3.6-27b`, `moonshotai/kimi-k2.6`, `z-ai/glm-5.1`, `tencent/hy3-preview`, `google/gemma-4-31b-it`, `google/gemma-4-26b-a4b-it`, `nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free` | yes | yes |
| `openrouter` | `deepseek/deepseek-v4-pro`, `deepseek/deepseek-v4-flash`, `arcee-ai/trinity-large-thinking`, `minimax/minimax-m3`, `xiaomi/mimo-v2.5-pro`, `xiaomi/mimo-v2.5`, `qwen/qwen3.6-35b-a3b`, `qwen/qwen3.6-27b`, `moonshotai/kimi-k2.6`, `z-ai/glm-5.1`, `tencent/hy3-preview`, `google/gemma-4-31b-it`, `google/gemma-4-26b-a4b-it`, `nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free` | yes | yes |
| `xiaomi-mimo` | `mimo-v2.5-pro`, `mimo-v2.5` | yes | yes |
| `novita` | `deepseek/deepseek-v4-pro`, `deepseek/deepseek-v4-flash` | yes | yes |
| `fireworks` | `accounts/fireworks/models/deepseek-v4-pro` | yes | yes |
+1 -1
View File
@@ -18,7 +18,7 @@ export interface RepoFacts {
}
export const FACTS: RepoFacts = {
"generatedAt": "2026-06-01T00:40:33.053Z",
"generatedAt": "2026-06-01T04:44:32.528Z",
"version": "0.8.48",
"crates": [
"agent",
-537
View File
@@ -1669,7 +1669,6 @@
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
"integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
@@ -2435,7 +2434,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -2458,7 +2456,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -2481,7 +2478,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -2498,7 +2494,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -2515,7 +2510,6 @@
"cpu": [
"arm"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -2532,7 +2526,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -2549,7 +2542,6 @@
"cpu": [
"ppc64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -2566,7 +2558,6 @@
"cpu": [
"riscv64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -2583,7 +2574,6 @@
"cpu": [
"s390x"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -2600,7 +2590,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -2617,7 +2606,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -2634,7 +2622,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -2651,7 +2638,6 @@
"cpu": [
"arm"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -2674,7 +2660,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -2697,7 +2682,6 @@
"cpu": [
"ppc64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -2720,7 +2704,6 @@
"cpu": [
"riscv64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -2743,7 +2726,6 @@
"cpu": [
"s390x"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -2766,7 +2748,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -2789,7 +2770,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -2812,7 +2792,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -2835,7 +2814,6 @@
"cpu": [
"wasm32"
],
"dev": true,
"license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
"optional": true,
"dependencies": {
@@ -2855,7 +2833,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "Apache-2.0 AND LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -2875,7 +2852,6 @@
"cpu": [
"ia32"
],
"dev": true,
"license": "Apache-2.0 AND LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -2895,7 +2871,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "Apache-2.0 AND LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -13107,474 +13082,6 @@
}
}
},
"node_modules/vitest/node_modules/@esbuild/aix-ppc64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz",
"integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"aix"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/vitest/node_modules/@esbuild/android-arm": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.0.tgz",
"integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/vitest/node_modules/@esbuild/android-arm64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.0.tgz",
"integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/vitest/node_modules/@esbuild/android-x64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.0.tgz",
"integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/vitest/node_modules/@esbuild/darwin-arm64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.0.tgz",
"integrity": "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/vitest/node_modules/@esbuild/darwin-x64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.0.tgz",
"integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/vitest/node_modules/@esbuild/freebsd-arm64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.0.tgz",
"integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/vitest/node_modules/@esbuild/freebsd-x64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.0.tgz",
"integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/vitest/node_modules/@esbuild/linux-arm": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.0.tgz",
"integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/vitest/node_modules/@esbuild/linux-arm64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.0.tgz",
"integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/vitest/node_modules/@esbuild/linux-ia32": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.0.tgz",
"integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/vitest/node_modules/@esbuild/linux-loong64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.0.tgz",
"integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==",
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/vitest/node_modules/@esbuild/linux-mips64el": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.0.tgz",
"integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==",
"cpu": [
"mips64el"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/vitest/node_modules/@esbuild/linux-ppc64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.0.tgz",
"integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/vitest/node_modules/@esbuild/linux-riscv64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.0.tgz",
"integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/vitest/node_modules/@esbuild/linux-s390x": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.0.tgz",
"integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==",
"cpu": [
"s390x"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/vitest/node_modules/@esbuild/linux-x64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.0.tgz",
"integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/vitest/node_modules/@esbuild/netbsd-arm64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.0.tgz",
"integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/vitest/node_modules/@esbuild/netbsd-x64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.0.tgz",
"integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/vitest/node_modules/@esbuild/openbsd-arm64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.0.tgz",
"integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/vitest/node_modules/@esbuild/openbsd-x64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.0.tgz",
"integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/vitest/node_modules/@esbuild/openharmony-arm64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.0.tgz",
"integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openharmony"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/vitest/node_modules/@esbuild/sunos-x64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.0.tgz",
"integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"sunos"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/vitest/node_modules/@esbuild/win32-arm64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.0.tgz",
"integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/vitest/node_modules/@esbuild/win32-ia32": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.0.tgz",
"integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/vitest/node_modules/@esbuild/win32-x64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.0.tgz",
"integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/vitest/node_modules/@vitest/mocker": {
"version": "4.1.7",
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.7.tgz",
@@ -13602,50 +13109,6 @@
}
}
},
"node_modules/vitest/node_modules/esbuild": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.0.tgz",
"integrity": "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"peer": true,
"bin": {
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=18"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.28.0",
"@esbuild/android-arm": "0.28.0",
"@esbuild/android-arm64": "0.28.0",
"@esbuild/android-x64": "0.28.0",
"@esbuild/darwin-arm64": "0.28.0",
"@esbuild/darwin-x64": "0.28.0",
"@esbuild/freebsd-arm64": "0.28.0",
"@esbuild/freebsd-x64": "0.28.0",
"@esbuild/linux-arm": "0.28.0",
"@esbuild/linux-arm64": "0.28.0",
"@esbuild/linux-ia32": "0.28.0",
"@esbuild/linux-loong64": "0.28.0",
"@esbuild/linux-mips64el": "0.28.0",
"@esbuild/linux-ppc64": "0.28.0",
"@esbuild/linux-riscv64": "0.28.0",
"@esbuild/linux-s390x": "0.28.0",
"@esbuild/linux-x64": "0.28.0",
"@esbuild/netbsd-arm64": "0.28.0",
"@esbuild/netbsd-x64": "0.28.0",
"@esbuild/openbsd-arm64": "0.28.0",
"@esbuild/openbsd-x64": "0.28.0",
"@esbuild/openharmony-arm64": "0.28.0",
"@esbuild/sunos-x64": "0.28.0",
"@esbuild/win32-arm64": "0.28.0",
"@esbuild/win32-ia32": "0.28.0",
"@esbuild/win32-x64": "0.28.0"
}
},
"node_modules/vitest/node_modules/vite": {
"version": "8.0.14",
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.14.tgz",