Synced from monorepo

Synced from monorepo

Changes:
- Refresh tool search when the managed MCP catalog is re-fetched
- Prevent duplicate leader process spawn and startup hang from stale leaders
- Document marketplaces, plugins, and organization controls
- Stamp session ID on image generation direct-to-API requests
- Fix auto mode blocked documentation
- Auto mode considers recent user intent
- Expose deploy archive, taken-down, limit, and in-progress reasons on the chat API
- Fail-closed auth refresh contract for shell clients
- Emit a chat-supplied per-session turn index in turn hooks
- Show bash mode chrome in minimal mode
- Add metrics for true-noop and stationarity stops
- Include voice interim text on prompt submit
- Silently end turn on true-noop thrash
- Quiet copy toast when clipboard delivery is confirmed
- Fix session fork truncating at the wrong prompt in rewound sessions
- Make the idle "still running" watcher cue clickable to open the tasks pane
- Default web search model to grok-4.5
- Let plugin subagents inherit parent MCP servers
- Gate no-op end-turn reminder on system reminders
- Add gateway bridge lifecycle telemetry
- Allow editing finalized text while voice is open
- Relocate token carrier to turn-commit events and plumb per-turn origin context
- Raise workflow scratch quotas and make failed runs resumable
- Workflows overlay: auto-progress phases, live agent status, and drop budget meter

Source-Revision: 9b8d35b46d959c042ea9aa31cbbebbd1f0c5c527
This commit is contained in:
grokkybara[bot] 2026-07-24 16:59:42 +00:00
commit 6e38642082
103 changed files with 4964 additions and 1261 deletions

View file

