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

@ -6,9 +6,9 @@ pub(crate) use serde_json::json;
pub(crate) use std::path::Path;
pub(crate) use std::time::{Duration, Instant};
pub(crate) use xai_grok_pager_pty_harness::{
ContentController, MockModel, PtyHarness, ScriptedResponse, SseEvent, keys,
oauth_env_for_pager, pager_binary, seed_fake_oauth, sse, wait_for_labels_absent,
wait_for_model_via_new_sessions,
ContentController, InferenceEndpoint, InferenceRequestMatcher, MockModel, PtyHarness,
ScriptedResponse, SseEvent, keys, oauth_env_for_pager, pager_binary, seed_fake_oauth, sse,
wait_for_labels_absent, wait_for_model_via_new_sessions,
};
/// Default PTY size used by every e2e test. Large enough to render the
@ -1116,6 +1116,18 @@ const WRAP_DRAIN_TIMEOUT: Duration = Duration::from_secs(10);
/// before auth/network/sandbox.
#[cfg(unix)]
pub(crate) fn run_wrap(wrap_args: &[&str], extra_env: &[(&str, &str)]) -> (Option<u32>, String) {
run_wrap_driving(wrap_args, extra_env, |_| {})
}
/// Like [`run_wrap`], but hands the live harness to `drive` right after spawn
/// so a test can interact mid-run (wait for output, deliver signals to wrap
/// itself) before the exit-and-drain phase.
#[cfg(unix)]
pub(crate) fn run_wrap_driving(
wrap_args: &[&str],
extra_env: &[(&str, &str)],
drive: impl FnOnce(&mut PtyHarness),
) -> (Option<u32>, String) {
let binary = pager_binary().expect("resolve pager binary");
let home = tempfile::tempdir().expect("home tempdir");
let home_str = home.path().to_str().expect("utf8 home").to_owned();
@ -1128,6 +1140,8 @@ pub(crate) fn run_wrap(wrap_args: &[&str], extra_env: &[(&str, &str)]) -> (Optio
let mut harness =
PtyHarness::new(&binary, DEFAULT_ROWS, DEFAULT_COLS, &args, &env).expect("spawn grok wrap");
drive(&mut harness);
let code = harness
.wait_for_exit_and_drain(WRAP_TIMEOUT, WRAP_DRAIN_TIMEOUT)
.ok();

View file

@ -10,13 +10,18 @@ use super::common::*;
#[ignore]
async fn empty_enter_force_sends_top_queued() {
let content = ContentController::start().await.expect("start content");
// Gate turn 1's terminal event so the queue + empty-Enter provably land
// mid-turn regardless of suite load.
content.hold_agent_completions();
content.set_turns([
slow_turn_text("TURNONE"),
"TURNTWO reply to the promoted follow-up.".to_owned(),
]);
let mut turn_one = content.expect_response_blocked(
"running turn before send-now",
InferenceRequestMatcher::foreground(InferenceEndpoint::ChatCompletions),
ScriptedResponse::sse(chat_completions_message_events(&slow_turn_text("TURNONE"))),
);
let mut turn_two = content.expect_response(
"promoted queued follow-up",
InferenceRequestMatcher::foreground(InferenceEndpoint::ChatCompletions),
ScriptedResponse::sse(chat_completions_message_events(
"TURNTWO reply to the promoted follow-up.",
)),
);
let binary = pager_binary().expect("resolve pager binary");
let mut harness =
@ -32,6 +37,9 @@ async fn empty_enter_force_sends_top_queued() {
harness
.wait_for_text("TURNONE", Duration::from_secs(30))
.expect("turn 1 streaming");
tokio::time::timeout(Duration::from_secs(10), turn_one.wait_blocked())
.await
.expect("turn 1 reached the completion barrier");
harness
.inject_keys(b"please also check the logs\r")
@ -44,7 +52,7 @@ async fn empty_enter_force_sends_top_queued() {
// shell cancels turn 1 (the abort beats the held completion) and promotes
// the row to run as turn 2.
harness.inject_keys(b"\r").expect("empty Enter send-now");
content.release_agent_completions();
turn_one.release();
// The promoted row renders as a standard " " prompt block via the
// turn-start adoption (the arrow prefix distinguishes the committed block
// from the prefix-less queue row).
@ -58,6 +66,9 @@ async fn empty_enter_force_sends_top_queued() {
harness
.wait_for_text("TURNTWO", Duration::from_secs(40))
.expect("promoted turn reply");
tokio::time::timeout(Duration::from_secs(10), turn_two.wait_satisfied())
.await
.expect("promoted turn expectation satisfied");
// The send-now cancel is silent: no cancelled marker between the partial
// turn-1 output and the promoted prompt.

View file

@ -10,14 +10,25 @@ use super::common::*;
#[ignore]
async fn empty_enter_sends_top_not_last_of_two() {
let content = ContentController::start().await.expect("start content");
// Gate turn 1's terminal event so both queues + the empty Enter provably
// land while turn 1 is still the running turn.
content.hold_agent_completions();
content.set_turns([
slow_turn_text("TURNONE"),
"TURNTWO top-row send-now acknowledged.".to_owned(),
"TURNTHREE remaining queue promoted.".to_owned(),
]);
let mut turn_one = content.expect_response_blocked(
"running turn before top-row send-now",
InferenceRequestMatcher::foreground(InferenceEndpoint::ChatCompletions),
ScriptedResponse::sse(chat_completions_message_events(&slow_turn_text("TURNONE"))),
);
let mut turn_two = content.expect_response(
"top queued row",
InferenceRequestMatcher::foreground(InferenceEndpoint::ChatCompletions),
ScriptedResponse::sse(chat_completions_message_events(
"TURNTWO top-row send-now acknowledged.",
)),
);
let mut turn_three = content.expect_response(
"remaining queued row",
InferenceRequestMatcher::foreground(InferenceEndpoint::ChatCompletions),
ScriptedResponse::sse(chat_completions_message_events(
"TURNTHREE remaining queue promoted.",
)),
);
let binary = pager_binary().expect("resolve pager binary");
let mut harness =
@ -33,6 +44,9 @@ async fn empty_enter_sends_top_not_last_of_two() {
harness
.wait_for_text("TURNONE", Duration::from_secs(45))
.expect("turn 1 streaming");
tokio::time::timeout(Duration::from_secs(10), turn_one.wait_blocked())
.await
.expect("turn 1 reached completion barrier");
harness
.inject_keys(b"queue-alpha-top\r")
@ -50,7 +64,7 @@ async fn empty_enter_sends_top_not_last_of_two() {
harness
.inject_keys(b"\r")
.expect("empty Enter send-now top");
content.release_agent_completions();
turn_one.release();
// Alpha (the promoted TOP row) then bravo drain back-to-back. Each
// promoted " …" block and the intermediate TURNTWO reply is scrolled
// above the viewport by the next turn's start-adoption before a 100ms poll
@ -61,6 +75,12 @@ async fn empty_enter_sends_top_not_last_of_two() {
harness
.wait_for_text("TURNTHREE", Duration::from_secs(90))
.expect("all queued turns drained through to the final reply");
tokio::time::timeout(Duration::from_secs(10), turn_two.wait_satisfied())
.await
.expect("top queued row expectation satisfied");
tokio::time::timeout(Duration::from_secs(10), turn_three.wait_satisfied())
.await
.expect("remaining queued row expectation satisfied");
// The send-now cancel of turn 1 is silent.
assert!(

View file

@ -0,0 +1,58 @@
// Per-test-case module for the `pty_e2e` integration test crate.
#[allow(unused_imports)]
use super::common::*;
/// Dirty-death e2e: when the wrapped child dies with DEC private modes still
/// latched, `grok wrap` must emit the matching resets so the outer terminal is
/// not left broken.
///
/// The child SIGKILLs itself after enabling alt screen, all-motion mouse
/// tracking, SGR mouse encoding, bracketed paste, and cursor hide. From wrap's
/// perspective a child SIGKILL is byte-identical to the local ssh client dying
/// on a transport drop (laptop sleep, `~.`, remote host gone): the PTY hits
/// EOF with the enables' reset bytes never having arrived. Only wrap survives
/// to clean up the local terminal.
#[test]
#[ignore = "PTY e2e; run the owning pty_e2e_* Cargo test with --ignored (see Cargo.toml)"]
#[cfg(unix)]
fn wrap_child_killed_with_latched_modes_restores_terminal() {
let (code, raw) = run_wrap(
&[
"/bin/sh",
"-c",
r"printf '\033[?1049h\033[?1003h\033[?1006h\033[?2004h\033[?25l'; kill -KILL $$",
],
&[],
);
assert!(
code.is_some(),
"wrap must exit after the child is killed\nraw:\n{raw:?}"
);
// All resets must appear after the last enable (the cursor hide): they can
// only have come from wrap's own restore path, not from the dead child.
let last_enable = raw
.rfind("\x1b[?25l")
.unwrap_or_else(|| panic!("child's mode enables must pass through\nraw:\n{raw:?}"));
let reset_pos = |needle: &str| -> usize {
match raw.rfind(needle) {
Some(pos) if pos > last_enable => pos,
Some(_) => {
panic!("reset {needle:?} must appear after the child's enables\nraw:\n{raw:?}")
}
None => panic!(
"wrap must emit {needle:?} for a mode the dead child left latched\nraw:\n{raw:?}"
),
}
};
let alt_screen_leave = reset_pos("\x1b[?1049l");
for needle in ["\x1b[?1003l", "\x1b[?1006l", "\x1b[?2004l", "\x1b[?25h"] {
let pos = reset_pos(needle);
assert!(
pos < alt_screen_leave,
"alt-screen leave must come last among the resets ({needle:?} at {pos} vs \
?1049l at {alt_screen_leave})\nraw:\n{raw:?}"
);
}
}

View file

@ -0,0 +1,51 @@
// Per-test-case module for the `pty_e2e` integration test crate.
#[allow(unused_imports)]
use super::common::*;
/// Transparency e2e: when the wrapped child balances every mode it enables and
/// exits cleanly, `grok wrap` must add zero reset bytes of its own. Blindly
/// blasting resets on exit would be visible here (duplicate disables, and a
/// kitty pop that could corrupt an enclosing context's keyboard stack); the
/// mode tracker keeps clean exits byte-for-byte transparent.
#[test]
#[ignore = "PTY e2e; run the owning pty_e2e_* Cargo test with --ignored (see Cargo.toml)"]
#[cfg(unix)]
fn wrap_clean_exit_stays_byte_transparent() {
let (code, raw) = run_wrap(
&[
"/bin/sh",
"-c",
concat!(
r"printf '\033[?1049h\033[?1003h\033[?1006h\033[?2004h\033[?25l'; ",
r"printf '\033[?25h\033[?2004l\033[?1006l\033[?1003l\033[?1049l'",
),
],
&[],
);
assert_eq!(
code,
Some(0),
"clean child exit must propagate\nraw:\n{raw:?}"
);
// Exactly the child's own disables — one occurrence each. A second copy
// means wrap injected resets on a clean exit.
for needle in [
"\x1b[?1003l",
"\x1b[?1006l",
"\x1b[?2004l",
"\x1b[?25h",
"\x1b[?1049l",
] {
assert_eq!(
raw.matches(needle).count(),
1,
"clean exit must stay byte-transparent: expected exactly the child's own \
{needle:?}\nraw:\n{raw:?}"
);
}
assert!(
!raw.contains("\x1b[<u"),
"wrap must not pop a kitty keyboard stack the child never pushed\nraw:\n{raw:?}"
);
}

View file

@ -0,0 +1,48 @@
// Per-test-case module for the `pty_e2e` integration test crate.
#[allow(unused_imports)]
use super::common::*;
/// Signal-death e2e: SIGTERM delivered to `grok wrap` itself (external kill,
/// terminal-close HUP class) must not skip cleanup. Drop handlers never run on
/// signal death, so wrap needs an explicit signal path that forwards the
/// signal to the child, emits the resets for whatever the child left latched,
/// and exits with the conventional 128+N code.
///
/// Uses `run_wrap_driving` to signal wrap mid-run, and only after a READY
/// sentinel proves the enables already flowed through wrap (signaling earlier
/// would race the latch).
#[test]
#[ignore = "PTY e2e; run the owning pty_e2e_* Cargo test with --ignored (see Cargo.toml)"]
#[cfg(unix)]
fn wrap_sigterm_restores_terminal_and_exit_code() {
let (code, raw) = run_wrap_driving(
&[
"/bin/sh",
"-c",
r"printf '\033[?1003h\033[?1006h\033[?2004h\033[?25l'; printf 'WRAP_E2E_READY'; sleep 60",
],
&[],
|harness| {
harness
.wait_until(
"child mode enables to flow through wrap",
WRAP_TIMEOUT,
|h| String::from_utf8_lossy(h.raw_output()).contains("WRAP_E2E_READY"),
)
.expect("child never latched its modes");
harness.send_signal(libc::SIGTERM).expect("SIGTERM wrap");
},
);
assert_eq!(
code,
Some(143),
"SIGTERM death must surface as the conventional 128+15\nraw:\n{raw:?}"
);
for needle in ["\x1b[?1003l", "\x1b[?1006l", "\x1b[?2004l", "\x1b[?25h"] {
assert!(
raw.contains(needle),
"wrap's signal path must emit {needle:?} for the latched mode\nraw:\n{raw:?}"
);
}
}