fix: livrable tickets #70 #100 #102 — UX surface scoping

- #70: implémentation suppression modèles locaux téléchargés
- #100: correction scroll OpenCode
- #102: correction fit TUI après switch/layout
- memory note scoping UX
This commit is contained in:
2026-07-26 19:42:06 +02:00
parent 4321d048ac
commit 02603441c1
31 changed files with 1589 additions and 152 deletions

View File

@ -64,6 +64,11 @@ pub trait LiveAgentRegistry: Send + Sync {
/// be keyed on the hosting node, not the agent (otherwise a duplicate leaf
/// would be wrongly marked as still running).
fn is_node_live(&self, node_id: &NodeId) -> bool;
/// Snapshots every live agent session currently known by this registry.
fn live_agent_snapshots(&self) -> Vec<LiveSessionSnapshot> {
Vec::new()
}
}
/// In-memory registry of active terminal sessions.
@ -89,6 +94,26 @@ impl LiveAgentRegistry for TerminalSessions {
.map(|m| m.values().any(|e| e.session.node_id == *node_id))
.unwrap_or(false)
}
fn live_agent_snapshots(&self) -> Vec<LiveSessionSnapshot> {
self.entries
.lock()
.map(|m| {
m.values()
.filter_map(|e| match e.session.kind {
SessionKind::Agent { agent_id } => Some(LiveSessionSnapshot {
project_id: e.project_id,
agent_id,
node_id: e.session.node_id,
session_id: e.session.id,
kind: LiveSessionKind::Pty,
}),
SessionKind::Plain => None,
})
.collect()
})
.unwrap_or_default()
}
}
impl TerminalSessions {
@ -426,6 +451,23 @@ impl LiveAgentRegistry for StructuredSessions {
.map(|m| m.values().any(|e| e.node_id == *node_id))
.unwrap_or(false)
}
fn live_agent_snapshots(&self) -> Vec<LiveSessionSnapshot> {
self.entries
.lock()
.map(|m| {
m.values()
.map(|e| LiveSessionSnapshot {
project_id: e.project_id,
agent_id: e.agent_id,
node_id: e.node_id,
session_id: e.session.id(),
kind: LiveSessionKind::Structured,
})
.collect()
})
.unwrap_or_default()
}
}
impl StructuredSessions {
@ -819,42 +861,8 @@ impl LiveSessions {
/// Tous les agents vivants avec le type de registre source (PTY puis structuré).
#[must_use]
pub fn live_agent_snapshots(&self) -> Vec<LiveSessionSnapshot> {
let mut all: Vec<LiveSessionSnapshot> = self
.pty
.entries
.lock()
.map(|m| {
m.values()
.filter_map(|e| match e.session.kind {
SessionKind::Agent { agent_id } => Some(LiveSessionSnapshot {
project_id: e.project_id,
agent_id,
node_id: e.session.node_id,
session_id: e.session.id,
kind: LiveSessionKind::Pty,
}),
SessionKind::Plain => None,
})
.collect()
})
.unwrap_or_default();
all.extend(
self.structured
.entries
.lock()
.map(|m| {
m.values()
.map(|e| LiveSessionSnapshot {
project_id: e.project_id,
agent_id: e.agent_id,
node_id: e.node_id,
session_id: e.session.id(),
kind: LiveSessionKind::Structured,
})
.collect::<Vec<_>>()
})
.unwrap_or_default(),
);
let mut all = self.pty.live_agent_snapshots();
all.extend(self.structured.live_agent_snapshots());
all
}
}
@ -868,4 +876,8 @@ impl LiveAgentRegistry for LiveSessions {
fn is_node_live(&self, node_id: &NodeId) -> bool {
self.pty.is_node_live(node_id) || self.structured.is_node_live(node_id)
}
fn live_agent_snapshots(&self) -> Vec<LiveSessionSnapshot> {
LiveSessions::live_agent_snapshots(self)
}
}