Synced from monorepo
Changes: - Non-blocking coding-data sharing upsell banner - Consolidate remediation in Doctor - Auto mode defers fail-closed gate asks to the classifier - Coalesce marketplace list fetches - Allow removing a marketplace source by name - Contain hung git marketplace sources (timeouts, non-blocking refresh, unbrick modal) - Label failed workspace RPCs with error_kind - Drop redundant explicit tonic/prost deps from xai-grok-shell - Report real exit codes for completed background shells - Narrow the date-rollover reminder to date-bearing templates - Wire toolOverrides through the session and agent - Security: Bash(git:*) allowlist matches whole command chain by prefix - Split prompt-trigger telemetry and record classifier provenance - Raise connectors-manager timeout to 60s - Auto classifier honors recorded approvals for repeat actions - Apply doctor fixes in the TUI - Auto-mode classifier timeouts prompt instead of silently denying - Scope subagent completion drains to the owning session - Add the toolOverrides wire types - Set client_identifier=grok-agent-sdk - Accept both spellings of the workspace-teleport kill switch - Persist one-shot occurrence journal - Stop turns that poll the exact same tool call 16x in a row - Copy compaction checkpoint files when forking sessions - Auto-focus permission prompt from scrollback - Esc cancels the running turn in non-vim and minimal modes - List Ctrl+Z undo and redo in keyboard shortcuts - Out-of-process macOS mic capture - Show active auth mode on session-info - Install the npm binary under $GROK_HOME - Remove hover/click dead zones between dashboard items - Route startup warnings to doctor - Document [feedback.user] author identity config - Extend bang command timeout - Close combine-queued edit-hold race - Integrate relocation recovery - Expose privacy notice rollout flag - Break harness discovery ref cycle so connections can idle-evict - Shift/Alt+Enter inserts newline when editing a queued prompt - Gate project Claude permissions on folder trust - Echo response.create.event_id on response.created - Toast when session creation fails from disk full - Add shared test process lifecycle - Enable dynamic workflows by default - Add relocation transaction state machine - Add shared test sandbox - Surface auth failures on model-switch compact - Persist durable scheduler expiry - Confirm before removing extensions-modal items - Re-run compact and prompt after login when compact hit expired auth - Recap sends hosted tools under backend search
This commit is contained in:
parent
3af4d5d398
commit
a5727c5960
482 changed files with 37627 additions and 13402 deletions
|
|
@ -42,11 +42,10 @@ async fn minimal_commits_thinking_body_to_scrollback() {
|
|||
)
|
||||
.expect("write config");
|
||||
|
||||
let env = content.env_for_pager();
|
||||
let env_refs: Vec<(&str, &str)> = env.iter().map(|(k, v)| (k.as_str(), v.as_str())).collect();
|
||||
let binary = pager_binary().expect("resolve pager binary");
|
||||
let mut harness = PtyHarness::new(&binary, DEFAULT_ROWS, DEFAULT_COLS, MINIMAL_ARGS, &env_refs)
|
||||
.expect("spawn minimal pager");
|
||||
let mut harness =
|
||||
PtyHarness::spawn_with_content(&binary, DEFAULT_ROWS, DEFAULT_COLS, &content, MINIMAL_ARGS)
|
||||
.expect("spawn minimal pager");
|
||||
harness.set_respond_to_queries(true);
|
||||
|
||||
wait_minimal_ready(&mut harness);
|
||||
|
|
|
|||
|
|
@ -27,10 +27,12 @@ async fn minimal_ctrl_c_arms_and_quits() {
|
|||
|
||||
// Second Ctrl+C within the confirm window exits the process.
|
||||
harness.inject_keys(b"\x03").expect("inject Ctrl+C again");
|
||||
let code = harness.wait_exit_code(Duration::from_secs(5));
|
||||
let exit = harness
|
||||
.wait_exit_code(Duration::from_secs(5))
|
||||
.expect("wait for minimal pager exit");
|
||||
assert!(
|
||||
code.is_some(),
|
||||
"second Ctrl+C should quit minimal\nscreen:\n{}",
|
||||
matches!(exit, PtyExitPoll::Exited(_) | PtyExitPoll::PendingStatus),
|
||||
"second Ctrl+C should quit minimal, got {exit:?}\nscreen:\n{}",
|
||||
harness.screen_contents()
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,14 +20,24 @@ async fn minimal_ctrl_o_send_now_queued_apple_terminal() {
|
|||
);
|
||||
|
||||
let binary = pager_binary().expect("resolve pager binary");
|
||||
let mut env = content.env_for_pager();
|
||||
env.push(("TERM_PROGRAM".into(), "Apple_Terminal".into()));
|
||||
let mut overrides: Vec<(String, String)> =
|
||||
vec![("TERM_PROGRAM".into(), "Apple_Terminal".into())];
|
||||
// Non-interactive $PAGER so a mistaken transcript open fails fast rather
|
||||
// than hanging in `less` if the predicate regresses.
|
||||
env.push(("PAGER".into(), "cat".into()));
|
||||
let env_refs: Vec<(&str, &str)> = env.iter().map(|(k, v)| (k.as_str(), v.as_str())).collect();
|
||||
let mut harness = PtyHarness::new(&binary, DEFAULT_ROWS, DEFAULT_COLS, MINIMAL_ARGS, &env_refs)
|
||||
.expect("spawn minimal + Apple_Terminal");
|
||||
overrides.push(("PAGER".into(), "cat".into()));
|
||||
let env_refs: Vec<(&str, &str)> = overrides
|
||||
.iter()
|
||||
.map(|(key, value)| (key.as_str(), value.as_str()))
|
||||
.collect();
|
||||
let mut harness = PtyHarness::spawn_with_content_env(
|
||||
&binary,
|
||||
DEFAULT_ROWS,
|
||||
DEFAULT_COLS,
|
||||
&content,
|
||||
MINIMAL_ARGS,
|
||||
&env_refs,
|
||||
)
|
||||
.expect("spawn minimal + Apple_Terminal");
|
||||
harness.set_respond_to_queries(true);
|
||||
|
||||
wait_minimal_ready(&mut harness);
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@ use crate::common::*;
|
|||
/// Minimal mode guards the documented `in_flight_committed` dogfood
|
||||
/// double-show: a promoted queued prompt's "❯ " block commits (prints) into
|
||||
/// native scrollback immediately, so cancelling its turn pre-first-token
|
||||
/// (minimal's cancel gesture is Ctrl+C; Esc is swallowed) must SKIP the
|
||||
/// composer rewind — a rewind would leave the printed block on screen AND
|
||||
/// refill the composer, showing the prompt twice. Standard cancel instead:
|
||||
/// the block renders exactly once and the cancel marker is visible.
|
||||
/// (via Ctrl+C here) must SKIP the composer rewind — a rewind would leave the
|
||||
/// printed block on screen AND refill the composer, showing the prompt twice.
|
||||
/// Standard cancel instead: the block renders exactly once and the cancel
|
||||
/// marker is visible.
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
#[ignore]
|
||||
async fn minimal_double_esc_committed_queued_prompt_single_render() {
|
||||
|
|
|
|||
|
|
@ -2,11 +2,13 @@
|
|||
#[allow(unused_imports)]
|
||||
use crate::common::*;
|
||||
|
||||
/// Mid-turn Esc in minimal mode is a swallowed no-op (the prompt is always
|
||||
/// focused). Esc must NOT cancel; cancel remains on Ctrl+C.
|
||||
/// Esc cancels a running turn in minimal mode (the prompt is always focused, so
|
||||
/// the turn-running Esc branch wins; minimal enables the Esc-cancel gate
|
||||
/// regardless of vim mode). The cancellation marker is finalized and committed
|
||||
/// to native scrollback like any other block.
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
#[ignore]
|
||||
async fn minimal_esc_mid_turn_is_swallowed() {
|
||||
async fn minimal_esc_cancels_running_turn() {
|
||||
let content = ContentController::start().await.expect("start content");
|
||||
// Paced, long stream so the turn is provably still running when Esc lands.
|
||||
let long = format!(
|
||||
|
|
@ -26,27 +28,13 @@ async fn minimal_esc_mid_turn_is_swallowed() {
|
|||
.wait_for_text(MOCK_RESPONSE_SENTINEL, Duration::from_secs(30))
|
||||
.expect("turn streaming in the live tail");
|
||||
|
||||
harness.inject_keys(keys::ESC).expect("press esc");
|
||||
harness.update(Duration::from_millis(1000));
|
||||
harness.inject_keys(keys::ESC).expect("press esc to cancel");
|
||||
|
||||
// Full-text: minimal commits the cancel marker to native scrollback, so it
|
||||
// may sit above the pinned viewport — check scrollback + screen.
|
||||
assert!(
|
||||
!harness.contains_full_text("Turn cancelled by user"),
|
||||
"mid-turn Esc must NOT cancel in minimal mode\nfull contents:\n{}",
|
||||
harness.full_text()
|
||||
);
|
||||
|
||||
// Positive tail: prove the turn was still alive at Esc-time (the negative
|
||||
// check above would false-pass on an already-finished turn) and that
|
||||
// Ctrl+C — the replacement cancel gesture — works in minimal mode. The
|
||||
// prompt is empty and the turn is running, so Ctrl+C cancels (the minimal
|
||||
// quit arm applies only to an idle empty prompt).
|
||||
harness.inject_keys(keys::CTRL_C).expect("press ctrl+c");
|
||||
harness
|
||||
.wait_for_full_text("Turn cancelled by user", Duration::from_secs(15))
|
||||
.expect("Ctrl+C must cancel the still-running turn in minimal mode");
|
||||
|
||||
.expect("cancellation marker committed to scrollback");
|
||||
assert!(
|
||||
!harness.contains_text("panicked"),
|
||||
"pager panicked\nscreen:\n{}",
|
||||
|
|
@ -36,12 +36,16 @@ async fn minimal_external_editor_round_trip() {
|
|||
format!("'{}'", script.display())
|
||||
};
|
||||
|
||||
let mut env = content.env_for_pager();
|
||||
env.push(("VISUAL".to_owned(), editor));
|
||||
let env_refs: Vec<(&str, &str)> = env.iter().map(|(k, v)| (k.as_str(), v.as_str())).collect();
|
||||
let binary = pager_binary().expect("resolve pager binary");
|
||||
let mut harness = PtyHarness::new(&binary, DEFAULT_ROWS, DEFAULT_COLS, MINIMAL_ARGS, &env_refs)
|
||||
.expect("spawn minimal pager");
|
||||
let mut harness = PtyHarness::spawn_with_content_env_ops(
|
||||
&binary,
|
||||
DEFAULT_ROWS,
|
||||
DEFAULT_COLS,
|
||||
&content,
|
||||
MINIMAL_ARGS,
|
||||
&[EnvOp::set("VISUAL", &editor)],
|
||||
)
|
||||
.expect("spawn minimal pager");
|
||||
harness.set_respond_to_queries(true);
|
||||
|
||||
wait_minimal_ready(&mut harness);
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ async fn minimal_resize_preserves_committed_scrollback() {
|
|||
harness.update(Duration::from_millis(800));
|
||||
|
||||
assert!(
|
||||
harness.is_running(),
|
||||
harness.is_running().expect("poll pager liveness"),
|
||||
"pager exited during resize\nscreen:\n{}",
|
||||
harness.screen_contents()
|
||||
);
|
||||
|
|
|
|||
|
|
@ -17,12 +17,21 @@ async fn minimal_transcript_opens_in_pager() {
|
|||
|
||||
// Minimal env + PAGER=cat (non-interactive). Response forwarding on so the
|
||||
// inline-viewport cursor probe completes (see spawn_minimal).
|
||||
let mut env = content.env_for_pager();
|
||||
env.push(("PAGER".to_string(), "cat".to_string()));
|
||||
let env_refs: Vec<(&str, &str)> = env.iter().map(|(k, v)| (k.as_str(), v.as_str())).collect();
|
||||
let overrides: Vec<(String, String)> = vec![("PAGER".to_string(), "cat".to_string())];
|
||||
let env_refs: Vec<(&str, &str)> = overrides
|
||||
.iter()
|
||||
.map(|(key, value)| (key.as_str(), value.as_str()))
|
||||
.collect();
|
||||
let binary = pager_binary().expect("resolve pager binary");
|
||||
let mut harness = PtyHarness::new(&binary, DEFAULT_ROWS, DEFAULT_COLS, MINIMAL_ARGS, &env_refs)
|
||||
.expect("spawn minimal pager");
|
||||
let mut harness = PtyHarness::spawn_with_content_env(
|
||||
&binary,
|
||||
DEFAULT_ROWS,
|
||||
DEFAULT_COLS,
|
||||
&content,
|
||||
MINIMAL_ARGS,
|
||||
&env_refs,
|
||||
)
|
||||
.expect("spawn minimal pager");
|
||||
harness.set_respond_to_queries(true);
|
||||
|
||||
wait_minimal_ready(&mut harness);
|
||||
|
|
|
|||
|
|
@ -43,16 +43,25 @@ async fn minimal_transcript_pager_restore_no_artifacts() {
|
|||
let content = ContentController::start().await.expect("start content");
|
||||
content.set_response(format!("{MOCK_RESPONSE_SENTINEL} transcript body."));
|
||||
|
||||
let mut env = content.env_for_pager();
|
||||
env.push(("PAGER".to_string(), "less".to_string()));
|
||||
env.push((
|
||||
let mut overrides: Vec<(String, String)> = vec![("PAGER".to_string(), "less".to_string())];
|
||||
overrides.push((
|
||||
"GROK_TEST_FRAME_WRITE_DELAY_MS".to_string(),
|
||||
FRAME_DELAY_MS.to_string(),
|
||||
));
|
||||
let env_refs: Vec<(&str, &str)> = env.iter().map(|(k, v)| (k.as_str(), v.as_str())).collect();
|
||||
let env_refs: Vec<(&str, &str)> = overrides
|
||||
.iter()
|
||||
.map(|(key, value)| (key.as_str(), value.as_str()))
|
||||
.collect();
|
||||
let binary = pager_binary().expect("resolve pager binary");
|
||||
let mut harness = PtyHarness::new(&binary, DEFAULT_ROWS, DEFAULT_COLS, MINIMAL_ARGS, &env_refs)
|
||||
.expect("spawn minimal pager");
|
||||
let mut harness = PtyHarness::spawn_with_content_env(
|
||||
&binary,
|
||||
DEFAULT_ROWS,
|
||||
DEFAULT_COLS,
|
||||
&content,
|
||||
MINIMAL_ARGS,
|
||||
&env_refs,
|
||||
)
|
||||
.expect("spawn minimal pager");
|
||||
harness.set_respond_to_queries(true);
|
||||
|
||||
wait_minimal_ready(&mut harness);
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ mod minimal_committed_content_survives_overlay_grow;
|
|||
mod minimal_continue_reprints_transcript;
|
||||
mod minimal_ctrl_c_arms_and_quits;
|
||||
mod minimal_double_esc_committed_queued_prompt_single_render;
|
||||
mod minimal_esc_mid_turn_is_swallowed;
|
||||
mod minimal_esc_cancels_running_turn;
|
||||
mod minimal_external_editor_round_trip;
|
||||
mod minimal_flush_left_no_hpad;
|
||||
mod minimal_help_opens_command_palette;
|
||||
|
|
|
|||
Loading…
Reference in a new issue