Watch
1
0
Fork
You've already forked souveraine
0

pin CI to rust 1.94, fix agents detail pane + settings test

agents: wire the rest of the detail widgets into the section children so
PRIMARY badge etc actually render; drop the HARDCODED debug text.
settings: test needs a provider in the map before navigating to Providers
cat.
clippy: pin CI to rust 1.94 per Cargo.toml rust-version; also apply what
cargo clippy --fix could auto-fix for 1.96 compat.
This commit is contained in:
Fimeg 2026-06-19 12:02:38 -04:00
commit 45d25b25a4
58 changed files with 178 additions and 223 deletions

View file

@ -16,8 +16,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8
with:
toolchain: "1.94"
components: clippy
- name: cargo test
run: cargo test

4
.gitignore vendored
View file

@ -62,6 +62,10 @@ souveraine.toml
# Working notes — kept on disk, never committed to any remote
CLAUDE.md
docs/
continuation_prompt.md
AD_continuation_prompt.md
COMMIT_MESSAGES.txt
vanguard-souveraine-notes.md
# Local-only project scaffolding — kept on disk, never committed to any remote
.superpowers/

View file

@ -384,7 +384,7 @@ async fn firehose_stream(
Ok(j) => j,
Err(_) => continue,
};
if socket.send(Message::Text(json.into())).await.is_err() {
if socket.send(Message::Text(json)).await.is_err() {
break;
}
}
@ -483,7 +483,7 @@ pub async fn update_config(
}
pub async fn get_compaction_logs(
State(server): State<Arc<SouveraineServer>>,
State(_server): State<Arc<SouveraineServer>>,
) -> Result<Json<serde_json::Value>, ApiError> {
let base = dirs::home_dir().unwrap_or_default().join(".souveraine");
let events_dir = base.join("events");

View file

@ -1,13 +1,7 @@
use anyhow::Result;
use futures::stream::StreamExt;
use std::sync::Arc;
use std::time::{Duration, Instant};
use tokio::sync::mpsc;
use crate::bridge::bifrost::Message as BifrostMessage;
use crate::core::nervous::EventBus;
use crate::core::session::{ContentBlock, ConversationMessage, MessageRole};
use crate::server::{ConsciousnessEvent, SouveraineServer};
use crate::server::SouveraineServer;
use crate::backend::{Backend, BackendEvent};
@ -126,11 +120,7 @@ impl crate::core::nervous::handler::TurnInjector for LocalBackend {
// holding a !Send MutexGuard across the .await below.
let conv_id = {
let map = self.server.surface_conversations.lock().unwrap();
if let Some(id) = map.get(conversation_id) {
Some(id.clone())
} else {
None
}
map.get(conversation_id).map(|id| id.clone())
};
let conv_id = match conv_id {
Some(id) => id,

View file

@ -15,12 +15,11 @@ use async_trait::async_trait;
use futures::stream::{BoxStream, StreamExt};
use std::sync::Arc;
use std::sync::atomic::{AtomicU32, Ordering};
use std::time::Duration;
use tokio::sync::mpsc;
use tokio_stream::wrappers::ReceiverStream;
use tokio_util::sync::CancellationToken;
use crate::core::session::{ContentBlock, ConversationMessage, ImageAttachment, MessageRole};
use crate::core::session::{ContentBlock, ConversationMessage, ImageAttachment};
use crate::core::config::ConsciousnessConfig;
use crate::server::SouveraineServer;

View file

@ -128,7 +128,7 @@ impl Message {
}
/// Multimodal user message with text + image content parts.
pub fn multimodal_user(text: impl Into<String>, parts: Vec<ContentPart>) -> Self {
pub fn multimodal_user(_text: impl Into<String>, parts: Vec<ContentPart>) -> Self {
Self {
role: "user".to_string(),
content: ContentValue::Parts(parts),

View file

@ -59,7 +59,7 @@ impl TokenCounter {
return 0;
}
if let Some(ref enc) = self.encoding {
if let Some(enc) = self.encoding {
enc.encode_with_special_tokens(text).len()
} else {
// No tiktoken available: chars/4 fallback

View file

@ -211,9 +211,9 @@ fn accumulate_item(item: &Value, content: &mut String, tool_calls: &mut Vec<Pars
serde_json::from_str(args_str).unwrap_or_else(|_| Value::Object(Default::default()));
tool_calls.push(ParsedToolCall { id, name, arguments });
}
Some("message") => {
Some("message")
// Fallback only — text normally arrives via output_text.delta.
if content.is_empty() {
if content.is_empty() => {
if let Some(parts) = item.get("content").and_then(|v| v.as_array()) {
for p in parts {
let is_text = matches!(
@ -228,7 +228,6 @@ fn accumulate_item(item: &Value, content: &mut String, tool_calls: &mut Vec<Pars
}
}
}
}
_ => {}
}
}

View file

@ -161,7 +161,7 @@ impl ArchivistEngine {
}
let interval_due =
turn_count > 0 && self.config.interval > 0 && turn_count % self.config.interval == 0;
turn_count > 0 && self.config.interval > 0 && turn_count.is_multiple_of(self.config.interval);
let pressure_due = pressure >= self.config.threshold;
if !interval_due && !pressure_due {
return Ok(None);

View file

@ -33,7 +33,6 @@ use chrono::{DateTime, Utc};
use tokio::sync::RwLock;
use crate::bridge::model_router::TokenCounter;
use crate::bridge::LlmProvider;
use crate::bridge::ProviderRegistry;
use crate::core::config::ConsciousnessConfig;
use crate::core::memory::MemoryRepo;

View file

@ -156,7 +156,7 @@ impl AuditEntry {
pub fn render(&self) -> String {
let yaml = serde_yaml::to_string(&AuditFrontmatter::from(self)).unwrap_or_default();
let mut body = String::new();
body.push_str(&format!("## Compaction Summary\n\n"));
body.push_str(&"## Compaction Summary\n\n".to_string());
body.push_str(&format!(
"Strategy: {}\nMessages: {} → {}\nTokens: {} → {}\n",
self.strategy, self.before_messages, self.after_messages, self.before_tokens, self.after_tokens

View file

@ -247,7 +247,7 @@ impl CompactionStrategy for MicrocompactStrategy {
}
}
let keep_recent = 5usize.max(1);
let keep_recent = 5usize;
if ordered_ids.len() <= keep_recent {
return Ok(CompactionPlan::empty());
}

View file

@ -747,38 +747,35 @@ pub struct AgentIdentity {
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[derive(Default)]
pub enum N1Trigger {
#[default]
EveryResponse,
EveryNResponses(usize),
TimeBased(u64),
Manual,
}
impl Default for N1Trigger {
fn default() -> Self { N1Trigger::EveryResponse }
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[derive(Default)]
pub enum ReflectionTrigger {
Off,
#[default]
StepCount,
CompactionEvent,
}
impl Default for ReflectionTrigger {
fn default() -> Self { ReflectionTrigger::StepCount }
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[derive(Default)]
pub enum BandwidthClass {
#[default]
High, Medium, Low, Minimal,
}
impl Default for BandwidthClass {
fn default() -> Self { BandwidthClass::High }
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]

View file

@ -3,7 +3,6 @@
//! Decodes raw image bytes, resizes to fit dimension/pixel budget, then
//! progressively reduces quality and dimension to stay under the byte ceiling.
use std::io::Write;
use base64::Engine;
@ -31,7 +30,7 @@ impl ResizePipeline {
/// Process raw image bytes into a resized (media_type, base64_data) pair.
/// Returns None if the image cannot be decoded at all.
pub fn process(&self, data: &[u8], media_type: &str) -> Option<(String, String)> {
pub fn process(&self, data: &[u8], _media_type: &str) -> Option<(String, String)> {
let img = image::load_from_memory(data).ok()?;
let img = self.resize_to_fit(&img);

View file

@ -341,7 +341,7 @@ impl MemoryRepo {
pub async fn append(&self, label: &str, content: &str) -> Result<()> {
let path = self.resolve_path(label);
let _frontmatter = if path.exists() {
if path.exists() {
let existing = tokio::fs::read_to_string(&path).await?;
let parsed = parse_memory_file(&existing)?;
if parsed.frontmatter.read_only.as_deref() == Some("true") {
@ -637,7 +637,7 @@ pub async fn execute_memory_command_with_context(
// Agent ID resolution: context > command > env var > default
let agent_id = ctx
.and_then(|c| c.agent_id.as_ref())
.or_else(|| match cmd {
.or(match cmd {
MemoryCommand::Init { agent_id } => Some(agent_id),
_ => None,
})

View file

@ -148,12 +148,11 @@ pub fn purge_old_events(events_dir: &Path, retain_days: i64) -> Result<u32> {
.and_then(|s| s.strip_suffix(".jsonl"))
{
if let Ok(date) = NaiveDate::parse_from_str(date_str, "%Y-%m-%d") {
if date < cutoff {
if std::fs::remove_file(entry.path()).is_ok() {
if date < cutoff
&& std::fs::remove_file(entry.path()).is_ok() {
removed += 1;
debug!(file = %name_str, "purged old event log");
}
}
}
}
}

View file

@ -762,7 +762,7 @@ async fn build_synthesis_orientation(memory_root: &Path) -> String {
continue;
}
let name = entry.file_name().to_string_lossy().to_string();
if newest.as_ref().map_or(true, |(n, _)| name > *n) {
if newest.as_ref().is_none_or(|(n, _)| name > *n) {
newest = Some((name, p));
}
}

View file

@ -18,6 +18,7 @@ pub struct Bash {
/// State that persists between bash calls — the body's proprioception.
#[derive(Debug, Clone)]
#[derive(Default)]
pub struct BashState {
/// Background tasks the agent has set in motion and can check on.
pub bg_tasks: Vec<BgTask>,
@ -37,13 +38,6 @@ pub enum BgStatus {
Failed { error: String },
}
impl Default for BashState {
fn default() -> Self {
Self {
bg_tasks: Vec::new(),
}
}
}
impl Bash {
pub fn new() -> Self {

View file

@ -161,7 +161,7 @@ impl ToolContext {
/// Is this path inside the agent's memory territory?
pub fn is_memory_path(&self, path: &PathBuf) -> bool {
self.memory_root.as_ref().map_or(false, |root| path.starts_with(root))
self.memory_root.as_ref().is_some_and(|root| path.starts_with(root))
}
/// Resolve a path relative to cwd if it's relative.

View file

@ -124,7 +124,7 @@ impl Itinerary {
/// Summarise for the agent's describe action.
pub fn describe(&self) -> String {
let mut out = format!("## {}\n", self.title);
for (i, stop) in self.stops.iter().enumerate() {
for (_i, stop) in self.stops.iter().enumerate() {
let marker = match stop.status {
StopStatus::Done => "",
StopStatus::Current => "",
@ -467,7 +467,7 @@ fn cmd_advance(
}
// Also complete a todo_id passed explicitly (may differ from stop's).
if let Some(ref tid) = input.get("todo_id").and_then(|v| v.as_str()) {
if let Some(tid) = input.get("todo_id").and_then(|v| v.as_str()) {
complete_todo(tasks_dir, tid);
}
}

View file

@ -96,7 +96,7 @@ static IMAGE_EXTENSIONS: &[&str] = &["png", "jpg", "jpeg", "gif", "bmp", "webp",
fn is_image(path: &Path) -> bool {
path.extension()
.and_then(|e| e.to_str())
.map_or(false, |e| IMAGE_EXTENSIONS.contains(&e))
.is_some_and(|e| IMAGE_EXTENSIONS.contains(&e))
}
fn is_text_extension(path: &Path) -> bool {
@ -108,7 +108,7 @@ fn is_text_extension(path: &Path) -> bool {
];
path.extension()
.and_then(|e| e.to_str())
.map_or(false, |e| text_exts.contains(&e.to_lowercase().as_str()))
.is_some_and(|e| text_exts.contains(&e.to_lowercase().as_str()))
}
fn looks_binary(path: &Path) -> bool {

View file

@ -80,7 +80,7 @@ impl Tool for Schedule {
};
if !schedules_dir.exists() {
std::fs::create_dir_all(&schedules_dir).map_err(|e| io_err(e))?;
std::fs::create_dir_all(&schedules_dir).map_err(io_err)?;
}
match action {
@ -147,7 +147,7 @@ impl Tool for Schedule {
chrono::Utc::now().to_rfc3339()
);
std::fs::write(&file_path, content).map_err(|e| io_err(e))?;
std::fs::write(&file_path, content).map_err(io_err)?;
ctx.fire_event(crate::core::nervous::SensorEvent {
sensor_name: "schedule".into(),
timestamp: chrono::Utc::now(),
@ -173,7 +173,7 @@ impl Tool for Schedule {
}
let mut entry = parse_schedule_file(&file_path)
.map_err(|e| io_err(e))?;
.map_err(io_err)?;
if let Some(s) = input.get("schedule").and_then(|v| v.as_str()) {
entry.schedule = s.to_string();
@ -195,7 +195,7 @@ impl Tool for Schedule {
};
}
write_schedule_file(&file_path, &entry).map_err(|e| io_err(e))?;
write_schedule_file(&file_path, &entry).map_err(io_err)?;
ctx.fire_event(crate::core::nervous::SensorEvent {
sensor_name: "schedule".into(),
timestamp: chrono::Utc::now(),
@ -220,7 +220,7 @@ impl Tool for Schedule {
return Err(err(&format!("schedule '{name}' not found")));
}
std::fs::remove_file(&file_path).map_err(|e| io_err(e))?;
std::fs::remove_file(&file_path).map_err(io_err)?;
ctx.fire_event(crate::core::nervous::SensorEvent {
sensor_name: "schedule".into(),
timestamp: chrono::Utc::now(),
@ -246,7 +246,7 @@ impl Tool for Schedule {
}
let trigger_path = schedules_dir.join(format!(".trigger-{name}"));
std::fs::write(&trigger_path, "").map_err(|e| io_err(e))?;
std::fs::write(&trigger_path, "").map_err(io_err)?;
ctx.fire_event(crate::core::nervous::SensorEvent {
sensor_name: "schedule".into(),
timestamp: chrono::Utc::now(),

View file

@ -181,7 +181,7 @@ impl Tool for Todo {
};
if !tasks_dir.exists() {
std::fs::create_dir_all(&tasks_dir).map_err(|e| io_err(e))?;
std::fs::create_dir_all(&tasks_dir).map_err(io_err)?;
}
// Identifier shared by start / update / complete / delete.
@ -271,7 +271,7 @@ impl Tool for Todo {
let energy = input
.get("energy")
.and_then(|v| v.as_str())
.unwrap_or_else(|| {
.unwrap_or({
// Default by nature
match nature {
"desire" | "investigation" => "generative",
@ -306,7 +306,7 @@ impl Tool for Todo {
thread: thread.map(|s| s.to_string()),
phase: phase.map(|s| s.to_string()),
};
write_todo_file(&file_path, &item).map_err(|e| io_err(e))?;
write_todo_file(&file_path, &item).map_err(io_err)?;
ctx.fire_event(crate::core::nervous::SensorEvent {
sensor_name: "todo".into(),
@ -339,7 +339,7 @@ impl Tool for Todo {
}
item.last_touched = chrono::Utc::now();
item.momentum = compute_momentum(&item.last_touched, &item.nature).to_string();
write_todo_file(&file_path, &item).map_err(|e| io_err(e))?;
write_todo_file(&file_path, &item).map_err(io_err)?;
ctx.fire_event(crate::core::nervous::SensorEvent {
sensor_name: "todo".into(),
@ -390,7 +390,7 @@ impl Tool for Todo {
// Editing a todo is touching it — momentum goes hot.
item.last_touched = chrono::Utc::now();
item.momentum = compute_momentum(&item.last_touched, &item.nature).to_string();
write_todo_file(&file_path, &item).map_err(|e| io_err(e))?;
write_todo_file(&file_path, &item).map_err(io_err)?;
ok(format!("Todo updated: \"{}\".", item.text))
}
@ -402,7 +402,7 @@ impl Tool for Todo {
item.status = STATUS_DONE.to_string();
item.completed_at = Some(chrono::Utc::now());
item.momentum = "cold".to_string();
write_todo_file(&file_path, &item).map_err(|e| io_err(e))?;
write_todo_file(&file_path, &item).map_err(io_err)?;
ctx.fire_event(crate::core::nervous::SensorEvent {
sensor_name: "todo".into(),
@ -422,7 +422,7 @@ impl Tool for Todo {
let identifier = want_id()?;
let (file_path, item) = resolve_todo(&tasks_dir, identifier)?;
std::fs::remove_file(&file_path).map_err(|e| io_err(e))?;
std::fs::remove_file(&file_path).map_err(io_err)?;
ctx.fire_event(crate::core::nervous::SensorEvent {
sensor_name: "todo".into(),
@ -558,7 +558,7 @@ fn load_todos(
}
}
}
out.sort_by(|a, b| a.1.created_at.cmp(&b.1.created_at));
out.sort_by_key(|a| a.1.created_at);
out
}

View file

@ -1332,7 +1332,7 @@ async fn load_config() -> anyhow::Result<ConsciousnessConfig> {
}
warn!("no config found; using defaults (will probe Bifrost for models)");
let mut config = ConsciousnessConfig::default();
let config = ConsciousnessConfig::default();
// Try to seed model list from the active inference provider
info!("discovering models from provider");

View file

@ -267,7 +267,7 @@ impl ConsciousnessEngine {
// Runs an LLM pass over the recent transcript and updates ledgers
// / primary memory via the memory tool. The summary string is
// surfaced as a ConsciousnessEvent so the cockpit panel renders it.
if turn_count > 0 && turn_count % 25 == 0 {
if turn_count > 0 && turn_count.is_multiple_of(25) {
match self
.reflection
.reflect_now(agent_id, messages)

View file

@ -1,4 +1,4 @@
use crate::bridge::{build_provider, build_registry, ProviderRegistry, LlmProvider};
use crate::bridge::{build_registry, ProviderRegistry, LlmProvider};
use crate::core::compact::{CompactionEngine, DefaultCompactionEngine, UtcClock};
use crate::core::config::ConsciousnessConfig;
use crate::core::identity::SeedId;
@ -159,7 +159,7 @@ impl SouveraineServer {
let conv_ids = s.list_for_agent(agent_id);
let conv_id = conv_ids.last()
.ok_or_else(|| anyhow::anyhow!("No session for {}", agent_id))?;
let mut session = s.get_mut(&conv_id)
let mut session = s.get_mut(conv_id)
.ok_or_else(|| anyhow::anyhow!("Session not found"))?;
session.messages = messages;
Ok(())

View file

@ -1,4 +1,3 @@
use anyhow::Result;
use async_trait::async_trait;
use std::sync::Arc;
use std::time::Duration;

View file

@ -1,4 +1,3 @@
use std::collections::HashMap;
use std::sync::Arc;
use std::sync::atomic::{AtomicU64, Ordering};
use std::time::{Duration, Instant};
@ -11,7 +10,7 @@ use crate::core::compact::CompactionEngine;
use crate::core::nervous::{EventBus, SensorEvent};
use crate::core::session::{ContentBlock, ConversationMessage, MessageRole};
use crate::core::tools::defs::ToolContext;
use crate::server::consciousness_engine::{ConsciousnessEvent, ConsciousnessEngine};
use crate::server::consciousness_engine::ConsciousnessEvent;
use crate::server::SouveraineServer;
use crate::backend::BackendEvent;
@ -131,7 +130,7 @@ pub(crate) async fn run_turn(
for b in &m.blocks {
match b {
ContentBlock::Text { text } => text_parts.push(text.as_str()),
ContentBlock::Image { media_type, .. } => {
ContentBlock::Image { media_type: _, .. } => {
text_parts.push("");
}
_ => {}
@ -637,7 +636,7 @@ pub(crate) async fn run_turn(
// the loop. The primary feels a halt as a migraine in her own
// register — no `[subconscious: …]` text is ever shoved into her
// context, and no `*[HALT]*` marker pollutes session storage.
if checkpoint_interval > 0 && tool_round > 0 && tool_round % checkpoint_interval == 0 {
if checkpoint_interval > 0 && tool_round > 0 && tool_round.is_multiple_of(checkpoint_interval) {
let recent: Vec<_> = checkpoint_blocks
.iter()
.rev()
@ -672,7 +671,7 @@ pub(crate) async fn run_turn(
&user_message,
tool_round,
in_flight_summary,
Some(&tx),
Some(tx),
)
.await
{
@ -877,7 +876,7 @@ pub(crate) async fn run_turn(
};
let pass_result = server
.consciousness
.on_response(&agent_id, n1_turn_count, &n1_messages, &final_content, Some(&tx))
.on_response(&agent_id, n1_turn_count, &n1_messages, &final_content, Some(tx))
.await;
let pass_elapsed = pass_start.elapsed();

View file

@ -339,7 +339,7 @@ pub mod bloom {
if cc < area.x + area.width && cr < area.y + area.height {
let cell = buf.get_mut(cc, cr);
cell.set_char('⬟');
cell.set_style(Style::default().fg(rgb(pr.min(255), pg.min(255), pb.min(255))));
cell.set_style(Style::default().fg(rgb(pr, pg, pb)));
}
}
}

View file

@ -1,4 +1,3 @@
use std::path::PathBuf;
use tracing::{info, warn};
@ -241,9 +240,7 @@ impl App {
Ok(local) => {
let agents = local.list_agents().await;
let repo = if let Ok(list) = &agents {
if let Some(a) = list.iter().find(|a| a.name == self.agent_pref || a.id == self.agent_pref).or_else(|| list.first()) {
Some(local.server_agents().memory_repo(&a.id))
} else { None }
list.iter().find(|a| a.name == self.agent_pref || a.id == self.agent_pref).or_else(|| list.first()).map(|a| local.server_agents().memory_repo(&a.id))
} else { None };
(agents, "local", repo)
}
@ -262,9 +259,7 @@ impl App {
// Pull a MemoryRepo for the current agent (if it exists)
// through the LocalBackend's server inventory.
let repo = if let Ok(list) = &agents {
if let Some(a) = list.iter().find(|a| a.name == self.agent_pref || a.id == self.agent_pref).or_else(|| list.first()) {
Some(local.server_agents().memory_repo(&a.id))
} else { None }
list.iter().find(|a| a.name == self.agent_pref || a.id == self.agent_pref).or_else(|| list.first()).map(|a| local.server_agents().memory_repo(&a.id))
} else { None };
(agents, "local", repo)
}

View file

@ -9,7 +9,6 @@ use ratatui::{
use ratatui_image::{Resize, StatefulImage};
use super::{App, AgentCard, short_id};
use crate::ui::presence::Posture;
use crate::core::config::ConsciousnessConfig;
impl App {

View file

@ -24,10 +24,9 @@ use std::time::{Duration, Instant};
use ratatui::{
backend::CrosstermBackend,
Terminal,
layout::{Alignment, Constraint, Direction, Layout, Rect},
style::{Color, Modifier, Style},
text::{Line, Span},
widgets::{Block, BorderType, Borders, Gauge, List, ListItem, Paragraph, Wrap},
layout::Alignment,
style::{Modifier, Style},
widgets::Paragraph,
Frame,
};
use crossterm::{
@ -36,23 +35,19 @@ use crossterm::{
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
use tokio::sync::RwLock;
use tracing::{info, warn};
use tracing::info;
use crate::core::config::ConsciousnessConfig;
use crate::ui::chat::{ChatState, draw as draw_chat};
use crate::ui::cockpit_panel::CockpitPane;
use crate::ui::health_panel::HealthPane;
use crate::ui::presence::{Posture, Presence};
use crate::ui::color_support::rgb;
use crate::ui::component::{Component, Scene, SceneLayout, TuiEvent};
use crate::ui::setup::SetupState;
use crate::backend::BackendEvent;
use crate::ui::settings::SettingsAction;
use ratatui_image::{picker::Picker, protocol::{Protocol, StatefulProtocol}, Resize, StatefulImage};
use ratatui_image::{picker::Picker, protocol::{Protocol, StatefulProtocol}};
#[cfg(feature = "figlet-rs")]
use figlet_rs::FIGlet;
pub struct App {
current_screen: Screen,

View file

@ -284,7 +284,7 @@ impl App {
let transcript_line = if is_listening {
transcript.map(|t| format!(" {} ", t)).unwrap_or_else(|| " listen ".to_string())
} else if is_speaking {
tts_display.map(|t| clip_to(&t, voice_area.width.saturating_sub(6) as usize))
tts_display.map(|t| clip_to(t, voice_area.width.saturating_sub(6) as usize))
.map(|c| format!("» {} «", c))
.unwrap_or_else(|| " speak ".to_string())
} else if let Some(t) = tts_display {
@ -313,7 +313,7 @@ impl App {
if is_listening {
let level = self.voice_capture.as_ref().map(|c| c.current_level()).unwrap_or(0.0);
let is_recording = level > 0.05;
let rec_glyph = if is_recording && self.tick % 2 == 0 { "● REC" } else { " rec" };
let rec_glyph = if is_recording && self.tick.is_multiple_of(2) { "● REC" } else { " rec" };
let mut wave_spans: Vec<Span> = Vec::new();
let bar_w = (voice_area.width.saturating_sub(10)).min(128) as usize;
@ -341,7 +341,7 @@ impl App {
))), wave_area);
} else {
let ghost: String = "▁▂▃▄▅▆▇█▇▆▅▄▃▂".chars()
.flat_map(|c| std::iter::repeat(c).take(3))
.flat_map(|c| std::iter::repeat_n(c, 3))
.take(voice_area.width as usize)
.collect();
let (ghost_r, ghost_g, ghost_b) = match palette.bg { Color::Rgb(r, g, b) => (r, g, b), _ => (40, 44, 60) };

View file

@ -12,8 +12,10 @@ use ratatui::style::Color;
/// Named atmospheric preset. The `Default` variant uses ANI_PRIMARY etc.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Default)]
pub enum Atmosphere {
/// Harness defaults — warm orange (#FF8C42 family).
#[default]
Default,
/// Calm greens and teals.
MintTea,
@ -200,8 +202,3 @@ impl Atmosphere {
}
}
impl Default for Atmosphere {
fn default() -> Self {
Atmosphere::Default
}
}

View file

@ -1,7 +1,5 @@
use std::cell::RefCell;
use std::time::Instant;
use anyhow::Result;
use futures::StreamExt;
use tokio::sync::oneshot;
use tokio_util::sync::CancellationToken;
@ -12,7 +10,7 @@ use crate::backend::{Backend, BackendEvent};
use crate::core::config::ConsciousnessConfig;
use super::{
BtwForkEvent, BtwState, ChatMessage, ChatMode, ChatState, ImageAttachment, TurnPhase,
ChatMessage, ChatMode, ChatState, ImageAttachment, TurnPhase,
};
impl ChatState {
@ -427,7 +425,7 @@ Tab toggles the cockpit pane. `t` (on empty input) toggles tool expansion.";
all_models.len()
);
for m in &all_models {
let marker = if bifrost_models.contains(&m) { "" } else { "" };
let marker = if bifrost_models.contains(m) { "" } else { "" };
text.push_str(&format!(" {} {}\n", marker, m));
}
text

View file

@ -9,7 +9,7 @@ use crate::backend::BackendEvent;
use super::{
BtwForkEvent, BtwState, ChatMessage, ChatState, CockpitEntry, CockpitKind,
ImageAttachment, MsgLayout, Overlay, SlashDef, ToolResultBlock, TurnPhase, SLASH_COMMANDS,
ImageAttachment, Overlay, SlashDef, ToolResultBlock, TurnPhase, SLASH_COMMANDS,
};
impl ChatState {
@ -290,7 +290,7 @@ impl ChatState {
self.tool_calls_this_turn = self.tool_calls_this_turn.saturating_add(1);
if !self.thinking.is_empty() {
let sep = format!("──── r{} ────", round);
let last_is_sep = self.thinking.last().map_or(false, |s| s.starts_with("────"));
let last_is_sep = self.thinking.last().is_some_and(|s| s.starts_with("────"));
if !last_is_sep {
self.thinking.push(sep);
}
@ -610,7 +610,7 @@ impl ChatState {
img.write_to(&mut png_buf, image::ImageFormat::Png)
.map_err(|e| format!("png encode: {e}"))?;
let b64 = base64::engine::general_purpose::STANDARD.encode(png_buf.into_inner());
let file_size = (width * height * 4) as usize;
let file_size = (width * height * 4);
Ok(ImageAttachment {
label: String::new(), // set below
media_type: "image/png".to_string(),

View file

@ -23,7 +23,6 @@ pub mod tool_renderers;
pub mod wrap;
pub use render::draw;
pub use footer::short;
use std::cell::{Cell, RefCell};
use std::sync::Arc;
@ -130,15 +129,15 @@ impl ChatPalette {
apr.wrapping_mul(31)
.wrapping_add(apg).wrapping_mul(37)
.wrapping_add(apb).wrapping_mul(41)
.wrapping_add(upr as u64).wrapping_mul(43)
.wrapping_add(upg as u64).wrapping_mul(47)
.wrapping_add(upb as u64).wrapping_mul(53)
.wrapping_add(tar as u64).wrapping_mul(59)
.wrapping_add(tag as u64).wrapping_mul(61)
.wrapping_add(tab as u64).wrapping_mul(67)
.wrapping_add(sur as u64).wrapping_mul(71)
.wrapping_add(sug as u64).wrapping_mul(73)
.wrapping_add(sub as u64).wrapping_mul(79)
.wrapping_add(upr).wrapping_mul(43)
.wrapping_add(upg).wrapping_mul(47)
.wrapping_add(upb).wrapping_mul(53)
.wrapping_add(tar).wrapping_mul(59)
.wrapping_add(tag).wrapping_mul(61)
.wrapping_add(tab).wrapping_mul(67)
.wrapping_add(sur).wrapping_mul(71)
.wrapping_add(sug).wrapping_mul(73)
.wrapping_add(sub).wrapping_mul(79)
}
}

View file

@ -4,7 +4,7 @@ use ratatui::{
layout::{Alignment, Constraint, Direction, Layout, Rect},
style::{Color, Modifier, Style},
text::{Line, Span},
widgets::{Block, BorderType, Borders, Paragraph, Wrap},
widgets::{Block, BorderType, Borders, Paragraph},
Frame,
};
@ -145,7 +145,7 @@ fn draw_phase(f: &mut Frame, state: &ChatState, area: Rect) {
let mut spans: Vec<Span<'static>> = vec![
Span::styled(format!(" {} ", glyph), Style::default().fg(color).add_modifier(Modifier::BOLD)),
Span::styled(format!("{}", label), Style::default().fg(color)),
Span::styled(label.to_string(), Style::default().fg(color)),
Span::styled(format!(" · {}s", elapsed), Style::default().fg(state.palette.agent_dim)),
];
if let Some(liveness_label) = liveness {
@ -608,7 +608,7 @@ fn draw_messages(f: &mut Frame, state: &ChatState, area: Rect) {
lines.push(Line::from(""));
}
ChatMessage::Image { media_type, label, dimensions, .. } => {
let dim_str = dimensions.map(|(w,h)| format!("{}x{}", w, h)).unwrap_or_default();
let _dim_str = dimensions.map(|(w,h)| format!("{}x{}", w, h)).unwrap_or_default();
lines.push(Line::from(vec![
Span::raw(" "),
Span::styled("🖼", Style::default().fg(state.palette.user_accent)),
@ -990,7 +990,7 @@ fn draw_input(f: &mut Frame, state: &ChatState, area: Rect) {
.border_type(BorderType::Rounded)
.border_style(Style::default().fg(border_color));
let cursor_visible = (state.tick / 5) % 2 == 0;
let cursor_visible = (state.tick / 5).is_multiple_of(2);
let cursor_ch: &str = if cursor_visible { "" } else { " " };
let inner_width = (area.width as usize).saturating_sub(5).max(1);
@ -1014,7 +1014,7 @@ fn draw_input(f: &mut Frame, state: &ChatState, area: Rect) {
let char_offset = ll[..cursor_byte_remaining].chars().count();
let chunks = wrap_input_line(&chars, inner_width);
let mut consumed = 0;
for (pos, &(cs, ce)) in chunks.iter().enumerate() {
for (_pos, &(cs, ce)) in chunks.iter().enumerate() {
if char_offset < consumed + (ce - cs) || char_offset == consumed && (ce - cs) == 0 {
cursor_visual_line = Some((li, consumed + cs + (char_offset - consumed)));
break;
@ -1023,7 +1023,7 @@ fn draw_input(f: &mut Frame, state: &ChatState, area: Rect) {
}
// If cursor is at the very end of the logical line, it's on the last chunk.
if cursor_visual_line.is_none() && !chunks.is_empty() {
let last = chunks.len() - 1;
let _last = chunks.len() - 1;
cursor_visual_line = Some((li, ll.len()));
}
break;

View file

@ -5,7 +5,7 @@
//! key:value dumps.
use ratatui::{
style::{Color, Modifier, Style},
style::{Modifier, Style},
text::{Line, Span},
};
use serde_json::Value;
@ -361,13 +361,13 @@ pub fn render_card_body(
// Fallback: markdown-rendered preview (existing behavior)
if let Some(out) = output {
let preview = preview_lines(out, 12);
let rendered = crate::ui::markdown::render_with_width(
crate::ui::markdown::render_with_width(
&preview,
fg_color,
Some(inner_width),
&mdpal,
);
rendered
)
} else {
Vec::new()
}
@ -386,8 +386,8 @@ fn render_bash_body(
let mut lines: Vec<Line<'static>> = Vec::new();
// ┌─ header
let top = format!("┌─ bash output ");
let top_dashes = inner_width.saturating_sub(top.chars().count()).max(0);
let top = "┌─ bash output ".to_string();
let top_dashes = inner_width.saturating_sub(top.chars().count());
let top_line = Line::from(Span::styled(
format!("{}{}", top, "".repeat(top_dashes)),
Style::default().fg(dim).add_modifier(Modifier::DIM),
@ -461,7 +461,7 @@ fn render_read_body(
// monospace look in the tool card.
let mut lines: Vec<Line<'static>> = Vec::new();
let header = format!("┌─ {} ", lang_label);
let dashes = _inner_width.saturating_sub(header.chars().count()).max(0);
let dashes = _inner_width.saturating_sub(header.chars().count());
lines.push(Line::from(Span::styled(
format!("{}{}", header, "".repeat(dashes)),
dim_style,
@ -495,7 +495,7 @@ fn render_grep_body(
output: &str,
inner_width: usize,
palette: &ChatPalette,
mdpal: &crate::ui::markdown::MarkdownPalette,
_mdpal: &crate::ui::markdown::MarkdownPalette,
) -> Vec<Line<'static>> {
let dim = palette.tool_dim;
let mut lines: Vec<Line<'static>> = Vec::new();
@ -611,7 +611,7 @@ fn render_write_body(
let mut lines: Vec<Line<'static>> = Vec::new();
// Header with path and output summary
let header = format!("┌─ {} ", if path.is_empty() { "write" } else { &path });
let dashes = inner_width.saturating_sub(header.chars().count()).max(0);
let dashes = inner_width.saturating_sub(header.chars().count());
lines.push(Line::from(Span::styled(
format!("{}{}", header, "".repeat(dashes)),
Style::default().fg(dim).add_modifier(Modifier::DIM),
@ -644,7 +644,7 @@ fn render_edit_body(
// Header with path
let header = format!("┌─ edit{} ", if path.is_empty() { "" } else { ":" });
let label = format!("{}{}", header, &path);
let dashes = inner_width.saturating_sub(label.chars().count()).max(0);
let dashes = inner_width.saturating_sub(label.chars().count());
lines.push(Line::from(Span::styled(
format!("{}{}", label, "".repeat(dashes)),
Style::default().fg(dim).add_modifier(Modifier::DIM),
@ -675,8 +675,8 @@ fn render_memory_body(
let mut lines: Vec<Line<'static>> = Vec::new();
// Header
let header = format!("┌─ memory ");
let dashes = inner_width.saturating_sub(header.chars().count()).max(0);
let header = "┌─ memory ".to_string();
let dashes = inner_width.saturating_sub(header.chars().count());
lines.push(Line::from(Span::styled(
format!("{}{}", header, "".repeat(dashes)),
Style::default().fg(dim).add_modifier(Modifier::DIM),

View file

@ -41,7 +41,7 @@ impl MarkdownPalette {
let b = |c: Color| -> u8 { match c { Color::Rgb(_, _, b) => b, _ => 0 } };
let bg = cpal.bg;
Self {
code_bg: Color::Rgb(r(bg).saturating_add(22).min(255), g(bg).saturating_add(22).min(255), b(bg).saturating_add(34).min(255)),
code_bg: Color::Rgb(r(bg).saturating_add(22), g(bg).saturating_add(22), b(bg).saturating_add(34)),
code_fg: Color::Rgb(pr.max(160), pg.max(160), pb.max(200)),
link_dim: Color::Rgb((pr / 3).saturating_add(100).min(220), (pg / 3).saturating_add(120).min(220), (pb / 2).saturating_add(100).min(220)),
quote_bar: Color::Rgb((pr / 3).saturating_add(80).min(200), (pg / 3).saturating_add(70).min(180), (pb / 2).saturating_add(80).min(200)),

View file

@ -105,9 +105,9 @@ fn color_for(key: char, posture: Posture, breath: f32) -> Option<Color> {
// Subtle pulse on cyan elements driven by breath.
let cyan_lum = (170.0 + breath * 60.0).clamp(120.0, 235.0) as u8;
let cyan_lum = if processing { cyan_lum.saturating_add(25).min(255) } else { cyan_lum };
let cyan_lum = if processing { cyan_lum.saturating_add(25) } else { cyan_lum };
// Alert: eyes brighter (the room just came into focus).
let cyan_lum = if alert { cyan_lum.saturating_add(15).min(255) } else { cyan_lum };
let cyan_lum = if alert { cyan_lum.saturating_add(15) } else { cyan_lum };
// Thinking: gaze narrows inward — cyan goes cooler and dimmer.
let cyan_lum = if thinking { cyan_lum.saturating_sub(40) } else { cyan_lum };
@ -191,8 +191,8 @@ pub fn render_scaled(buf: &mut Buffer, area: Rect, p: &Presence, scale: u16) {
if col.is_none() { continue; }
let col = col.unwrap();
let cx0 = area.x + (px as u16) * cell_w;
let cy0 = area.y + ((py / 2) as u16) * cell_h;
let cx0 = area.x + px * cell_w;
let cy0 = area.y + (py / 2) * cell_h;
for dx in 0..cell_w {
for dy in 0..cell_h {
let x = cx0 + dx;

View file

@ -405,7 +405,7 @@ impl Presence {
}
if self.eye == Eye::Blinking && *t >= self.blink_until {
self.eye = Eye::Open;
let jitter = (*t % 60) as u64;
let jitter = (*t % 60);
self.next_blink_at = *t + 180 + jitter;
} else if self.eye == Eye::Open && *t >= self.next_blink_at {
self.eye = Eye::Blinking;
@ -414,7 +414,7 @@ impl Presence {
// Breath: 8-15 s jittered interval, 2 s hold (Godot parity).
if self.is_breathing && *t >= self.breath_until {
self.is_breathing = false;
let jitter = (*t % 120) as u64;
let jitter = (*t % 120);
self.next_breath_at = *t + 480 + jitter; // 8-15 s
} else if !self.is_breathing && *t >= self.next_breath_at {
self.is_breathing = true;

View file

@ -183,7 +183,7 @@ impl AgentsScreen {
let first_agent = agents.first().cloned();
// ── Wide layout: list left, detail right ──────────────────────────
let mut list_wide = build_list(&rows, palette);
let list_wide = build_list(&rows, palette);
let list_wide_id = list_wide.get_id();
let (detail_wide_pane, detail_wide_ids) = build_detail_pane(palette, first_agent.as_ref());
@ -205,7 +205,7 @@ impl AgentsScreen {
.children([list_col as Box<dyn Widget>, detail_wide_pane]);
// ── Narrow layout: list top, detail bottom ───────────────────────
let mut list_narrow = build_list(&rows, palette);
let list_narrow = build_list(&rows, palette);
let list_narrow_id = list_narrow.get_id();
let (detail_narrow_pane, detail_narrow_ids) = build_detail_pane(palette, first_agent.as_ref());
@ -576,7 +576,6 @@ fn build_detail_pane(palette: &ChatPalette, agent: Option<&AgentSummary>) -> (Bo
let ag = agent.unwrap_or(&default_agent);
let mut name_content = StyledString::new();
name_content.push_span(StyledStr::new("HARDCODED:").fg(primary).bold());
name_content.push_span(StyledStr::new(&ag.glyph).fg(primary));
name_content.push_span(StyledStr::new(&format!(" {}", ag.name)).fg(primary).bold());
let name = Text::new().content(name_content);
@ -646,6 +645,14 @@ fn build_detail_pane(palette: &ChatPalette, agent: Option<&AgentSummary>) -> (Bo
.children([
portrait_pane as Box<dyn Widget>,
name as Box<dyn Widget>,
description as Box<dyn Widget>,
primary_badge as Box<dyn Widget>,
instances as Box<dyn Widget>,
uptime as Box<dyn Widget>,
files as Box<dyn Widget>,
pubkey as Box<dyn Widget>,
activity_header as Box<dyn Widget>,
activity_lines as Box<dyn Widget>,
]);
let section_id = section.get_id();
@ -761,8 +768,8 @@ mod tests {
let term = Emulator::new(&mut *screen, Vec2::new(120, 30));
let rendered = term.get_snapshot_text();
assert!(
rendered.contains("HARDCODED"),
"expected 'HARDCODED' in detail pane, got: {rendered:?}"
rendered.contains("PRIMARY"),
"expected 'PRIMARY' badge in detail pane, got: {rendered:?}"
);
}

View file

@ -575,11 +575,7 @@ impl ChatScreen {
let Some(chat) = self.chat.as_ref() else { return };
match &chat.overlay {
Overlay::SlashComplete { selected, matches } => {
if let Some(cmd) = matches.get(*selected) {
Some(cmd.name.to_string())
} else {
None
}
matches.get(*selected).map(|cmd| cmd.name.to_string())
}
Overlay::ConversationPicker { selected, conversations } => {
conversations.get(*selected).map(|c| c.id.clone())
@ -947,7 +943,7 @@ impl ChatScreen {
if !self.pending_messages.contains(&text) {
self.pending_messages.push(text);
self.set_messages(vec![MsgKind::System {
text: format!("\u{2192} waiting for connection..."),
text: "\u{2192} waiting for connection...".to_string(),
}]);
tuie::dirty_paint();
}

View file

@ -50,11 +50,8 @@ use crate::ui::settings::SettingsView;
use crate::ui::theme;
use crate::ui::widgets::accordion::Accordion;
use crate::ui::widgets::button::Button;
use crate::ui::widgets::checkbox::Checkbox;
use crate::ui::widgets::counter::Counter;
use crate::ui::widgets::page_layout::PageLayout;
use crate::ui::widgets::segmented_control::SegmentedControl;
use crate::ui::widgets::focus_pane::FocusPane;
use actions::SettingsAction;
use field_grid::FieldGrid;
@ -508,7 +505,7 @@ impl SettingsScreen {
}
}
fn try_cycle_enum(&self, loc: FieldLoc, delta: i32) -> bool {
fn try_cycle_enum(&self, loc: FieldLoc, _delta: i32) -> bool {
let fields = self.view.fields_for_category(self.view.selected_category());
if let Some((_, EditableValue::EnumVariant { .. })) = fields.iter().find(|(l, _)| *l == loc) {
true
@ -523,10 +520,10 @@ impl SettingsScreen {
let Some((_, value)) = fields.iter().find(|(l, _)| *l == loc) else { return };
match value {
EditableValue::Bool(b) => {
EditableValue::Bool(_b) => {
self.enqueue(SettingsAction::ToggleBool(loc));
}
EditableValue::EnumVariant { index, variants } => {
EditableValue::EnumVariant { index: _, variants } => {
if variants.len() > 6 {
// Open model picker sub-page for large variant lists.
self.enqueue(SettingsAction::OpenModelPicker(loc));
@ -1162,26 +1159,35 @@ mod tests {
}
/// Switching categories must swap the right-hand field grid. "virtual key"
/// is a Bifrost-only field label that never appears in the Agent category
/// is a Providers-only field label that never appears in the Agent category
/// or the left category list, so it's a clean signal the grid rebuilt.
/// Uses the narrow (<80 col) layout because the wide layout's accordion
/// expands via a scheduler-driven animation that doesn't advance under
/// `Emulator`, which would clip the body to one row.
/// (Regression: rebuild() used to discard the new fields entirely.)
#[test]
fn category_change_swaps_field_grid() {
let mut s = screen();
let buffer = Rc::new(RefCell::new(None));
let mut config = crate::core::config::ConsciousnessConfig::default();
config.providers.insert(
"testbf".into(),
crate::core::config::ProviderConfig {
provider_type: "openai-compatible".into(),
base_url: "http://localhost:8080/v1".into(),
api_key: String::new(),
virtual_key: "vk-test".into(),
primary_model: String::new(),
timeout_secs: 30,
},
);
let mut s = SettingsScreen::new(&config, std::path::PathBuf::from("souveraine.toml"), buffer);
let mut term = Emulator::new(&mut *s, Vec2::new(60, 40));
assert!(
!term.get_snapshot_text().contains("virtual key"),
"Agent category should not show Bifrost's virtual key field"
"Agent category should not show Providers virtual key field"
);
// Agent(0) -> Inference(1) -> Bifrost(2).
// Agent(0) -> Inference(1) -> Providers(2).
term.update(&mut *s, &[down(), down()]);
assert_eq!(s.cat_idx, 2, "expected to land on Bifrost");
assert_eq!(s.cat_idx, 2, "expected to land on Providers");
assert!(
term.get_snapshot_text().contains("virtual key"),
"Bifrost category should render its fields after navigating"
"Providers category should render its fields after navigating"
);
}

View file

@ -378,7 +378,7 @@ fn render_bloom(ctx: &mut RenderContext, w: u16, h: u16, state: &BloomState, tic
row_w.cell(0)
.glyph('⬟')
.style(&Style::new().fg(Color::Rgb(
pr.min(255), pg.min(255), pb.min(255),
pr, pg, pb,
)).bg(Color::BLACK));
}
}

View file

@ -358,7 +358,7 @@ fn build_stat_row(palette: &ChatPalette, status: &AgentStatus) -> Box<dyn Widget
};
let bar = {
let filled = (status.energy as usize + 19) / 20; // 0..5
let filled = (status.energy as usize).div_ceil(20); // 0..5
let filled = filled.min(5);
format!(
"{}{}",

View file

@ -6,7 +6,7 @@ use ratatui::{
Frame,
};
use super::types::{Category, FieldLoc, SettingsMode, PanelFocus};
use super::types::{Category, SettingsMode, PanelFocus};
use super::view::SettingsView;
// ── Drawing ─────────────────────────────────────────────────────────────────

View file

@ -9,7 +9,7 @@ mod view;
mod key_handling;
mod draw;
pub use types::{PanelFocus, Category, CategoryGroup, FieldLoc, EditableValue, SettingsMode};
pub use types::{Category, CategoryGroup, FieldLoc, EditableValue, SettingsMode};
pub use view::{ActiveAgentSettings, SettingsView};
pub use key_handling::SettingsAction;
pub use draw::draw;

View file

@ -482,7 +482,7 @@ impl SetupState {
pub fn build_create_request(&self) -> CreateAgentRequest {
CreateAgentRequest {
name: self.agent_name.clone(),
description: Some(format!("Created by Souveraine setup wizard")),
description: Some("Created by Souveraine setup wizard".to_string()),
llm_config: LlmConfig {
model: self.model_handle.clone(),
context_window: 128000,

View file

@ -35,6 +35,7 @@ use crate::ui::presence::Posture;
/// Supersedes both the lossy `(String, String, String)` tuples that
/// `AgentStatus` used to carry and `manager::AgentProcessInfo`.
#[derive(Debug, Clone)]
#[derive(Default)]
pub struct AgentSummary {
pub id: String,
pub name: String,
@ -57,23 +58,6 @@ pub struct AgentSummary {
pub recent_activity: Vec<String>,
}
impl Default for AgentSummary {
fn default() -> Self {
Self {
id: String::new(),
name: String::new(),
description: String::new(),
glyph: String::new(),
instance_count: 0,
uptime_pct: 0,
memory_count: 0,
pubkey_prefix: String::new(),
is_primary: false,
atmosphere: None,
recent_activity: Vec::new(),
}
}
}
// ── Agent status ───────────────────────────────────────────────────────────────
@ -811,7 +795,7 @@ async fn load_dashboard_data(
let available_agents: Vec<AgentSummary> = agents
.iter()
.map(|a| AgentSummary::from_agent_info(a))
.map(AgentSummary::from_agent_info)
.collect();
return AgentStatus {

View file

@ -27,9 +27,9 @@ impl MarkdownPalette {
};
Self {
code_bg: Color::Rgb(
br.saturating_add(22).min(255),
bg_g.saturating_add(22).min(255),
bb.saturating_add(34).min(255),
br.saturating_add(22),
bg_g.saturating_add(22),
bb.saturating_add(34),
),
code_fg: Color::Rgb(pr.max(160), pg.max(160), pb.max(200)),
link_dim: Color::Rgb(

View file

@ -152,7 +152,7 @@ impl ChatBubble {
.unwrap_or(0);
let body_w = if let Some(styled) = &self.body_styled {
styled.as_str().split('\n')
.map(|l| unicode_display_width(l))
.map(unicode_display_width)
.max()
.unwrap_or(0)
} else {
@ -177,7 +177,7 @@ impl ChatBubble {
(self.container_width as usize).saturating_sub(outer) / 2
}
};
" ".repeat(pad.max(0))
" ".repeat(pad)
}
// ── Rebuild ──────────────────────────────────────────────────────────────

View file

@ -44,7 +44,7 @@ pub fn get_input_text(input: &Input) -> String {
/// Get the current text from an Input stored in a pane tree.
pub fn read_input_text(root: &dyn Widget, input_id: WidgetId<Input>) -> String {
root.get_widget(input_id)
.map(|input| get_input_text(input))
.map(get_input_text)
.unwrap_or_default()
}

View file

@ -106,19 +106,19 @@ impl ChatSidebar {
.border_style(Style::new().fg(primary).dim())
.children([
Text::new().content(title) as Box<dyn Widget>,
Text::new().content(dim_text.clone()).id(&mut name_id),
Text::new().content(dim_text.clone()).id(&mut mood_id),
Text::new().content(dim_text.clone()).id(&mut energy_id),
Text::new().content(dim_text.clone()).id(&mut pressure_id),
Text::new().content(dim_text.clone()).id(&mut n1_id),
Text::new().content(dim_text.clone()).id(&mut commits_id),
Text::new().content(dim_text.clone()).id(&mut tasks_id),
Text::new().content(dim_text.clone()).id(&mut backend_id),
Text::new().content(dim_text.clone()).id(&mut n25_id),
Text::new().content(dim_text.clone()).id(&mut n100_id),
Text::new().content(dim_text.clone()).id(&mut compaction_id),
Text::new().content(dim_text.clone()).id(&mut strain_id),
Text::new().content(dim_text.clone()).id(&mut uptime_id),
Text::new().content(dim_text).id(&mut name_id),
Text::new().content(dim_text).id(&mut mood_id),
Text::new().content(dim_text).id(&mut energy_id),
Text::new().content(dim_text).id(&mut pressure_id),
Text::new().content(dim_text).id(&mut n1_id),
Text::new().content(dim_text).id(&mut commits_id),
Text::new().content(dim_text).id(&mut tasks_id),
Text::new().content(dim_text).id(&mut backend_id),
Text::new().content(dim_text).id(&mut n25_id),
Text::new().content(dim_text).id(&mut n100_id),
Text::new().content(dim_text).id(&mut compaction_id),
Text::new().content(dim_text).id(&mut strain_id),
Text::new().content(dim_text).id(&mut uptime_id),
]);
Box::new(Self {

View file

@ -26,7 +26,7 @@ impl DelegateWidget for GlobalChords {
}
chord!(Ctrl + z) => {
queue.next();
let _ = tuie::suspend();
tuie::suspend();
}
#[cfg(feature = "gui")]
chord!(Ctrl + Char('+')) => {

View file

@ -25,7 +25,7 @@ impl DelegateWidget for ItineraryStrip {
impl ItineraryStrip {
/// Create a hidden strip. Call `set_line` to show content.
pub fn new(palette: &ChatPalette) -> Box<Self> {
let color = theme::to_tuie_color(palette.agent_dim);
let _color = theme::to_tuie_color(palette.agent_dim);
let content = StyledString::new();
let mut text = Text::new().content(content);

View file

@ -151,7 +151,7 @@ impl Widget for Responsive {
) -> Option<WidgetId> {
// Focus traversal only ever sees the active arrangement.
let child = self.active();
if let Some(found) = child.find_descendant(predicate, path.as_mut().map(|p| &mut **p)) {
if let Some(found) = child.find_descendant(predicate, path.as_deref_mut()) {
if let Some(p) = &mut path {
p.push(child.get_id());
}
@ -176,7 +176,7 @@ impl Widget for Responsive {
return None;
}
let hit = child
.descendant_at_pos(pos, path.as_mut().map(|p| &mut **p))
.descendant_at_pos(pos, path.as_deref_mut())
.unwrap_or_else(|| child.get_id());
if let Some(p) = &mut path {
p.push(child.get_id());
@ -195,7 +195,7 @@ impl Widget for Responsive {
return None;
}
if let Some(found) =
child.find_descendant_at_pos(pos, predicate, path.as_mut().map(|p| &mut **p))
child.find_descendant_at_pos(pos, predicate, path.as_deref_mut())
{
if let Some(p) = &mut path {
p.push(child.get_id());