Synced from monorepo

Changes:
- Classify clipboard delivery confidence
- Add durable session update append
- Scope the xAI session bearer to first-party memory embedding endpoints
- Persist subagent outputs to disk and bound long-lived agent state
- Add MiniSweAgent:bash for mini-swe-agent parity
- Revert taking local sessions off the persistent shell
- Contextual tip recommending grok wrap on SSH sessions
- Voice STT bearer from model BYOK env_key/api_key
- Define exact website policies for sandbox
- Gate unsafe shell environments
- Shared pin hoist; single require_sha gate for marketplace plugins
- Server-signed is-managed claim (closes sidecar-removal downgrade)
- Optional require_sha pin for remote plugin installs
- Show session title and last exchange in the exit resume hint
- Gate shell output redirects
- Warn when fail_closed is present but not a boolean
- Add canonical text editing core (ratatui-textarea)
- Keep execution state out of goal scratch
- Add acknowledged persistence primitives
- Inherit child network restrictions in sandbox
- Fail closed when hook matchers fail to recompile
- Add MCP setup preferences for plugin MCPs
- Gate sourced shell scripts
- Gate file-typed project hooks
- grok wrap: restore terminal modes on child death
- Harden owner-only permissions on auth and MCP credentials
- Create crash dump files with owner-only permissions
- Write the agent_id cache owner-only (0600)
- SessionMetrics mode skips Mixpanel profile sync
- Dashboard: slim live-tail peek
- Yank full queued prompt text, not (+N lines)
- Defeat clock-rollback on the signed managed-config cache
- Stop early session/cancel from overtaking the prompt and wedging the turn slot
- Self-heal a diverged agent entrypoint on startup
- Add matched inference expectations in test-support
- Add AuthSingleFlight cancel/successor gap tests
- Remove consumer from external OTEL allowlist and pin scrub coverage
- Enable /copy in minimal mode
- Surface capacity and API-key detail on 429 errors
- Single-flight interactive auth
- Fix PageUp/PageDown skipping lines behind sticky prompt header
This commit is contained in:
grokkybara[bot] 2026-07-17 14:19:50 +01:00
commit 98c3b2438a
225 changed files with 18836 additions and 7156 deletions

View file

