Consolidate redact and terminal crates into util

Merges two small utility crates into a single `util` crate to reduce
workspace clutter. No behavioral changes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Bryan Helmkamp 2026-02-27 18:44:19 -05:00
parent b6d285a79c
commit 0756a42ce8
23 changed files with 37 additions and 50 deletions

31
Cargo.lock generated
View file

@ -23,10 +23,10 @@ dependencies = [
"serde_json",
"tar",
"tempfile",
"terminal",
"thiserror 2.0.18",
"tokio",
"tokio-util",
"util",
"uuid",
]
@ -210,18 +210,17 @@ dependencies = [
"nom",
"predicates",
"rand 0.8.5",
"redact",
"scopeguard",
"serde",
"serde_json",
"tempfile",
"terminal",
"thiserror 2.0.18",
"tokio",
"tokio-stream",
"tokio-util",
"toml",
"tower",
"util",
"uuid",
]
@ -2295,17 +2294,6 @@ dependencies = [
"getrandom 0.3.4",
]
[[package]]
name = "redact"
version = "0.1.0"
dependencies = [
"aho-corasick",
"regex",
"serde",
"serde_json",
"toml",
]
[[package]]
name = "redox_syscall"
version = "0.5.18"
@ -2996,10 +2984,6 @@ dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "terminal"
version = "0.1.0"
[[package]]
name = "termtree"
version = "0.5.1"
@ -3407,6 +3391,17 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "util"
version = "0.1.0"
dependencies = [
"aho-corasick",
"regex",
"serde",
"serde_json",
"toml",
]
[[package]]
name = "uuid"
version = "1.21.0"

View file

@ -26,7 +26,7 @@ clap.workspace = true
anyhow.workspace = true
dotenvy.workspace = true
llm = { path = "../llm" }
terminal = { path = "../terminal" }
util = { path = "../util" }
thiserror.workspace = true
serde.workspace = true
serde_json.workspace = true

View file

@ -8,7 +8,7 @@ use llm::client::Client;
use std::io::{IsTerminal, Write};
use std::path::PathBuf;
use std::sync::{Arc, Mutex};
use terminal::Styles;
use util::terminal::Styles;
/// Minimal CLI for the agent agentic loop.
#[derive(Parser)]

View file

@ -26,9 +26,8 @@ clap.workspace = true
anyhow.workspace = true
dotenvy.workspace = true
agent = { path = "../agent" }
terminal = { path = "../terminal" }
util = { path = "../util" }
llm = { path = "../llm" }
redact = { path = "../redact" }
thiserror.workspace = true
serde.workspace = true
serde_json.workspace = true

View file

@ -9,7 +9,7 @@ use agent::{
subagent::{SessionFactory, SubAgentManager},
};
use llm::client::Client;
use terminal::Styles;
use util::terminal::Styles;
use crate::context::Context;
use crate::error::AttractorError;

View file

@ -11,7 +11,7 @@ use clap::{Args, Parser, Subcommand, ValueEnum};
use std::fmt;
use std::path::PathBuf;
use std::str::FromStr;
use terminal::Styles;
use util::terminal::Styles;
use agent::AgentEvent;
use crate::event::PipelineEvent;

View file

@ -5,7 +5,7 @@ use std::time::Instant;
use agent::{DockerConfig, DockerExecutionEnvironment, ExecutionEnvironment, LocalExecutionEnvironment};
use anyhow::bail;
use chrono::{Local, Utc};
use terminal::Styles;
use util::terminal::Styles;
use crate::checkpoint::Checkpoint;
use crate::engine::{PipelineEngine, RunConfig};
@ -156,7 +156,7 @@ pub async fn run_command(args: RunArgs, styles: &'static Styles) -> anyhow::Resu
});
// Append to progress.ndjson
if let Ok(line) = serde_json::to_string(&envelope) {
let line = redact::redact_jsonl_line(&line);
let line = util::redact::redact_jsonl_line(&line);
use std::io::Write;
if let Ok(mut f) = std::fs::OpenOptions::new()
.create(true)
@ -168,7 +168,7 @@ pub async fn run_command(args: RunArgs, styles: &'static Styles) -> anyhow::Resu
}
// Overwrite live.json
if let Ok(pretty) = serde_json::to_string_pretty(&envelope) {
let pretty = redact::redact_jsonl_line(&pretty);
let pretty = util::redact::redact_jsonl_line(&pretty);
let _ = std::fs::write(&live_path, pretty);
}
});
@ -526,7 +526,7 @@ mod tests {
}
});
let compact = serde_json::to_string(&envelope).unwrap();
let redacted = redact::redact_jsonl_line(&compact);
let redacted = util::redact::redact_jsonl_line(&compact);
assert!(!redacted.contains("AKIAYRWQG5EJLPZLBYNP"));
assert!(redacted.contains("REDACTED"));
@ -547,7 +547,7 @@ mod tests {
}
});
let pretty = serde_json::to_string_pretty(&envelope).unwrap();
let redacted = redact::redact_jsonl_line(&pretty);
let redacted = util::redact::redact_jsonl_line(&pretty);
assert!(!redacted.contains("AKIAYRWQG5EJLPZLBYNP"));
assert!(redacted.contains("REDACTED"));

