Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
ff51d79
refactor(testutil): hoist the reaped-child pid helper
ReagentX Jul 28, 2026
4050803
refactor: adopt map_or at three Option sites, inline the preview clones
ReagentX Jul 28, 2026
675a96d
refactor(supervisor-tests): collapse the launch-context and snapshot …
ReagentX Jul 28, 2026
f2292c1
refactor(preview): narrow the summary-adapter seam to the rows it reads
ReagentX Jul 28, 2026
d3a510b
refactor(summary-tests): build claude fixtures from one screen helper
ReagentX Jul 28, 2026
141f148
refactor(summary-tests): fold the corpus replay into one helper, name…
ReagentX Jul 28, 2026
8eba4d6
refactor(supervisor): route single-task commands through with_task
ReagentX Jul 28, 2026
a1fed52
refactor(emulator): derive Handler delegation from one method name
ReagentX Jul 28, 2026
44a30d3
refactor(clipboard): one enum for the three OSC 52 targets
ReagentX Jul 28, 2026
892f873
refactor(selection): build extract from row_segment
ReagentX Jul 28, 2026
f753ccb
refactor(main): route fatal client errors through the run boundary
ReagentX Jul 28, 2026
dd335f0
refactor(harness): name the harness-local fixtures module for what it is
ReagentX Jul 28, 2026
5011a3c
refactor(app): render the paste notice through format::bytes
ReagentX Jul 28, 2026
cea397a
test: cover the unknown-id no-op for Kill, Tag, and Scrollback
ReagentX Jul 28, 2026
51a14b3
refactor: improve documentation and comments across multiple modules
ReagentX Jul 28, 2026
cb6539b
refactor: reorganize imports
ReagentX Jul 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1383,9 +1383,9 @@ impl App {
// Avoid closing the client connection with an oversized frame.
if s.len() > MAX_PASTE {
self.status = Some(format!(
"paste dropped: {} MiB exceeds the {} MiB limit",
s.len() >> 20,
MAX_PASTE >> 20
"paste dropped: {} exceeds the {} limit",
crate::format::bytes(s.len()),
crate::format::bytes(MAX_PASTE)
));
return;
}
Expand Down
3 changes: 2 additions & 1 deletion src/app_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1105,7 +1105,8 @@ fn oversized_paste_is_refused_with_a_notice() {
app.focused_id = Some(1);
app.on_paste(&"x".repeat(MAX_PASTE + 1));
let status = app.status.clone().unwrap_or_default();
assert!(status.contains("paste dropped"), "status was {status:?}");
// MiB values are truncated, so both sizes display as 8 MiB.
assert_eq!(status, "paste dropped: 8 MiB exceeds the 8 MiB limit");
// The boundary value is accepted.
app.on_paste(&"x".repeat(MAX_PASTE));
assert!(app.status.is_none(), "boundary paste must not be refused");
Expand Down
15 changes: 4 additions & 11 deletions src/harness/assets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,10 +205,11 @@ mod tests {
process::{Command, Stdio},
};

use super::super::testutil::ID;
use super::super::{CAPTURE_ENV, NOTIFY_CHAIN_ENV};
use super::*;
use crate::testutil::{install_fake_notifier, temp, write_executable};
use crate::{
harness::{CAPTURE_ENV, NOTIFY_CHAIN_ENV, fixtures::ID},
testutil::{dead_pid, install_fake_notifier, temp, write_executable},
};

fn mode(p: &Path) -> u32 {
fs::metadata(p).unwrap().permissions().mode() & 0o777
Expand Down Expand Up @@ -366,14 +367,6 @@ mod tests {
let _ = fs::remove_dir_all(&root);
}

/// Spawn and reap a child, then return its inactive PID.
fn dead_pid() -> u32 {
let mut child = Command::new("sh").arg("-c").arg("exit 0").spawn().unwrap();
let pid = child.id();
child.wait().unwrap();
pid
}

/// Installation removes a dead owner's namespace and its contents.
#[test]
fn install_reaps_a_dead_owner_namespace() {
Expand Down
6 changes: 4 additions & 2 deletions src/harness/claude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,11 @@ fn slug(cwd: &Path) -> Option<String> {
mod tests {
use std::{fs, path::PathBuf};

use super::super::testutil::{ID, OTHER, assert_all_opaque, assert_corpus_scrape, paths};
use super::*;
use crate::testutil::temp;
use crate::{
harness::fixtures::{ID, OTHER, assert_all_opaque, assert_corpus_scrape, paths},
testutil::temp,
};

/// Claude-specific opaque shapes: flags, `--continue`/`-c`, subcommands,
/// the short/`=` resume spellings, and `--session-id`. The syntax shared
Expand Down
6 changes: 4 additions & 2 deletions src/harness/codex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,9 +353,11 @@ fn line1_cwd_matches(path: &Path, cwd: &Path) -> bool {
mod tests {
use std::path::PathBuf;

use super::super::testutil::{OTHER, assert_all_opaque, assert_corpus_scrape, paths};
use super::*;
use crate::testutil::{temp, v7_at, write_rollout};
use crate::{
harness::fixtures::{OTHER, assert_all_opaque, assert_corpus_scrape, paths},
testutil::{temp, v7_at, write_rollout},
};

/// Codex's own launch and resume commands carry v7 IDs; the shared v4
/// fixture stays valid for detection, which is version-agnostic.
Expand Down
10 changes: 7 additions & 3 deletions src/harness/grok.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,14 @@ fn encode_cwd(cwd: &Path) -> Option<String> {
mod tests {
use std::fs;

use super::super::is_uuid;
use super::super::testutil::{ID, OTHER, assert_all_opaque, assert_corpus_scrape, paths};
use super::*;
use crate::testutil::temp;
use crate::{
harness::{
fixtures::{ID, OTHER, assert_all_opaque, assert_corpus_scrape, paths},
is_uuid,
},
testutil::temp,
};

/// Grok-specific opaque shapes: flags, the `-r`/`-s`/`=` spellings the
/// tool prints but detection refuses, and subcommands. The syntax shared
Expand Down
8 changes: 5 additions & 3 deletions src/harness/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ fn shell_quote(s: &str) -> String {

/// Fixtures and assertions for harness detection and exit scraping.
#[cfg(test)]
pub(crate) mod testutil {
pub(crate) mod fixtures {
use std::path::PathBuf;

use super::{CapturePaths, Harness};
Expand Down Expand Up @@ -358,8 +358,10 @@ pub(crate) mod testutil {

#[cfg(test)]
mod tests {
use super::testutil::{ID, OTHER};
use super::*;
use super::{
fixtures::{ID, OTHER},
*,
};

/// Harness, program word, selector, and path prefix for the shape tests
/// shared by every harness. Codex's resume selector is a subcommand, not
Expand Down
39 changes: 17 additions & 22 deletions src/harness/summary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

use std::path::Path;

use crate::preview::{ScreenFacts, SummaryAdapter};
use crate::preview::SummaryAdapter;

/// Select an adapter by the basename of the command's first
/// whitespace-separated word. Arguments are accepted; environment prefixes
Expand Down Expand Up @@ -107,17 +107,16 @@ const CLAUDE_STATUS_WINDOW: usize = 16;
pub struct ClaudeSummary;

impl SummaryAdapter for ClaudeSummary {
fn live_preview(&self, screen: &dyn ScreenFacts) -> Option<(String, &'static str)> {
let rows = screen.live_rows();
match claude_box_top(&rows) {
Some(top) => claude_spinner_status(&rows, top),
fn live_preview(&self, rows: &[String]) -> Option<(String, &'static str)> {
match claude_box_top(rows) {
Some(top) => claude_spinner_status(rows, top),
// Consider approval menus only when the normal input box is absent.
None => claude_approval(&rows),
None => claude_approval(rows),
}
}

fn model_label(&self, screen: &dyn ScreenFacts) -> Option<String> {
claude_welcome_label(&screen.live_rows())
fn model_label(&self, rows: &[String]) -> Option<String> {
claude_welcome_label(rows)
}

/// Canonicalize a leading claude spinner or braille frame to `✻` so title
Expand Down Expand Up @@ -307,18 +306,16 @@ fn claude_welcome_label(rows: &[String]) -> Option<String> {
pub struct CodexSummary;

impl SummaryAdapter for CodexSummary {
fn live_preview(&self, screen: &dyn ScreenFacts) -> Option<(String, &'static str)> {
let rows = screen.live_rows();
if let Some(hit) = codex_approval(&rows) {
fn live_preview(&self, rows: &[String]) -> Option<(String, &'static str)> {
if let Some(hit) = codex_approval(rows) {
return Some(hit);
}
let composer = codex_composer(&rows)?;
codex_status(&rows, composer)
let composer = codex_composer(rows)?;
codex_status(rows, composer)
}

fn model_label(&self, screen: &dyn ScreenFacts) -> Option<String> {
let rows = screen.live_rows();
let token = codex_token_line(&rows)?;
fn model_label(&self, rows: &[String]) -> Option<String> {
let token = codex_token_line(rows)?;
// `codex_token_line` guarantees a non-empty first segment.
Some(rows[token].trim().split(" · ").next()?.to_string())
}
Expand Down Expand Up @@ -428,9 +425,8 @@ fn codex_working(after_paren: &str) -> String {
pub struct GrokSummary;

impl SummaryAdapter for GrokSummary {
fn live_preview(&self, screen: &dyn ScreenFacts) -> Option<(String, &'static str)> {
let rows = screen.live_rows();
let (top, _) = grok_input_box(&rows)?;
fn live_preview(&self, rows: &[String]) -> Option<(String, &'static str)> {
let (top, _) = grok_input_box(rows)?;
// One probe row: the first painted row above the box. The splash
// panel's hints and the session header land here in non-working
// states and match neither shape.
Expand All @@ -444,9 +440,8 @@ impl SummaryAdapter for GrokSummary {
grok_worked(t).then(|| (t.to_string(), "grok:worked"))
}

fn model_label(&self, screen: &dyn ScreenFacts) -> Option<String> {
let rows = screen.live_rows();
let (_, bottom) = grok_input_box(&rows)?;
fn model_label(&self, rows: &[String]) -> Option<String> {
let (_, bottom) = grok_input_box(rows)?;
grok_border_label(&rows[bottom])
}
}
Expand Down
Loading