Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .agents/agent-console.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ conversation/execution timeline.
rows and tabs. Selecting an actually visible session marks it read and
restores its context and composer draft; hidden selection is navigation
identity only.
- The Agents navigator includes every remote session in the authenticated
Platform directory, including observation-only and stale sessions, without
requiring a local checkout mapping. Reuse Fleet's typed directory and retained
cockpit; refresh it while Agents is visible. Remote selection keeps local
sessions hidden for unread accounting and never attaches or claims control
implicitly. Account reset clears the shared directory.
- Treat provider, target, permissions, workdir, and model as one execution
context, collapsed into the compact session header by default.
- Change execution context through the core context setter so an opaque resume
Expand Down
4 changes: 4 additions & 0 deletions crates/shelldeck-core/locales/en.toml
Original file line number Diff line number Diff line change
Expand Up @@ -1167,6 +1167,10 @@ user.monique.recent_activity = "Recent activity"
user.github_issue = "GitHub #%{number}"
fleet.title = "Platform cockpit"
fleet.refresh = "Refresh"
agents.remote.title = "Remote sessions"
agents.remote.loading = "Loading sessions…"
agents.remote.unavailable = "This remote session is no longer available."
agents.remote.cannot_observe = "Observation is unavailable for this session."
fleet.metric.resources = "%{count} resources"
fleet.metric.sessions = "%{count} sessions"
fleet.metric.models = "%{count} models"
Expand Down
4 changes: 4 additions & 0 deletions crates/shelldeck-core/locales/fr.toml
Original file line number Diff line number Diff line change
Expand Up @@ -1167,6 +1167,10 @@ user.monique.recent_activity = "Activité récente"
user.github_issue = "GitHub #%{number}"
fleet.title = "Poste de contrôle plateforme"
fleet.refresh = "Actualiser"
agents.remote.title = "Sessions distantes"
agents.remote.loading = "Chargement des sessions…"
agents.remote.unavailable = "Cette session distante n’est plus disponible."
agents.remote.cannot_observe = "L’observation n’est pas disponible pour cette session."
fleet.metric.resources = "%{count} ressources"
fleet.metric.sessions = "%{count} sessions"
fleet.metric.models = "%{count} modèles"
Expand Down
22 changes: 19 additions & 3 deletions crates/shelldeck-ui/src/agent_console_view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ mod model;
mod navigator;
#[path = "agent_console_view/progress.rs"]
mod progress;
#[path = "agent_console_view/remote_sessions.rs"]
mod remote_sessions;
use live_input::PendingLiveInput;
#[path = "agent_console_view/review.rs"]
mod review;
Expand Down Expand Up @@ -116,6 +118,8 @@ struct InspectorDiff {

#[derive(Debug, Clone)]
pub enum AgentConsoleEvent {
RefreshRemoteSessions,
OpenPlatformSession(shelldeck_core::config::platform::ResourceCoordinate),
SaveFile(AgentFileSaveRequest),
Run(AgentRunRequest),
Stop(Uuid),
Expand Down Expand Up @@ -286,6 +290,7 @@ pub struct AgentConsoleView {
model_discovery: model::AgentModelDiscoveryUi,
navigator_search: Entity<InputState>,
sessions: AgentSessionCollection,
remote_sessions: remote_sessions::RemoteAgentSessionsUi,
session_ui: HashMap<Uuid, AgentSessionUi>,
run_sessions: HashMap<Uuid, Uuid>,
foreground_runs: HashSet<Uuid>,
Expand Down Expand Up @@ -402,6 +407,7 @@ impl AgentConsoleView {
model_discovery: model::AgentModelDiscoveryUi::new(),
navigator_search: input_state(cx, String::new()),
sessions,
remote_sessions: remote_sessions::RemoteAgentSessionsUi::default(),
session_ui,
run_sessions: HashMap::new(),
foreground_runs: HashSet::new(),
Expand Down Expand Up @@ -704,7 +710,8 @@ impl AgentConsoleView {
}

pub fn run_requests_focus(&self, run_id: Uuid) -> bool {
self.foreground_runs.contains(&run_id)
!self.remote_sessions.active
&& self.foreground_runs.contains(&run_id)
&& self.run_sessions.get(&run_id).copied() == self.sessions.selected_id()
}

Expand Down Expand Up @@ -763,6 +770,7 @@ impl AgentConsoleView {
if self.sessions.select(session_id).is_err() {
return false;
}
self.set_remote_session_active(false, cx);
self.apply_selected_context(cx);
self.schedule_library_save(cx);
pin_to_latest(&self.scroll);
Expand All @@ -781,6 +789,7 @@ impl AgentConsoleView {
.create(name, context, now_ms())
.map_err(|error| error.to_string())?;
self.session_ui.insert(session_id, AgentSessionUi::new(cx));
self.set_remote_session_active(false, cx);
self.apply_selected_context(cx);
self.schedule_library_save(cx);
pin_to_latest(&self.scroll);
Expand All @@ -806,7 +815,11 @@ impl AgentConsoleView {
}

pub fn set_surface_visible(&mut self, visible: bool, cx: &mut Context<Self>) {
if self.sessions.set_surface_visible(visible) {
self.remote_sessions.surface_visible = visible;
if self
.sessions
.set_surface_visible(visible && !self.remote_sessions.active)
{
cx.notify();
}
}
Expand Down Expand Up @@ -1549,6 +1562,9 @@ impl AgentConsoleView {

impl Render for AgentConsoleView {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
if self.remote_sessions.active && self.remote_sessions.available {
return self.render_remote_session(cx);
}
if self.surface_focus_requested
&& self.pending_confirm.is_none()
&& self.workflows.dialog.is_none()
Expand Down Expand Up @@ -2129,7 +2145,7 @@ impl Render for AgentConsoleView {
.absolute()
.size_full(),
);
root
root.into_any_element()
}
}

Expand Down
12 changes: 7 additions & 5 deletions crates/shelldeck-ui/src/agent_console_view/navigator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ impl AgentConsoleView {
.map(|session| u64::from(session.unread_count))
.sum::<u64>();
let mut body = div().flex().flex_col().gap(px(4.0)).px(px(6.0)).py(px(7.0));
body = body.child(self.render_remote_session_rows(cx));
if self.project_groups.is_empty() {
body = body.child(self.render_session_rows(None, cx));
} else {
Expand Down Expand Up @@ -41,10 +42,11 @@ impl AgentConsoleView {
);
for worktree in &project.worktrees {
let worktree_option = worktree.clone();
let worktree_selected = self
.sessions
.selected()
.is_some_and(|session| session_worktree_matches(session, worktree));
let worktree_selected = !self.remote_sessions.active
&& self
.sessions
.selected()
.is_some_and(|session| session_worktree_matches(session, worktree));
body = body.child(
div()
.id(("agent-worktree", stable_string_key(&worktree.id)))
Expand Down Expand Up @@ -264,7 +266,7 @@ impl AgentConsoleView {
.filter(|session| include(session))
{
let id = session.id;
let selected = self.sessions.selected_id() == Some(id);
let selected = !self.remote_sessions.active && self.sessions.selected_id() == Some(id);
let removable = self.sessions.sessions().len() > 1 && !session.status.is_active();
let mut row = div()
.id(("agent-nav-session", uuid_key(id)))
Expand Down
Loading
Loading