@ -915,6 +915,10 @@ pub struct AppView {
/// first evaluation at a stable agent-view draw (regardless of outcome),
/// so later resizes can never re-trigger the tip within this run.
pub small_screen_tip_evaluated: bool,
/// One-shot gate for the SSH `grok wrap` tip: set after the first
/// evaluation at a stable agent-view draw (the environment gates are
/// process-constant, so one evaluation decides the run).
pub ssh_wrap_tip_evaluated: bool,
/// Focus-scoped, opportunistically-polled clipboard-image tip state: poll
/// throttle, changeCount delta-detection, fire cooldown, and changeCount
/// dedup (macOS-only at the probe layer).
@ -955,6 +959,9 @@ pub struct AppView {
pub auth_code_input: String,
/// Monotonically increasing sequence number for auth requests.
pub next_auth_request_seq: u64,
/// Abort handle for the in-flight `PollAuthUrl` task (with its request_seq).
/// Aborted alongside the Authenticate task in single-flight re-login.
pub auth_url_poll_handle: Option<(u64, tokio::task::AbortHandle)>,
/// Every session/chat/worktree/prompt action deferred behind startup gates.
pub deferred_startup: crate::app::session_startup::DeferredStartupActions,
/// Whether deferred welcome-screen login should force OAuth.
@ -1275,6 +1282,7 @@ impl AppView {
tip_seen_counts: Default::default(),
last_known_terminal_rows: 0,
small_screen_tip_evaluated: false,
ssh_wrap_tip_evaluated: false,
clipboard_focus_tip: Default::default(),
new_session_worktree_mode: WorktreeMode::Never,
fork_worktree_mode: WorktreeMode::Ask,
@ -1289,6 +1297,7 @@ impl AppView {
auth_start_mode: AuthMode::Pending,
auth_code_input: String::new(),
next_auth_request_seq: 1,
auth_url_poll_handle: None,
deferred_startup: Default::default(),
auth_use_oauth: false,
auth_clipboard_copied: false,
@ -1647,6 +1656,16 @@ impl AppView {
None
}
}
/// The active agent's view, when an agent tab is focused.
///
/// Always the root agent, even when a subagent view is focused within the
/// tab; for subagent-aware resolution use `dispatch::ctx::get_active_agent`.
pub fn active_agent(&self) -> Option<&AgentView> {
match self.active_view {
ActiveView::Agent(id) => self.agents.get(&id),
_ => None,
}
}
/// Session ID of the active agent, if one exists and has an established session.
pub fn active_session_id(&self) -> Option<&str> {
match self.active_view {
@ -3741,6 +3760,7 @@ impl AppView {
}
}
self.maybe_trigger_small_screen_tip();
self.maybe_trigger_ssh_wrap_tip();
let compact = self.appearance.prompt.compact;
let (header_pad_left, header_pad_right, header_pad_top) = {
let layout_cfg = &self.appearance.scrollback.layout;
@ -4076,6 +4096,11 @@ impl AppView {
d.overlay_prev_hit.set(header.and_then(|c| c.prev_rect));
d.overlay_next_hit.set(header.and_then(|c| c.next_rect));
}
if let Some(d) = self.dashboard.as_mut()
&& d.peek_viewport.is_some()
{
d.restore_peek_viewport(agents);
}
if let Some(agent) = agents.get_mut(&id) {
let announcement_banner_h =
crate::views::announcements::session_banner_height(
@ -4425,6 +4450,59 @@ impl AppView {
self.small_screen_tip_evaluated = true;
super::dispatch::show_small_screen_tip(self);
}
/// One-shot SSH `grok wrap` tip trigger, run at the top of every `draw`
/// right after [`Self::maybe_trigger_small_screen_tip`]. The welcome
/// screen has no ephemeral-tip row, so the first stable agent-view draw
/// is the earliest surface that can paint a session-load tip. Reads the
/// live environment (cached statics) and delegates to the injectable
/// inner so tests never depend on the host's SSH shape.
pub(crate) fn maybe_trigger_ssh_wrap_tip(&mut self) {
if self.ssh_wrap_tip_evaluated {
return;
}
static ENV_RECOMMENDS_WRAP: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
let env_recommends_wrap = *ENV_RECOMMENDS_WRAP.get_or_init(|| {
let ctx = crate::terminal::terminal_context();
crate::diagnostics::ssh_wrap_hint(
ctx.is_ssh,
crate::clipboard::osc52_sink_active(),
ctx.is_official_vscode_remote,
)
.is_some()
});
self.maybe_trigger_ssh_wrap_tip_inner(env_recommends_wrap);
}
/// Inner trigger with the environment verdict injected
/// (`diagnostics::ssh_wrap_hint` on the live path). Same
/// defer-vs-consume rules as the small-screen trigger above, with two
/// deltas: the environment gates are process-constant, so a failing
/// verdict consumes the one-shot; and a busy tip slot defers instead of
/// replacing — both session-load tips can qualify on the same first
/// draw, and replacing would burn the other tip's once-per-session show,
/// while this one loses nothing by waiting for a later draw.
pub(crate) fn maybe_trigger_ssh_wrap_tip_inner(&mut self, env_recommends_wrap: bool) {
if self.ssh_wrap_tip_evaluated {
return;
}
let ActiveView::Agent(id) = self.active_view else {
return;
};
let Some(agent) = self.agents.get(&id) else {
return;
};
if agent.terminal_size_stale || agent.last_terminal_size == (0, 0) {
return;
}
if !env_recommends_wrap {
self.ssh_wrap_tip_evaluated = true;
return;
}
if !agent.ephemeral_tip_can_render() || agent.ephemeral_tip.is_active() {
return;
}
self.ssh_wrap_tip_evaluated = true;
super::dispatch::show_ssh_wrap_tip(self);
}
/// Whether the clipboard-image tip may poll right now — the single in-window
/// gate. Outside it the poll touches the pasteboard ZERO times: contextual
/// hints on, the probe supported (macOS), past the fire cooldown, the
@ -5110,6 +5188,7 @@ pub(crate) mod tests {
tip_seen_counts: Default::default(),
last_known_terminal_rows: 0,
small_screen_tip_evaluated: false,
ssh_wrap_tip_evaluated: false,
clipboard_focus_tip: Default::default(),
new_session_worktree_mode: WorktreeMode::Never,
fork_worktree_mode: WorktreeMode::Ask,
@ -5124,6 +5203,7 @@ pub(crate) mod tests {
auth_start_mode: AuthMode::Pending,
auth_code_input: String::new(),
next_auth_request_seq: 1,
auth_url_poll_handle: None,
deferred_startup: Default::default(),
auth_use_oauth: false,
auth_clipboard_copied: false,
@ -5240,7 +5320,7 @@ pub(crate) mod tests {
voice_state: VoiceState::Idle,
}
}
fn test_app_with_agent() -> AppView {
pub(crate) fn test_app_with_agent() -> AppView {
let mut app = test_app();
let id = super::super::agent::AgentId(0);
let mut agent = AgentView::new(