aboutsummaryrefslogtreecommitdiff
path: root/src/app
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-05-17 01:41:17 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-05-17 01:41:17 +0300
commitf7fe0f203e0f349df33819aab239c0aade016f79 (patch)
tree51540d4a040a1a2d32ecf73c5c2d9277a7d4efef /src/app
parent3ecacfddae86d603bfd0d1a0c01602b1d34b1df3 (diff)
fix: polish terminal-core agent semantics
Diffstat (limited to 'src/app')
-rw-r--r--src/app/actions.rs14
-rw-r--r--src/app/agents.rs17
-rw-r--r--src/app/creation.rs7
-rw-r--r--src/app/input/mod.rs2
-rw-r--r--src/app/input/navigate.rs4
-rw-r--r--src/app/mod.rs17
-rw-r--r--src/app/runtime.rs5
-rw-r--r--src/app/terminal_targets.rs6
8 files changed, 52 insertions, 20 deletions
diff --git a/src/app/actions.rs b/src/app/actions.rs
index 27ca7474..faa5717d 100644
--- a/src/app/actions.rs
+++ b/src/app/actions.rs
@@ -693,18 +693,23 @@ impl AppState {
pub fn apply_workspace_git_statuses(&mut self, results: Vec<WorkspaceGitStatus>) -> bool {
let mut changed = false;
for result in results {
- let Some(ws) = self
+ let Some(ws_idx) = self
.workspaces
- .iter_mut()
- .find(|ws| ws.id == result.workspace_id)
+ .iter()
+ .position(|ws| ws.id == result.workspace_id)
else {
continue;
};
- if ws.resolved_identity_cwd().as_ref() != Some(&result.resolved_identity_cwd) {
+ if self.workspaces[ws_idx]
+ .resolved_identity_cwd_from(&self.terminals, &self.terminal_runtimes)
+ .as_ref()
+ != Some(&result.resolved_identity_cwd)
+ {
continue;
}
+ let ws = &mut self.workspaces[ws_idx];
if ws.cached_git_branch != result.branch {
ws.cached_git_branch = result.branch;
changed = true;
@@ -1050,6 +1055,7 @@ mod tests {
}
fn mark_agent(state: &mut AppState, ws_idx: usize, tab_idx: usize, pane_id: PaneId) {
+ state.ensure_test_terminals();
let terminal_id = state.workspaces[ws_idx].tabs[tab_idx]
.panes
.get(&pane_id)
diff --git a/src/app/agents.rs b/src/app/agents.rs
index f9e410f5..15b93674 100644
--- a/src/app/agents.rs
+++ b/src/app/agents.rs
@@ -17,7 +17,6 @@ impl App {
.filter_map(move |pane_id| self.agent_info(ws_idx, pane_id))
})
})
- .filter(|agent| agent.name.is_some() || agent.agent.is_some())
.collect()
}
@@ -88,8 +87,11 @@ impl App {
}));
};
match normalized_name {
- Some(name) => terminal.set_manual_label(name),
- None => terminal.clear_manual_label(),
+ Some(name) => {
+ terminal.set_agent_name(name.clone());
+ terminal.set_manual_label(name);
+ }
+ None => terminal.clear_agent_name(),
}
self.state.mark_session_dirty();
self.agent_info(resolved.ws_idx, resolved.pane_id)
@@ -195,6 +197,7 @@ impl App {
let Some(terminal) = self.state.terminals.get_mut(&terminal_id) else {
return Err(AgentStartError::SpawnFailed("terminal disappeared".into()));
};
+ terminal.set_agent_name(name.clone());
terminal.set_manual_label(name);
self.state.mark_session_dirty();
@@ -403,10 +406,16 @@ impl App {
ws_idx: usize,
pane_id: crate::layout::PaneId,
) -> Option<crate::api::schema::AgentInfo> {
+ let ws = self.state.workspaces.get(ws_idx)?;
+ let pane_state = ws.pane_state(pane_id)?;
+ let terminal = self.state.terminals.get(&pane_state.attached_terminal_id)?;
+ if !terminal.is_agent_terminal() {
+ return None;
+ }
let pane = self.pane_info(ws_idx, pane_id)?;
Some(crate::api::schema::AgentInfo {
terminal_id: pane.terminal_id,
- name: pane.label,
+ name: terminal.agent_name.clone(),
agent: pane.agent,
agent_status: pane.agent_status,
workspace_id: pane.workspace_id,
diff --git a/src/app/creation.rs b/src/app/creation.rs
index 1832e637..f1638e15 100644
--- a/src/app/creation.rs
+++ b/src/app/creation.rs
@@ -8,7 +8,10 @@ use crate::workspace::Workspace;
impl App {
pub(super) fn seed_cwd_from_workspace(&self, ws_idx: usize) -> Option<std::path::PathBuf> {
- self.state.workspaces.get(ws_idx)?.resolved_identity_cwd()
+ self.state
+ .workspaces
+ .get(ws_idx)?
+ .resolved_identity_cwd_from(&self.state.terminals, &self.state.terminal_runtimes)
}
pub(super) fn workspace_creation_source(&self) -> Option<usize> {
@@ -294,7 +297,7 @@ impl App {
crate::api::schema::WorkspaceInfo {
workspace_id: self.public_workspace_id(index),
number: index + 1,
- label: ws.display_name(),
+ label: ws.display_name_from(&self.state.terminals, &self.state.terminal_runtimes),
focused: self.state.active == Some(index),
pane_count: ws.public_pane_numbers.len(),
tab_count: ws.tabs.len(),
diff --git a/src/app/input/mod.rs b/src/app/input/mod.rs
index fea88b55..7823de31 100644
--- a/src/app/input/mod.rs
+++ b/src/app/input/mod.rs
@@ -216,6 +216,8 @@ impl AppState {
self.host_terminal_theme,
) {
let new_id = new_pane.pane_id;
+ self.terminal_runtimes
+ .insert(new_pane.terminal.id.clone(), new_pane.runtime);
self.terminals
.insert(new_pane.terminal.id.clone(), new_pane.terminal);
ws.layout.focus_pane(new_id);
diff --git a/src/app/input/navigate.rs b/src/app/input/navigate.rs
index 6445b6ab..798aafa8 100644
--- a/src/app/input/navigate.rs
+++ b/src/app/input/navigate.rs
@@ -331,6 +331,9 @@ impl App {
)?;
let new_pane_id = new_pane.pane_id;
self.state
+ .terminal_runtimes
+ .insert(new_pane.terminal.id.clone(), new_pane.runtime);
+ self.state
.terminals
.insert(new_pane.terminal.id.clone(), new_pane.terminal);
ws.active_tab_mut()
@@ -1122,6 +1125,7 @@ mod tests {
.await;
assert_eq!(app.state.workspaces[0].tabs[0].layout.pane_count(), 2);
+ assert_eq!(app.state.terminal_runtimes.len(), 2);
assert!(app.state.workspaces[0].tabs[0].zoomed);
let _ = wait_for_file(&output_path);
diff --git a/src/app/mod.rs b/src/app/mod.rs
index c5654db2..1c818a9c 100644
--- a/src/app/mod.rs
+++ b/src/app/mod.rs
@@ -412,8 +412,11 @@ impl App {
state.terminals = restored_terminals;
state.terminal_runtimes = restored_terminal_runtimes;
- for ws in &mut state.workspaces {
- ws.refresh_git_branch();
+ for ws_idx in 0..state.workspaces.len() {
+ let cwd = state.workspaces[ws_idx]
+ .resolved_identity_cwd_from(&state.terminals, &state.terminal_runtimes);
+ state.workspaces[ws_idx].cached_git_branch =
+ cwd.as_deref().and_then(crate::workspace::git_branch);
}
// Background auto-update is disabled in monolithic no-session mode
@@ -1702,7 +1705,7 @@ mod tests {
}
#[test]
- fn terminal_target_resolves_unique_manual_name() {
+ fn terminal_target_resolves_unique_agent_name() {
let mut app = test_app();
let workspace = Workspace::test_new("terminal-target-name");
let pane = workspace.tabs[0].root_pane;
@@ -1718,7 +1721,7 @@ mod tests {
.terminals
.get_mut(&attached_terminal_id)
.unwrap()
- .manual_label = Some("reviewer".into());
+ .set_agent_name("reviewer".into());
app.state.active = Some(0);
app.state.selected = 0;
@@ -1746,7 +1749,7 @@ mod tests {
}
#[test]
- fn terminal_target_reports_ambiguous_duplicate_manual_name() {
+ fn terminal_target_reports_ambiguous_duplicate_agent_name() {
let mut app = test_app();
let mut workspace = Workspace::test_new("terminal-target-ambiguous");
let first = workspace.tabs[0].root_pane;
@@ -1762,7 +1765,7 @@ mod tests {
.terminals
.get_mut(&first_terminal_id)
.unwrap()
- .manual_label = Some("worker".into());
+ .set_agent_name("worker".into());
let second_terminal_id = app.state.workspaces[0]
.pane_state(second)
.unwrap()
@@ -1772,7 +1775,7 @@ mod tests {
.terminals
.get_mut(&second_terminal_id)
.unwrap()
- .manual_label = Some("worker".into());
+ .set_agent_name("worker".into());
app.state.active = Some(0);
app.state.selected = 0;
diff --git a/src/app/runtime.rs b/src/app/runtime.rs
index 98ae4e0e..55c89e73 100644
--- a/src/app/runtime.rs
+++ b/src/app/runtime.rs
@@ -247,7 +247,10 @@ impl App {
.state
.workspaces
.iter()
- .filter_map(|ws| ws.resolved_identity_cwd().map(|cwd| (ws.id.clone(), cwd)))
+ .filter_map(|ws| {
+ ws.resolved_identity_cwd_from(&self.state.terminals, &self.state.terminal_runtimes)
+ .map(|cwd| (ws.id.clone(), cwd))
+ })
.collect();
if workspaces.is_empty() {
diff --git a/src/app/terminal_targets.rs b/src/app/terminal_targets.rs
index 94cf89d0..71ca83bb 100644
--- a/src/app/terminal_targets.rs
+++ b/src/app/terminal_targets.rs
@@ -65,8 +65,10 @@ impl App {
.terminals
.values()
.find(|terminal| terminal.id.to_string() == candidate.terminal_id)
- .and_then(|terminal| terminal.manual_label.as_deref())
- .is_some_and(|label| label == target)
+ .is_some_and(|terminal| {
+ terminal.agent_name.as_deref() == Some(target)
+ || terminal.effective_agent_label() == Some(target)
+ })
})
.collect();
if let Some(resolved) = self.single_terminal_match(target, name_matches)? {