View file

@ -1,6 +1,6 @@
use std::sync::Arc;
use terminal::Styles;
use util::terminal::Styles;
use tokio::net::TcpListener;
use crate::cli::backend::AgentBackend;

View file

@ -1,5 +1,5 @@
use anyhow::bail;
use terminal::Styles;
use util::terminal::Styles;
use crate::pipeline::PipelineBuilder;
use crate::validation::Severity;

View file

@ -2,7 +2,7 @@ use std::io::IsTerminal;
use async_trait::async_trait;
use dialoguer::console::Term;
use terminal::Styles;
use util::terminal::Styles;
use tokio::io::{AsyncBufReadExt, BufReader};
use super::{Answer, AnswerValue, Interviewer, Question, QuestionType};

View file

@ -1,5 +1,5 @@
use clap::Parser;
use terminal::Styles;
use util::terminal::Styles;
#[tokio::main]
async fn main() {

View file

@ -371,7 +371,7 @@ async fn get_events(
let stream = BroadcastStream::new(rx).filter_map(|result| match result {
Ok(event) => {
let data = serde_json::to_string(&event).unwrap_or_default();
let data = redact::redact_jsonl_line(&data);
let data = util::redact::redact_jsonl_line(&data);
Some(Ok::<Event, std::convert::Infallible>(
Event::default().data(data),
))

View file

@ -27,7 +27,7 @@ use attractor::transform::{StylesheetApplicationTransform, Transform, VariableEx
use attractor::cli::backend::AgentBackend;
use attractor::handler::default_registry;
use attractor::validation::{validate, validate_or_raise, Severity};
use terminal::Styles;
use util::terminal::Styles;
fn local_env() -> Arc<dyn agent::ExecutionEnvironment> {
Arc::new(agent::LocalExecutionEnvironment::new(

View file

@ -1,9 +0,0 @@
[package]
name = "terminal"
edition.workspace = true
version.workspace = true
license.workspace = true
description = "Shared ANSI terminal styling for CLI binaries"
[lib]
doctest = false

View file

@ -1,9 +1,9 @@
[package]
name = "redact"
name = "util"
edition.workspace = true
version.workspace = true
license.workspace = true
description = "Secret detection and redaction for log output"
description = "Shared utilities: secret redaction and terminal styling"
[lib]
doctest = false

2
crates/util/src/lib.rs Normal file
View file

@ -0,0 +1,2 @@
pub mod redact;
pub mod terminal;

View file

@ -1,4 +1,4 @@
use crate::Region;
use super::Region;
use regex::Regex;
use std::sync::LazyLock;

View file

@ -1,4 +1,4 @@
use crate::Region;
use super::Region;
use aho_corasick::AhoCorasick;
use regex::Regex;
use std::sync::{LazyLock, OnceLock};

View file

@ -58,7 +58,7 @@ fn collect_replacements(v: &Value) -> Vec<(String, String)> {
}
}
Value::String(s) => {
let redacted = crate::redact_string(s);
let redacted = super::redact_string(s);
if redacted != *s && seen.insert(s.clone()) {
repls.push((s.clone(), redacted));
}
@ -91,7 +91,7 @@ pub fn redact_jsonl_line(line: &str) -> String {
let parsed: Value = match serde_json::from_str(trimmed) {
Ok(v) => v,
Err(_) => return crate::redact_string(line),
Err(_) => return super::redact_string(line),
};
let repls = collect_replacements(&parsed);