@ -74,20 +74,22 @@ pub struct TurnStatusOutput {
pub cancel_button: Option<Rect>,
/// Hit area for the background-demote button, if rendered.
pub bg_button: Option<Rect>,
/// Hit area for the still-running watcher cue (click opens the tasks
/// pane). `None` on keyboard-only hosts.
pub watching_cue: Option<Rect>,
}
/// Mouse-clickable affordances on the turn-status row — the `[stop]` cancel and
/// `[↓]` send-to-background buttons — with their current hover state. Passing
/// `Some(_)` to [`render_turn_status`] renders the buttons; passing `None`
/// marks a keyboard-only host (minimal mode has no mouse capture) and suppresses
/// both — that host cancels the turn via `Ctrl+C` and sends to background via
/// `Ctrl+B` instead.
/// Hover state for the turn-status row's mouse affordances (`[stop]`, `[↓]`,
/// the still-running watcher cue). `Some(_)` renders them; `None` marks a
/// keyboard-only host (minimal mode — no mouse capture) and suppresses all.
#[derive(Debug, Clone, Copy, Default)]
pub struct MouseButtons {
/// Whether the mouse is over the `[stop]` cancel button.
pub cancel_hovered: bool,
/// Whether the mouse is over the `[↓]` send-to-background button.
pub bg_hovered: bool,
/// Whether the mouse is over the still-running watcher cue.
pub watching_hovered: bool,
}
/// Counts of idle-surviving "watcher" work — background jobs that can wake
@ -191,49 +193,64 @@ pub fn is_sendable_wait(activity: &Option<TurnActivity>) -> bool {
)
}
/// Inputs to [`render_turn_status`] — one frame's worth of turn state.
#[derive(Debug)]
pub struct TurnStatusArgs<'a> {
pub state: &'a AgentState,
pub activity: &'a Option<TurnActivity>,
pub turn_elapsed: Option<Duration>,
pub activity_started_at: Option<Instant>,
pub tick: u64,
pub drain_blocked: bool,
/// Mouse affordances + hover state; `None` for keyboard-only hosts.
pub buttons: Option<MouseButtons>,
pub has_running_execute: bool,
/// Context-window tokens used, shown as `⇣Nk`.
pub total_tokens: Option<u64>,
pub mcp_init_progress: Option<&'a McpInitProgress>,
pub is_bash_turn: bool,
pub is_pending_user_input: bool,
pub goal_verifying: bool,
pub watchers: Watchers,
/// Parked on a sendable wait (`AgentView::renders_parked`): suppress the
/// running-turn chrome and render only the still-running cue.
pub parked: bool,
/// Transparent right-side background so the row blends with the
/// terminal's own background (minimal mode).
pub flat_background: bool,
pub held_queue: usize,
pub held_queue_top_sendable: bool,
}
/// Render the turn status line into the given area.
///
/// The caller is responsible for only allocating a 1-row area when
/// `should_show()` returns true (and 0 rows when false).
///
/// # Parameters
/// - `buttons`: `Some(MouseButtons { .. })` to render the mouse-clickable
/// `[stop]` / `[↓]` buttons with their hover state; `None` for a keyboard-only
/// host (minimal mode — no mouse capture), which suppresses both buttons.
/// - `total_tokens`: Total tokens used (context window usage), shown as `⇣Nk`.
/// - `parked`: the turn is parked on a sendable wait and renders the stopped
/// look (`AgentView::renders_parked`). The running-turn chrome is suppressed;
/// only the "… still running" cue renders (the parked turn is by definition
/// waiting on background work, so the cue explains the idle-looking chrome).
/// - `flat_background`: when `true`, right-side timer/buttons use a transparent
/// (`Color::Reset`) background instead of `theme.bg_base`, so the row blends
/// with the terminal's own background (minimal mode).
///
/// # Returns
/// A [`TurnStatusOutput`] containing the cancel button hit area (if rendered).
#[allow(clippy::too_many_arguments)]
pub fn render_turn_status(
buf: &mut Buffer,
area: Rect,
state: &AgentState,
activity: &Option<TurnActivity>,
turn_elapsed: Option<Duration>,
activity_started_at: Option<Instant>,
tick: u64,
drain_blocked: bool,
buttons: Option<MouseButtons>,
has_running_execute: bool,
total_tokens: Option<u64>,
mcp_init_progress: Option<&McpInitProgress>,
is_bash_turn: bool,
is_pending_user_input: bool,
goal_verifying: bool,
watchers: Watchers,
parked: bool,
flat_background: bool,
held_queue: usize,
held_queue_top_sendable: bool,
args: TurnStatusArgs<'_>,
) -> TurnStatusOutput {
let TurnStatusArgs {
state,
activity,
turn_elapsed,
activity_started_at,
tick,
drain_blocked,
buttons,
has_running_execute,
total_tokens,
mcp_init_progress,
is_bash_turn,
is_pending_user_input,
goal_verifying,
watchers,
parked,
flat_background,
held_queue,
held_queue_top_sendable,
} = args;
// Resolve the mouse affordances: a keyboard-only host (`None`) suppresses
// both buttons and reports no hover.
let show_buttons = buttons.is_some();
@ -289,15 +306,22 @@ pub fn render_turn_status(
// turn spinner (see MONITOR_PULSE_DIVISOR).
let frames = crate::glyphs::monitor_icon_frames();
let frame_idx = (tick / MONITOR_PULSE_DIVISOR) as usize % frames.len();
let icon = format!("{} ", frames[frame_idx]);
let label_fg = if buttons.is_some_and(|b| b.watching_hovered) {
theme.text_primary
} else {
theme.gray
};
let cue_width = (icon.width() + cue.width()).min(area.width as usize) as u16;
let spans = vec![
Span::styled(
format!("{} ", frames[frame_idx]),
Style::default().fg(theme.accent_system),
),
Span::styled(cue, Style::default().fg(theme.gray)),
Span::styled(icon, Style::default().fg(theme.accent_system)),
Span::styled(cue, Style::default().fg(label_fg)),
];
buf.set_line(area.x, area.y, &Line::from(spans), area.width);
return TurnStatusOutput::default();
return TurnStatusOutput {
watching_cue: show_buttons.then(|| Rect::new(area.x, area.y, cue_width, 1)),
..TurnStatusOutput::default()
};
}
// Parked with no watchers left: render nothing. The stopped look must
@ -603,6 +627,7 @@ pub fn render_turn_status(
TurnStatusOutput {
cancel_button: cancel_button_rect,
bg_button: bg_button_rect,
watching_cue: None,
}
}
@ -1123,33 +1148,49 @@ mod tests {
.join("\n")
}
/// Baseline render args: idle agent on a mouse host with the given watchers.
fn idle_args<'a>(watchers: Watchers) -> TurnStatusArgs<'a> {
TurnStatusArgs {
state: &AgentState::Idle,
activity: &None,
turn_elapsed: None,
activity_started_at: None,
tick: 0,
drain_blocked: false,
buttons: Some(MouseButtons::default()),
has_running_execute: false,
total_tokens: None,
mcp_init_progress: None,
is_bash_turn: false,
is_pending_user_input: false,
goal_verifying: false,
watchers,
parked: false,
flat_background: false,
held_queue: 0,
held_queue_top_sendable: false,
}
}
/// Render `args` into a `width`×1 row.
fn render_row(args: TurnStatusArgs<'_>, width: u16) -> (TurnStatusOutput, Buffer) {
let area = Rect::new(0, 0, width, 1);
let mut buf = Buffer::empty(area);
let output = render_turn_status(&mut buf, area, args);
(output, buf)
}
/// Render `args` into a `width`×1 row, returning the visible text.
fn render_row_text(args: TurnStatusArgs<'_>, width: u16) -> String {
let (_, buf) = render_row(args, width);
buffer_text(&buf, buf.area)
}
/// Invoke `render_turn_status` for an idle agent with the given MCP seed.
fn render_idle_with_mcp(progress: &McpInitProgress) -> String {
let area = Rect::new(0, 0, 60, 1);
let mut buf = Buffer::empty(area);
render_turn_status(
&mut buf,
area,
&AgentState::Idle,
&None,
None,
None,
0,
false,
Some(MouseButtons::default()),
false,
None,
Some(progress),
false,
false,
false,
Watchers::default(),
false,
false,
0,
false,
);
buffer_text(&buf, area)
let mut args = idle_args(Watchers::default());
args.mcp_init_progress = Some(progress);
render_row_text(args, 60)
}
/// Invoke `render_turn_status` for an idle agent with the given watcher
@ -1160,61 +1201,21 @@ mod tests {
/// [`render_idle_with_watchers_at_tick`] with an explicit row width.
fn render_idle_with_watchers_in_width(watchers: Watchers, tick: u64, width: u16) -> String {
let area = Rect::new(0, 0, width, 1);
let mut buf = Buffer::empty(area);
render_turn_status(
&mut buf,
area,
&AgentState::Idle,
&None,
None,
None,
tick,
false,
Some(MouseButtons::default()),
false,
None,
None,
false,
false,
false,
watchers,
false,
false,
0,
false,
);
buffer_text(&buf, area)
let mut args = idle_args(watchers);
args.tick = tick;
render_row_text(args, width)
}
/// Invoke `render_turn_status` for a PARKED running turn (the stopped
/// look) with the given watcher counts.
fn render_parked_with_watchers(watchers: Watchers) -> String {
let area = Rect::new(0, 0, 72, 1);
let mut buf = Buffer::empty(area);
render_turn_status(
&mut buf,
area,
&AgentState::TurnRunning,
&Some(TurnActivity::Waiting(WaitingReason::TasksComplete)),
Some(Duration::from_secs(5)),
None,
0,
false,
Some(MouseButtons::default()),
false,
None,
None,
false,
false,
false,
watchers,
true,
false,
0,
false,
);
buffer_text(&buf, area)
let activity = Some(TurnActivity::Waiting(WaitingReason::TasksComplete));
let mut args = idle_args(watchers);
args.state = &AgentState::TurnRunning;
args.activity = &activity;
args.turn_elapsed = Some(Duration::from_secs(5));
args.parked = true;
render_row_text(args, 72)
}
/// Invoke `render_turn_status` for an idle agent with the given watcher
@ -1268,6 +1269,38 @@ mod tests {
);
}
/// Mouse hosts get a hit rect hugging exactly the rendered cue text, and
/// hover brightens the label; keyboard-only hosts get neither.
#[test]
fn watching_cue_is_clickable_on_mouse_hosts_only() {
let theme = Theme::current();
let watchers = Watchers {
monitors: 1,
..Watchers::default()
};
// First label cell (after the 2-col icon).
let label_fg = |buf: &Buffer| buf.cell((2, 0)).map(|c| c.fg);
let (output, buf) = render_row(idle_args(watchers), 60);
let rect = output.watching_cue.expect("mouse host must get a hit rect");
let rendered_width = buffer_text(&buf, buf.area).trim_end().width() as u16;
assert_eq!(rect, Rect::new(0, 0, rendered_width, 1));
assert_eq!(label_fg(&buf), Some(theme.gray));
let mut args = idle_args(watchers);
args.buttons = Some(MouseButtons {
watching_hovered: true,
..MouseButtons::default()
});
let (_, buf) = render_row(args, 60);
assert_eq!(label_fg(&buf), Some(theme.text_primary));
let mut args = idle_args(watchers);
args.buttons = None;
let (output, _) = render_row(args, 60);
assert!(output.watching_cue.is_none());
}
#[test]
fn idle_with_loops_renders_still_running_cue() {
let text = render_idle_with_watchers(Watchers {
@ -1439,31 +1472,14 @@ mod tests {
#[test]
fn queued_hint_renders_after_phase_timer() {
let area = Rect::new(0, 0, 80, 1);
let mut buf = Buffer::empty(area);
render_turn_status(
&mut buf,
area,
&AgentState::TurnRunning,
&Some(TurnActivity::Waiting(WaitingReason::Subagent)),
None,
Some(Instant::now() - Duration::from_secs(359)),
0,
false,
Some(MouseButtons::default()),
false,
None,
None,
false,
false,
false,
Watchers::default(),
false,
false,
1,
true,
);
let text = buffer_text(&buf, area);
let activity = Some(TurnActivity::Waiting(WaitingReason::Subagent));
let mut args = idle_args(Watchers::default());
args.state = &AgentState::TurnRunning;
args.activity = &activity;
args.activity_started_at = Some(Instant::now() - Duration::from_secs(359));
args.held_queue = 1;
args.held_queue_top_sendable = true;
let text = render_row_text(args, 80);
assert!(
text.contains("Waiting on subagent… 5m59s · 1 queued — Enter to send now"),
"phase timer must sit between the wait label and the queued hint, got: {text:?}"