docs(comments): rewrite comments across all crates to the guidelines

Sweep every first-party crate source (1956 .rs files) to the project comment
guidelines: delete redundant restatements, decorative banners, change
narration, and end-of-line comments; keep and tighten the crucial ones
(invariants, bug rationale, SAFETY blocks, ported-source attribution).

No functional code changed. Every edit is proven comment-only against the
prior tree by a comment-stripping lexer (string/char/raw-string aware) plus a
separate doctest-fence check. Where removing a comment made rustfmt or clippy
want to re-lay-out adjacent code, the minimal triggering comment is restored so
code tokens stay byte-identical.

Gates green: cargo fmt --all --check (0 diffs), cargo check and cargo clippy
--workspace --all-targets (0 warnings).

Adds scripts/check_codegen_comment_guidelines.py — the enforcement gate for
these guidelines (flags banners, end-of-line comments, change narration, and
commented-out code).
This commit is contained in:
ZacharyZhang-NY committed 2026-07-23 16:55:39 -04:00
1 parent ff0fb56c67
commit a02b555e66
1458 files changed
+10729 -21750

No files matched your search

@@ -175,12 +175,9 @@ pub fn compute_layout_with_dispatch(
} else {
1
};
// Standalone peek rect retired. Peek now renders
// INSIDE the dispatch rect (which grows when `peek_visible`,
// computed above). Kept as a zero-height field for ABI compat
// with the existing call sites that still destructure
// `layout.peek`; the field can be removed in a follow-up
// cleanup.
// Peek renders INSIDE the dispatch rect (which grows when
// `peek_visible`, computed above); this field stays zero-height so
// call sites that still destructure `layout.peek` keep compiling.
let peek_h: u16 = 0;
let remaining = area.height.saturating_sub(
top_margin_h
@@ -235,7 +232,7 @@ pub fn compute_layout_with_dispatch(
};
y += header_gap_h;
// Polish — inset the list by LIST_OUTER_HPAD on each side so the
// Inset the list by LIST_OUTER_HPAD on each side so the
// row content and group header rules have side breathing room.
// The outer columns stay painted bg_base by the area-wide fill in
// render_dashboard. Mirrors the dispatch inset pattern but with a
@@ -470,7 +467,7 @@ mod tests {
assert_eq!(layout.list.width, area.width - LIST_OUTER_HPAD * 2);
}
/// Polish — the list rect is inset by LIST_OUTER_HPAD cols on each
/// The list rect is inset by LIST_OUTER_HPAD cols on each
/// side so row content (markers, rules, text) has breathing room
/// and doesn't touch the terminal edges. The outer columns remain
/// bg_base (painted by the top-level area fill).
@@ -674,9 +671,8 @@ mod tests {
assert_eq!(layout.peek.height, 0);
}
/// The standalone peek rect was retired (peek now
/// renders INSIDE the dispatch box). The peek rect is always
/// zero-height; what changes when `peek_visible == true` is
/// Peek renders INSIDE the dispatch box, so the peek rect is
/// always zero-height; what changes when `peek_visible == true` is
/// the dispatch rect, which grows from 3 to 5 rows to host
/// the peek's status + reply input.
#[test]
@@ -1182,10 +1182,6 @@ pub fn extract_first_user_message(agent: &AgentView) -> Option<String> {
/// message had MORE than `count` non-empty lines — so the renderer can
/// show a `…` continuation marker only when there's genuinely more.
/// Returns `(vec![], false)` when the agent hasn't streamed any text.
///
/// This is the multi-line successor to the old single-line
/// `extract_last_agent_message`: the peek panel now surfaces up to 3
/// lines of the last response instead of just the first.
pub fn extract_last_agent_lines(agent: &AgentView, count: usize) -> (Vec<String>, bool) {
use crate::scrollback::block::RenderBlock;
use crate::views::session_title::sanitize_display_text;
@@ -1232,10 +1228,9 @@ pub fn extract_last_agent_lines(agent: &AgentView, count: usize) -> (Vec<String>
/// Extract the last `count` short text descriptions from the given
/// agent view's scrollback.
///
/// No more `format!("{:?}", entry.block)`, which leaked
/// Rust Debug output (variant tags, struct field names, escaped
/// strings — and worst of all the head of bash commands containing
/// credentials).
/// Never project via `format!("{:?}", entry.block)`: that leaks Rust
/// Debug output (variant tags, struct field names, escaped strings —
/// and worst of all the head of bash commands containing credentials).
///
/// Every projected string is run through
/// `strip_ansi_escapes::strip_str` so embedded `\x1b[...]` sequences
@@ -2047,7 +2042,8 @@ mod tests {
reject_option: None,
},
);
panel.selected_option = Some(1); // highlight the 2nd option
// Highlight the 2nd option.
panel.selected_option = Some(1);
let mut reply = test_reply();
let _ = render_peek_panel(
&mut buf,
@@ -2098,7 +2094,8 @@ mod tests {
},
);
panel.selected_option = Some(1);
panel.focused = false; // Tab → row nav
// Tab → row nav.
panel.focused = false;
let mut reply = test_reply();
let _ = render_peek_panel(
&mut buf,
@@ -2152,7 +2149,8 @@ mod tests {
reject_option: Some(1),
},
);
panel.selected_option = Some(1); // highlight the reject option
// Highlight the reject option.
panel.selected_option = Some(1);
let mut reply = test_reply();
reply.set_text("do it differently");
let res = render_peek_panel(
@@ -2214,7 +2212,8 @@ mod tests {
reject_option: Some(1),
},
);
panel.selected_option = Some(1); // highlight the "Other" row
// Highlight the "Other" row.
panel.selected_option = Some(1);
let mut reply = test_reply();
let _ = render_peek_panel(
&mut buf,
@@ -73,8 +73,6 @@ pub fn render_dashboard(
// empty body reads "Loading sessions…" instead of the "no agents
// yet" hint so a fresh open doesn't flash an empty-looking screen.
dashboard_sessions_loading: bool,
// `_compact` removed in this version. Hide-chrome / shortened
// activity strings are a Phase 5 polish item.
) -> Option<(u16, u16)> {
// Re-anchor selection BEFORE we build the rows so that the
// visible set drives selection clamping.
@@ -468,14 +466,13 @@ fn rename_cursor_pos(state: &DashboardState, rows: &[DashboardRow]) -> Option<(u
}
/// Render the compact dashboard "banner" used when an agent is
/// attached as a popup. Replaces the previous
/// stacked-input-bars layout (where the dashboard's dispatch +
/// footer rendered visibly BELOW the popup). The banner is a
/// bordered panel containing the row list summary; the popup
/// renders directly below it carrying the focused agent's full
/// view (scrollback + prompt + shortcuts), so the user sees a
/// single coherent surface with the agent's prompt as the only
/// input bar.
/// attached as a popup, instead of the dashboard's normal dispatch +
/// footer (which would otherwise render visibly BELOW the popup as a
/// second stacked input bar). The banner is a bordered panel
/// containing the row list summary; the popup renders directly below
/// it carrying the focused agent's full view (scrollback + prompt +
/// shortcuts), so the user sees a single coherent surface with the
/// agent's prompt as the only input bar.
///
/// Visual:
///
@@ -595,7 +592,7 @@ fn render_dashboard_banner(
/// inflate the tallies if counted directly. Chips with zero count are
/// suppressed.
///
/// Reintroduces a `[+ New Agent]` button on the right edge of
/// A `[+ New Agent]` button sits on the right edge of
/// the header. The button is the default cursor target whenever
/// no row is selected — Up-arrow from the first row, Esc deselect,
/// and dashboard-open-without-prior-agent all land here. While
@@ -799,8 +796,7 @@ fn render_header(
// Paint the current location — git branch + cwd (with worktree
// label) — on the left, mirroring the session surfaces (welcome
// top bar / agent status bar) so the dashboard shows WHERE a
// dispatched session will run. Replaces the old bare "Agents"
// label.
// dispatched session will run.
//
// Width budget: from `area.x` up to the leftmost chip's leading
// ` │ ` separator (3 cells, painted by `AgentStatusBar::render`
@@ -964,7 +960,8 @@ fn render_location_picker(
} else {
"[worktree:off]"
};
let wt_w = wt_text.len() as u16; // ASCII → byte len == display width
// ASCII → byte len == display width.
let wt_w = wt_text.len() as u16;
const WT_GAP: u16 = 1;
const MIN_PATH_W: u16 = 16;
let (path_w, wt_rect) = if show_worktree && content_area.width >= wt_w + WT_GAP + MIN_PATH_W
@@ -1127,11 +1124,11 @@ fn render_location_picker(
/// One line in the dashboard's vertical stack — either a state-group
/// header or a content row.
///
/// Reintroduces explicit state group headers (`──
/// Needs input (2) ──`). The per-row dot + state colour alone didn't
/// communicate group boundaries clearly enough; users couldn't tell at
/// a glance how many sessions were awaiting input vs working vs idle
/// vs done. Headers are emitted on every top-level state transition
/// Explicit state group headers (`──
/// Needs input (2) ──`) exist because the per-row dot + state colour
/// alone doesn't communicate group boundaries clearly enough; users
/// can't tell at a glance how many sessions are awaiting input vs
/// working vs idle vs done. Headers are emitted on every top-level state transition
/// (subagent rows inherit their parent's group and never trigger a
/// header) when `grouping == Grouping::State` and the filter isn't
/// already pinned to a single state.
@@ -2260,8 +2257,8 @@ fn render_narrow_rows(
let viewport_h = area.height as usize;
// The clamp follows whichever cursor is active — a row OR a section
// header — so navigating onto a section title scrolls it into view,
// matching the wide layout. Previously only a selected row was
// tracked, so a selected header could stay off-screen.
// matching the wide layout. Tracking only a selected row would leave
// a selected header stranded off-screen.
let selected_line_idx = lines.iter().position(|l| match l {
DashboardLine::Row(r) => state.selected.as_ref().is_some_and(|s| r.id == *s),
DashboardLine::PinnedHeader { .. } => state.selected_section == Some(SectionKey::Pinned),
@@ -2476,23 +2473,6 @@ fn render_empty_state(buf: &mut Buffer, area: Rect, theme: &Theme, loading: bool
);
}
/// Paint a rounded-box
/// chrome around the dispatch input so it reads as a real input
/// field. On a 3-row rect the layout is:
///
/// ```text
/// ╭──────────────────────────────────────────────────────────╮
/// │ ❯ Dispatch a new agent │
/// ╰──────────────────────────────────────────────────────────╯
/// ```
///
/// On a 1-row rect (very short terminals) we fall back to the
/// bare `❯ {text}` line so the input stays usable.
///
/// `reply_label` flips the placeholder between `Dispatch a new
/// agent` (`None`) and `Reply to {label}` (`Some`) so the
/// chrome reflects what Enter will do: dispatch a new session vs.
/// enqueue / send a prompt to the currently-selected agent.
/// Paint a short right-aligned feedback badge onto the dispatch box's
/// **top border** (e.g. `✗ Session no longer exists`, `✓ Theme: Kigi
/// Day`), in a neutral accent colour. The message is painted VERBATIM:
@@ -2500,7 +2480,7 @@ fn render_empty_state(buf: &mut Buffer, area: Rect, theme: &Theme, loading: bool
/// [`DashboardState::set_error_toast`] (`✗`), while successes / info
/// arrive from the `show_toast` builders (`✓` / `⚠`). The badge
/// therefore neither prepends a glyph nor forces a colour; doing so
/// previously produced a doubled `✗ ✓ …` and painted non-errors (like
/// would produce a doubled `✗ ✓ …` and paint non-errors (like
/// "Session closed") red. The glyph, not the colour, conveys severity —
/// mirroring the per-agent toast in [`crate::app::agent_view`]. The
/// badge ends one column before the right corner (`╮`) and is truncated
@@ -2609,6 +2589,17 @@ fn paint_dispatch_config_badge(
.render_info_line(buf, info_rect, &info, theme.bg_base, theme, input_focused);
}
/// Paint a rounded-box chrome around the dispatch input so it reads as a
/// real input field. On a 3-row rect the layout is:
///
/// ```text
/// ╭──────────────────────────────────────────────────────────╮
/// │ ❯ Dispatch a new agent │
/// ╰──────────────────────────────────────────────────────────╯
/// ```
///
/// On a 1-row rect (very short terminals) we fall back to the
/// bare `❯ {text}` line so the input stays usable.
fn render_dispatch(
buf: &mut Buffer,
area: Rect,
@@ -3015,11 +3006,9 @@ fn render_file_search_dropdown_for(
/// Render the dashboard's footer / shortcuts hint row.
///
/// Switched to the shared `ShortcutsBar` widget so
/// the dashboard's shortcut bar uses the same visual vocabulary as
/// the agent view's bottom bar: `Key:label` with bold keys + dim
/// ` │ ` separators on `bg_base`, instead of the previous custom
/// `key label · key label` gray-only string. When a
/// Built on the shared `ShortcutsBar` widget so the dashboard's shortcut
/// bar uses the same visual vocabulary as the agent view's bottom bar:
/// `Key:label` with bold keys + dim ` │ ` separators on `bg_base`. When a
/// stop-confirm is armed, `ShortcutsBar::with_pending` paints the
/// `press again to {label}` hint in place of the regular list,
/// matching the agent view's identical mechanism.
@@ -3233,8 +3222,8 @@ fn render_footer(
registry.find(id).map(|d| d.default_key).unwrap_or(fallback)
};
let enter = key!(Enter);
// "Send + open" is `Ctrl+S` (was `Shift+Enter`, which now inserts a
// newline). Hardcoded in the dispatch / peek key handlers, not a
// "Send + open" is fixed at `Ctrl+S` — Shift+Enter inserts a newline
// instead. Hardcoded in the dispatch / peek key handlers, not a
// registry action, so the chip is built directly.
let send_open = key!('s', CONTROL);
// Multiline: bare Enter inserts a newline; Shift+Enter (or Alt+Enter
@@ -3528,38 +3517,17 @@ pub(crate) fn cached_home() -> Option<&'static str> {
static HOME: std::sync::OnceLock<Option<String>> = std::sync::OnceLock::new();
// ---------------------------------------------------------------------------
// Popup overlay (banner-style)
// ---------------------------------------------------------------------------
/// Compute the rect for the attached-agent popup overlay.
///
/// The popup now takes the FULL bottom portion of
/// the screen (no horizontal inset, no bottom inset) with only a
/// dynamic top inset reserved for the dashboard banner.
///
/// The previous ~1/6-inset-on-all-sides design left the dashboard's
/// dispatch input + footer visible BELOW the popup, producing two
/// stacked input bars. The banner above the popup carries the live
/// row list in a bordered panel.
///
/// (Historical legacy comment kept for context — the old layout
/// description is no longer accurate; see the body of this function
/// for the current banner-style layout.)
/// terminal yields a ~164×48 popup with a ~36×12 dashboard frame
/// visible around it.
/// The popup takes the FULL bottom portion of the screen (no
/// horizontal inset, no bottom inset) with only a dynamic top inset
/// reserved for the dashboard banner, which carries the live row list
/// in a bordered panel above the popup.
///
/// On terminals too small to honour the minimum inset, falls through
/// to a 0-inset takeover (no escape: any non-zero inset would clip
/// the agent's prompt below readability).
pub fn popup_rect(view: Rect) -> Rect {
// Popup takes the FULL bottom area (no
// horizontal inset, no bottom inset) with only a small TOP
// inset reserved for the dashboard banner that shows the in-flight
// rows. The previous ~1/6-inset-on-all-sides design left the
// dashboard's own dispatch input + footer visible BELOW the
// popup, producing two visible input bars stacked vertically.
//
// The banner height is dynamic: ~30% of the screen up to a
// BANNER_MAX_HEIGHT cap, with a BANNER_MIN_HEIGHT floor on tall
// terminals so a 1-row banner doesn't crowd the rows out. Very
@@ -4505,7 +4473,8 @@ mod tests {
"x",
Some((1, 2)),
false,
true, // hover_next
// hover_next
true,
false,
)
.expect("overlay must paint");
@@ -4886,8 +4855,6 @@ mod tests {
);
}
// ── snap_offset_to_line_boundary unit tests ──────────────────────
/// An offset already on a boundary is returned unchanged.
#[test]
fn snap_offset_already_on_boundary_returns_input() {
@@ -4948,10 +4915,7 @@ mod tests {
/// `popup_rect` takes the FULL bottom area
/// (no horizontal inset, no bottom inset) with only a top inset
/// reserved for the dashboard banner. Replaces the previous
/// centred-inset design which left the dashboard's own dispatch
/// input + footer visible below the popup, producing two
/// stacked input bars.
/// reserved for the dashboard banner.
#[test]
fn popup_rect_takes_full_bottom_area_with_top_banner() {
let view = Rect::new(0, 0, 200, 80);
@@ -5015,8 +4979,7 @@ mod tests {
assert_eq!(popup.y, view.y);
}
/// Replacing the home-rolled chrome
/// with `picker::render_bordered_frame` means the divider sits
/// `picker::render_bordered_frame` places the divider
/// ABOVE the returned content rect. This test paints the chrome
/// plus a "fake agent" pattern in the inner rect and verifies
/// the divider's `─` glyph survives the inner paint.
@@ -5209,10 +5172,9 @@ mod tests {
/// Pressing the help key returns the
/// `DashboardOpenShortcutsHelp` action so the dispatcher can
/// build the modal state. No `error_toast` is set (the
/// an earlier polish iteration surfaced a hint via the dispatch
/// input placeholder, which the user explicitly rejected
/// because it conflicted with their typing slot).
/// build the modal state. No `error_toast` is set — the modal
/// itself carries the help; surfacing it via the dispatch input
/// placeholder would conflict with the input's typing slot.
#[test]
fn dashboard_shortcuts_help_action_opens_modal() {
use super::super::state::DashboardState;
@@ -6047,7 +6009,8 @@ mod tests {
fn render_rows_groups_off_uses_divider_not_pinned_header() {
let mut buf = Buffer::empty(Rect::new(0, 0, 80, 30));
let mut state = DashboardState::new();
state.grouping = Grouping::Directory; // groups off (Ctrl+G)
// groups off (Ctrl+G)
state.grouping = Grouping::Directory;
let mut pinned = header_test_row(1, RowState::Idle, "pinned row");
pinned.pinned = true;
let rows = vec![pinned, header_test_row(2, RowState::Working, "working row")];
@@ -6085,11 +6048,9 @@ mod tests {
/// Idle → Completed → Failed order (matching
/// `RowState::group_priority`).
///
/// Header chrome now uses Option A
/// (` ● Label (N)`): a 2-col indent, a state-coloured dot, then
/// the label + count in `gray_dim`. The previous full-row
/// `── Label (N) ────────────────` chrome was dropped (the
/// trailing dashes felt visually obnoxious — user complaint).
/// Regression guard: header chrome is `Label N ──…` (bold label,
/// dim count, trailing rule), NOT the parenthesised
/// `Awaiting (1)` form.
#[test]
fn render_rows_emits_group_headers_in_state_order() {
// Rows are 3 cells tall, headers 2 cells; 5 of each
@@ -6231,7 +6192,8 @@ mod tests {
let mut buf = Buffer::empty(Rect::new(0, 0, 100, 2));
let theme = Theme::current();
let mut state = DashboardState::new();
state.spinner_tick = 8; // → dot_spinner_frames()[2] = `⸬`.
// → dot_spinner_frames()[2] = `⸬`.
state.spinner_tick = 8;
let row = DashboardRow {
id: DashboardRowId::TopLevel(crate::app::agent::AgentId(1)),
label: "who are you?".to_string(),
@@ -6564,10 +6526,6 @@ mod tests {
/// `Grouping::Directory` keeps cwd as the
/// grouping primitive, so state headers are suppressed.
///
/// Header chrome marker updated to match Option
/// A. The `(count)` parenthesis pattern is the new specific
/// fingerprint for a state header.
#[test]
fn render_rows_skips_headers_when_grouping_is_directory() {
let mut buf = Buffer::empty(Rect::new(0, 0, 80, 10));
@@ -6597,9 +6555,6 @@ mod tests {
/// `Filter::State(_)` collapses the view to a
/// single state, so the header would be redundant chrome.
///
/// Header chrome marker updated to match Option
/// A (look for `Working (` instead of `── Working`).
#[test]
fn render_rows_skips_headers_when_filter_is_state() {
let mut buf = Buffer::empty(Rect::new(0, 0, 80, 10));
@@ -6833,10 +6788,6 @@ mod tests {
);
}
// ─────────────────────────────────────────────────────────────────
// Header redesign tests
// ─────────────────────────────────────────────────────────────────
/// Basename of the test process's cwd — the one deterministic
/// fragment of the header's location label. The full label depends
/// on global git caches (`git_info::*`) that parallel tests may
@@ -6962,11 +6913,12 @@ mod tests {
fn underline_location_on_hover_excludes_branch_icon() {
let icon = "\u{e0a0}";
let plain = Style::default();
// leading inset, git (icon + branch), git↔path separator, path.
let spans = vec![
Span::styled(" ".to_string(), plain), // leading inset
Span::styled(format!("{icon} main"), plain), // git: icon + branch
Span::styled(" ".to_string(), plain), // git↔path separator
Span::styled("/home/me/repo".to_string(), plain), // path
Span::styled(" ".to_string(), plain),
Span::styled(format!("{icon} main"), plain),
Span::styled(" ".to_string(), plain),
Span::styled("/home/me/repo".to_string(), plain),
];
let out = underline_location_on_hover(spans, icon);
@@ -7495,7 +7447,8 @@ mod tests {
&state,
&registry,
None,
true, // peek_active
// peek_active
true,
None,
);
let content = buf_to_text(&buf);
@@ -7553,7 +7506,8 @@ mod tests {
&state,
&registry,
None,
true, // peek_active
// peek_active
true,
None,
);
let content = buf_to_text(&buf);
@@ -7570,7 +7524,8 @@ mod tests {
let mut buf = Buffer::empty(Rect::new(0, 0, 200, 1));
let theme = Theme::current();
let mut state = DashboardState::new();
state.list_focused = true; // used to steal the footer before the peek fix
// Regression guard: this used to steal the footer before the peek fix.
state.list_focused = true;
state.peek = Some(crate::views::dashboard::peek::PeekPanelState::new(
DashboardRowId::TopLevel(crate::app::agent::AgentId(0)),
crate::views::dashboard::peek::PeekFields {
@@ -7706,7 +7661,8 @@ mod tests {
state,
&registry,
None,
true, // peek_active
// peek_active
true,
None,
);
buf_to_text(&buf)
@@ -7792,10 +7748,8 @@ mod tests {
}
/// When a row (NeedsInput or otherwise) is selected
/// with an empty prompt, the footer shows `Enter:open`.
/// The previous `see details` label is folded into the
/// unified "row selected → open" semantics — every row's
/// detail view is the answer surface for any user-input
/// with an empty prompt, the footer shows `Enter:open` — every
/// row's detail view is the answer surface for any user-input
/// state, including `NeedsInput`.
#[test]
fn render_footer_row_selected_empty_prompt_shows_enter_open() {
@@ -1258,10 +1258,9 @@ mod tests {
assert_eq!(rows[1].state, RowState::Working);
assert_eq!(rows[2].state, RowState::Idle);
}
/// Renamed from `sort_deterministic_with_equal_keys`.
/// The original name implied a tiebreak guarantee that
/// `sort_cluster_key` does NOT provide; documents the actual
/// behavioural contract: idempotent on identical inputs.
/// `sort_cluster_key` does not guarantee a full tiebreak by itself;
/// this asserts the weaker contract it does provide: idempotent on
/// identical inputs.
#[test]
fn sort_is_idempotent_for_identical_inputs() {
let now = SystemTime::now();
@@ -1737,9 +1736,8 @@ mod tests {
AgentView::new(session, ScrollbackState::new())
}
/// An idle local agent with no last message has a BLANK second line —
/// the model is no longer used as a fallback there (it now shows in
/// the peek panel's bottom-border badge for the selected row, keeping
/// the list uncluttered).
/// the model appears in the peek panel's bottom-border badge for the
/// selected row instead, keeping the list uncluttered.
#[test]
fn idle_local_agent_without_message_has_blank_secondary() {
let agent = make_idle_agent_with_model(Some("kigi-4.5"));
@@ -1498,27 +1498,18 @@ impl DashboardState {
/// agent/subagent no longer exists is silently dropped. Avoids edge
/// case 20 (a pinned row whose agent was deleted).
///
/// Also clears an in-flight `rename` whose row
/// disappeared (parent closed, subagent finished, etc.), so a
/// Commit-Enter doesn't silently drop the draft on a phantom row.
///
/// Extends the gc to `peek`, `hovered_row`, and
/// `last_click`. The previous version only cleared `pinned`,
/// `reorder`, `rename`, and `selected`. A stale `peek` would
/// render cached content for a dead row; a stale `last_click`
/// could trigger a double-click "attach" against whatever new
/// row took the cell.
///
/// Drop the "Row no longer exists; rename
/// cancelled" toast on stale rename. The toast fired on every
/// dashboard open if a row was closed externally, surprising the
/// user (they hadn't done anything since). The clear itself is
/// preserved — silently clearing the rename matches the silent
/// gc on `pinned` / `reorder` / `selected` / `peek` /
/// `hovered_row` / `last_click`. the earlier invariant ("Commit
/// Enter can't dispatch against a phantom row") is preserved
/// because the renamed row can't render the overlay if it's
/// gone, so Enter can't reach the commit path.
/// Also silently clears `rename`, `peek`, `hovered_row`, and
/// `last_click` when their row disappeared (parent closed, subagent
/// finished, etc.):
/// - A stale `rename` is cleared without a "Row no longer exists;
/// rename cancelled" toast, so a row closed elsewhere doesn't
/// surprise the user with a toast on the next dashboard open.
/// Commit-Enter still can't dispatch against a phantom row, because
/// the renamed row can't render the overlay once it's gone.
/// - A stale `peek` would otherwise render cached content for a dead
/// row.
/// - A stale `last_click` could trigger a double-click "attach"
/// against whatever new row took the cell.
pub fn gc_stale_refs(&mut self, alive: &dyn Fn(&DashboardRowId) -> bool) {
self.pinned.retain(|id| alive(id));
self.reorder.retain(|id| alive(id));
@@ -2516,7 +2507,7 @@ impl DashboardState {
.as_ref()
.is_some_and(|p| p.reject_option == selected);
match (key.code, selected) {
// ── No option selected → navigate agents / open ──
// No option selected: navigate agents / open.
(KeyCode::Up, None) => {
return Some(InputOutcome::Action(Action::DashboardSelectPrev));
}
@@ -2542,7 +2533,7 @@ impl DashboardState {
.unwrap_or(InputOutcome::Unchanged),
);
}
// ── Option selected → move within options (spill at edges) ──
// Option selected: move within options (spill at edges).
(KeyCode::Up, Some(0)) => {
return Some(InputOutcome::Action(Action::DashboardSelectPrev));
}
@@ -2882,11 +2873,11 @@ impl DashboardState {
// (the early return at the top of this function), so by the time
// execution reaches here the peek panel is guaranteed closed.
// ── Ctrl+V / Cmd+V paste ────────────────────────────────────────
// Read the pbpaste text once and route through the shared deferred
// paste pipeline: a file path wins synchronously, else the clipboard
// image/file-url probe defers off the event loop. Mirrors `AgentView`
// — without this, Ctrl+V on the dashboard did nothing useful.
// Ctrl+V / Cmd+V paste: read the pbpaste text once and route through
// the shared deferred paste pipeline: a file path wins synchronously,
// else the clipboard image/file-url probe defers off the event loop.
// Mirrors `AgentView` — without this, Ctrl+V on the dashboard did
// nothing useful.
if crate::input::key::is_paste_key(key) {
let clipboard_text = crate::app::actions::ClipboardTextRead::from_result(
crate::clipboard::system_clipboard_read_text(),
@@ -2894,11 +2885,10 @@ impl DashboardState {
return self.handle_paste_key_deferred(clipboard_text, /* peek */ false);
}
// ── @-file-search intercept ─────────────────────────────────────
// The dispatch input offers a session-less `@` context picker
// rooted at the pager's launch cwd. While its dropdown is
// visible, the prompt widget owns Up/Down/Tab/Enter/Esc — route
// the key there BEFORE the dashboard's row-nav / Enter / Esc
// @-file-search intercept: the dispatch input offers a session-less
// `@` context picker rooted at the pager's launch cwd. While its
// dropdown is visible, the prompt widget owns Up/Down/Tab/Enter/Esc
// — route the key there BEFORE the dashboard's row-nav / Enter / Esc
// handlers, mirroring `agent_view::handle_prompt_key`.
if self.dispatch.file_search_visible() {
match self.dispatch.handle_key(key) {
@@ -4112,9 +4102,8 @@ impl DashboardState {
if let Some(sel) = self.selected.as_ref()
&& !selectable.iter().any(|r| r.id == *sel)
{
// The previously selected row was filtered out / closed
// / lost its parent. Drop the cursor — re-selecting is
// the user's job.
// The selected row was filtered out / closed / lost its
// parent. Drop the cursor — re-selecting is the user's job.
self.selected = None;
}
}
@@ -4292,10 +4281,6 @@ fn handle_rename_key(draft: &mut RenameDraft, key: &KeyEvent) -> InputOutcome {
}
}
// ---------------------------------------------------------------------------
// Filter parser (edge case 11)
// ---------------------------------------------------------------------------
/// Parse a filter expression from the dispatch input.
///
/// Rules per edge case 11:
@@ -4367,10 +4352,6 @@ pub fn parse_row_state_token(s: &str) -> Option<RowState> {
}
}
// ---------------------------------------------------------------------------
// Persistence I/O
// ---------------------------------------------------------------------------
/// Read the persisted `[dashboard].enabled` flag (defaults to `true`).
///
/// Lenient: any error or unparseable value returns `None`, which the
@@ -4583,10 +4564,6 @@ fn parse_persist_key_list(item: &toml_edit::Item) -> Vec<PersistedRowId> {
.collect()
}
// ---------------------------------------------------------------------------
// Helper: relative path display
// ---------------------------------------------------------------------------
/// Compact a `Path` for display against `$HOME`, returning a `String`.
///
/// Used by the row renderer + filter substring search to keep cwd
@@ -5333,10 +5310,6 @@ mod tests {
);
}
// ---------------------------------------------------------------
// handle_key tests (Esc cascade, Enter routing).
// ---------------------------------------------------------------
fn make_state_with_selection() -> DashboardState {
let mut s = DashboardState::new();
s.selected = Some(DashboardRowId::TopLevel(AgentId(0)));
@@ -5724,7 +5697,8 @@ mod tests {
p.options = vec![("a".into(), "A".into()), ("other".into(), "Other".into())];
p.reject_option = Some(1);
p.selected_option = Some(1);
p.request_id = None; // Ask tool (not a permission)
// Ask tool (not a permission).
p.request_id = None;
}
let reg = crate::actions::ActionRegistry::defaults();
let enter = KeyEvent::new(KeyCode::Enter, KeyModifiers::NONE);
@@ -5910,7 +5884,8 @@ mod tests {
let mut state = state_with_open_peek();
let reg = crate::actions::ActionRegistry::defaults();
state.peek_reply.set_text("a draft");
state.peek.as_mut().unwrap().focused = false; // Tab → row nav
// Tab → row nav.
state.peek.as_mut().unwrap().focused = false;
assert!(matches!(
state.handle_key(&KeyEvent::new(KeyCode::Down, KeyModifiers::NONE), &reg),
InputOutcome::Action(Action::DashboardSelectNext)
@@ -6388,7 +6363,8 @@ mod tests {
("__other__".into(), "Other".into()),
];
f.reject_option = Some(2);
f.request_id = None; // ← marks it as an ask question, not a permission
// Marks it as an ask question, not a permission.
f.request_id = None;
state.peek = Some(super::super::peek::PeekPanelState::new(
DashboardRowId::TopLevel(AgentId(0)),
f,
@@ -7010,12 +6986,6 @@ mod tests {
}
}
// -----------------------------------------------------------------
// Reconciled dispatch-input features: slash commands, Alt+Enter
// multiline, vim-gated j/k, and paste — layered on top of the
// reply-mode / search-mode base.
// -----------------------------------------------------------------
/// A `/command` Enter routes through the session-less slash
/// dispatcher instead of becoming a new session's prompt.
#[test]
@@ -7421,7 +7391,8 @@ mod tests {
let mut state = DashboardState::new();
assert!(state.new_agent_button_focused);
state.dispatch.set_text("fix the bug");
state.list_focused = true; // e.g. after an Esc blur
// e.g. after an Esc blur.
state.list_focused = true;
match state.handle_key(&key, &reg) {
InputOutcome::Action(Action::DashboardDispatch { text, attach }) => {
assert_eq!(text, "fix the bug");
@@ -7808,7 +7779,6 @@ mod tests {
);
}
// -----------------------------------------------------------------
// The clipboard raster/file-url probe (osascript) + image decode +
// session persist run OFF the event loop. A paste that would probe
// enqueues a `ProbeClipboardAttachment` effect and returns without an
@@ -7816,7 +7786,6 @@ mod tests {
// attaches later via `complete_clipboard_attachment_paste`. Snapshot /
// support are faked via the test-only seam; plain text with no
// raster stays fully synchronous (no defer).
// -----------------------------------------------------------------
fn probe_image_data() -> crate::clipboard::ImageData {
crate::clipboard::ImageData {
@@ -8252,7 +8221,8 @@ mod tests {
/// instead of inserting into the now-hidden reply buffer.
#[test]
fn completion_peek_dropped_when_panel_closed() {
let mut state = DashboardState::new(); // no peek open
// No peek open.
let mut state = DashboardState::new();
state.paste_probe_in_flight = 1;
let completion = state.complete_clipboard_attachment_paste(
completion_ctx(None, true),
@@ -8279,7 +8249,8 @@ mod tests {
/// instead of replying to the newly peeked agent.
#[test]
fn completion_peek_dropped_when_row_changed() {
let mut state = state_with_open_peek(); // peeks TopLevel(AgentId(0))
// Peeks TopLevel(AgentId(0)).
let mut state = state_with_open_peek();
state.paste_probe_in_flight = 1;
state.deferred_peek_send = Some(DeferredPeekSend {
row: DashboardRowId::TopLevel(AgentId(0)),
@@ -8418,7 +8389,8 @@ mod tests {
/// draft stays in the widget.
#[test]
fn stashed_peek_reply_dropped_when_question_active() {
let mut state = state_with_open_peek(); // peeks TopLevel(AgentId(0))
// Peeks TopLevel(AgentId(0)).
let mut state = state_with_open_peek();
state.peek_reply.set_text("please look");
state.deferred_peek_send = Some(DeferredPeekSend {
row: DashboardRowId::TopLevel(AgentId(0)),
@@ -8444,12 +8416,6 @@ mod tests {
);
}
// -----------------------------------------------------------------
// `/` literal + `Ctrl+/` search mode (replaces the old `/`→filter
// behaviour that silently swallowed prompts starting with a
// filter prefix).
// -----------------------------------------------------------------
/// `/` types a literal slash into the prompt — it no longer
/// enters a filter mode. (Filtering moved to `Ctrl+/`.)
#[test]
@@ -8690,7 +8656,8 @@ mod tests {
let click = MouseEvent {
kind: MouseEventKind::Down(MouseButton::Left),
column: 10,
row: 5, // inside BOTH dropdown and row_rects
// Inside BOTH dropdown and row_rects.
row: 5,
modifiers: crossterm::event::KeyModifiers::NONE,
};
let outcome = state.handle_mouse(&click);
@@ -9171,7 +9138,8 @@ mod tests {
]),
mode: crate::views::shortcuts_help::ShortcutsHelpMode::Browse,
});
modal.state.selected = 1; // first registry-backed hint
// First registry-backed hint.
modal.state.selected = 1;
state.shortcuts_modal = Some(modal);
let snapshot = |s: &DashboardState| {
@@ -9765,10 +9733,6 @@ mod tests {
assert_eq!(s.viewport_offset, 5);
}
// -----------------------------------------------------------------
// Mouse wheel decoupled from selection
// -----------------------------------------------------------------
/// `handle_scroll` flags `manual_scroll_active` so the next
/// `clamp_viewport` knows to skip the snap-to-selection
/// pull-back.
@@ -9886,8 +9850,6 @@ mod tests {
unsafe { std::env::remove_var("KIGI_AGENT_DASHBOARD") };
}
// ── Location picker ─────────────────────────────────────────────
fn location_candidate(path: &str, label: &str) -> LocationCandidate {
LocationCandidate {
path: PathBuf::from(path),
@@ -10046,8 +10008,10 @@ mod tests {
#[cfg(unix)]
#[test]
fn location_path_completion_tags_symlinked_worktree() {
let real = tempfile::tempdir().unwrap(); // the real worktree target
let parent = tempfile::tempdir().unwrap(); // the dir we list
// The real worktree target.
let real = tempfile::tempdir().unwrap();
// The dir we list.
let parent = tempfile::tempdir().unwrap();
std::os::unix::fs::symlink(real.path(), parent.path().join("link")).unwrap();
// Index keyed by the real (canonical) path, as the worktree DB is.