Spread AbsolutePathBuf (#17792)

Mechanical change to promote absolute paths through code.
This commit is contained in:
pakrym-oai
2026-04-14 14:26:10 -07:00
committed by GitHub
parent dae56994da
commit dd1321d11b
166 changed files with 1638 additions and 1214 deletions

View File

@@ -1,8 +1,7 @@
use std::fs;
use std::path::Path;
use codex_config::ConfigLayerStack;
use codex_config::ConfigLayerStackOrdering;
use codex_utils_absolute_path::AbsolutePathBuf;
use std::fs;
use super::ConfiguredHandler;
use super::config::HookHandlerConfig;
@@ -93,7 +92,7 @@ pub(crate) fn discover_handlers(config_layer_stack: Option<&ConfigLayerStack>) -
&mut handlers,
&mut warnings,
&mut display_order,
source_path.as_path(),
&source_path,
event_name,
groups,
);
@@ -107,7 +106,7 @@ fn append_group_handlers(
handlers: &mut Vec<ConfiguredHandler>,
warnings: &mut Vec<String>,
display_order: &mut i64,
source_path: &Path,
source_path: &AbsolutePathBuf,
event_name: codex_protocol::protocol::HookEventName,
matcher: Option<&str>,
group_handlers: Vec<HookHandlerConfig>,
@@ -151,7 +150,7 @@ fn append_group_handlers(
command,
timeout_sec,
status_message,
source_path: source_path.to_path_buf(),
source_path: source_path.clone(),
display_order: *display_order,
});
*display_order += 1;
@@ -172,7 +171,7 @@ fn append_matcher_groups(
handlers: &mut Vec<ConfiguredHandler>,
warnings: &mut Vec<String>,
display_order: &mut i64,
source_path: &Path,
source_path: &AbsolutePathBuf,
event_name: codex_protocol::protocol::HookEventName,
groups: Vec<MatcherGroup>,
) {
@@ -191,10 +190,10 @@ fn append_matcher_groups(
#[cfg(test)]
mod tests {
use std::path::Path;
use std::path::PathBuf;
use codex_protocol::protocol::HookEventName;
use codex_utils_absolute_path::AbsolutePathBuf;
use codex_utils_absolute_path::test_support::PathBufExt;
use codex_utils_absolute_path::test_support::test_path_buf;
use pretty_assertions::assert_eq;
use super::ConfiguredHandler;
@@ -202,6 +201,10 @@ mod tests {
use super::append_group_handlers;
use crate::events::common::matcher_pattern_for_event;
fn source_path() -> AbsolutePathBuf {
test_path_buf("/tmp/hooks.json").abs()
}
#[test]
fn user_prompt_submit_ignores_invalid_matcher_during_discovery() {
let mut handlers = Vec::new();
@@ -212,7 +215,7 @@ mod tests {
&mut handlers,
&mut warnings,
&mut display_order,
Path::new("/tmp/hooks.json"),
&source_path(),
HookEventName::UserPromptSubmit,
matcher_pattern_for_event(HookEventName::UserPromptSubmit, Some("[")),
vec![HookHandlerConfig::Command {
@@ -232,7 +235,7 @@ mod tests {
command: "echo hello".to_string(),
timeout_sec: 600,
status_message: None,
source_path: PathBuf::from("/tmp/hooks.json"),
source_path: source_path(),
display_order: 0,
}]
);
@@ -248,7 +251,7 @@ mod tests {
&mut handlers,
&mut warnings,
&mut display_order,
Path::new("/tmp/hooks.json"),
&source_path(),
HookEventName::PreToolUse,
matcher_pattern_for_event(HookEventName::PreToolUse, Some("^Bash$")),
vec![HookHandlerConfig::Command {
@@ -268,7 +271,7 @@ mod tests {
command: "echo hello".to_string(),
timeout_sec: 600,
status_message: None,
source_path: PathBuf::from("/tmp/hooks.json"),
source_path: source_path(),
display_order: 0,
}]
);
@@ -284,7 +287,7 @@ mod tests {
&mut handlers,
&mut warnings,
&mut display_order,
Path::new("/tmp/hooks.json"),
&source_path(),
HookEventName::PreToolUse,
matcher_pattern_for_event(HookEventName::PreToolUse, Some("*")),
vec![HookHandlerConfig::Command {
@@ -310,7 +313,7 @@ mod tests {
&mut handlers,
&mut warnings,
&mut display_order,
Path::new("/tmp/hooks.json"),
&source_path(),
HookEventName::PostToolUse,
matcher_pattern_for_event(HookEventName::PostToolUse, Some("Edit|Write")),
vec![HookHandlerConfig::Command {

View File

@@ -117,9 +117,9 @@ fn scope_for_event(event_name: HookEventName) -> HookScope {
#[cfg(test)]
mod tests {
use std::path::PathBuf;
use codex_protocol::protocol::HookEventName;
use codex_utils_absolute_path::test_support::PathBufExt;
use codex_utils_absolute_path::test_support::test_path_buf;
use super::ConfiguredHandler;
use super::select_handlers;
@@ -136,7 +136,7 @@ mod tests {
command: command.to_string(),
timeout_sec: 5,
status_message: None,
source_path: PathBuf::from("/tmp/hooks.json"),
source_path: test_path_buf("/tmp/hooks.json").abs(),
display_order,
}
}

View File

@@ -5,10 +5,9 @@ pub(crate) mod dispatcher;
pub(crate) mod output_parser;
pub(crate) mod schema_loader;
use std::path::PathBuf;
use codex_config::ConfigLayerStack;
use codex_protocol::protocol::HookRunSummary;
use codex_utils_absolute_path::AbsolutePathBuf;
use crate::events::post_tool_use::PostToolUseOutcome;
use crate::events::post_tool_use::PostToolUseRequest;
@@ -34,7 +33,7 @@ pub(crate) struct ConfiguredHandler {
pub command: String,
pub timeout_sec: u64,
pub status_message: Option<String>,
pub source_path: PathBuf,
pub source_path: AbsolutePathBuf,
pub display_order: i64,
}

View File

@@ -7,6 +7,7 @@ use codex_protocol::protocol::HookOutputEntry;
use codex_protocol::protocol::HookOutputEntryKind;
use codex_protocol::protocol::HookRunStatus;
use codex_protocol::protocol::HookRunSummary;
use codex_utils_absolute_path::AbsolutePathBuf;
use serde_json::Value;
use super::common;
@@ -22,7 +23,7 @@ use crate::schema::PostToolUseToolInput;
pub struct PostToolUseRequest {
pub session_id: ThreadId,
pub turn_id: String,
pub cwd: PathBuf,
pub cwd: AbsolutePathBuf,
pub transcript_path: Option<PathBuf>,
pub model: String,
pub permission_mode: String,
@@ -302,13 +303,13 @@ fn serialization_failure_outcome(hook_events: Vec<HookCompletedEvent>) -> PostTo
#[cfg(test)]
mod tests {
use std::path::PathBuf;
use codex_protocol::ThreadId;
use codex_protocol::protocol::HookEventName;
use codex_protocol::protocol::HookOutputEntry;
use codex_protocol::protocol::HookOutputEntryKind;
use codex_protocol::protocol::HookRunStatus;
use codex_utils_absolute_path::test_support::PathBufExt;
use codex_utils_absolute_path::test_support::test_path_buf;
use pretty_assertions::assert_eq;
use serde_json::json;
@@ -482,7 +483,13 @@ mod tests {
let runs = preview(&[handler()], &request);
assert_eq!(runs.len(), 1);
assert_eq!(runs[0].id, "post-tool-use:0:/tmp/hooks.json:tool-call-456");
assert_eq!(
runs[0].id,
format!(
"post-tool-use:0:{}:tool-call-456",
test_path_buf("/tmp/hooks.json").display()
)
);
let parsed = parse_completed(
&handler(),
@@ -517,7 +524,7 @@ mod tests {
command: "python3 post_tool_use_hook.py".to_string(),
timeout_sec: 5,
status_message: Some("running post tool use hook".to_string()),
source_path: PathBuf::from("/tmp/hooks.json"),
source_path: test_path_buf("/tmp/hooks.json").abs(),
display_order: 0,
}
}
@@ -538,7 +545,7 @@ mod tests {
super::PostToolUseRequest {
session_id: ThreadId::new(),
turn_id: "turn-1".to_string(),
cwd: PathBuf::from("/tmp"),
cwd: test_path_buf("/tmp").abs(),
transcript_path: None,
model: "gpt-test".to_string(),
permission_mode: "default".to_string(),

View File

@@ -7,6 +7,7 @@ use codex_protocol::protocol::HookOutputEntry;
use codex_protocol::protocol::HookOutputEntryKind;
use codex_protocol::protocol::HookRunStatus;
use codex_protocol::protocol::HookRunSummary;
use codex_utils_absolute_path::AbsolutePathBuf;
use super::common;
use crate::engine::CommandShell;
@@ -20,7 +21,7 @@ use crate::schema::PreToolUseCommandInput;
pub struct PreToolUseRequest {
pub session_id: ThreadId,
pub turn_id: String,
pub cwd: PathBuf,
pub cwd: AbsolutePathBuf,
pub transcript_path: Option<PathBuf>,
pub model: String,
pub permission_mode: String,
@@ -239,13 +240,13 @@ fn serialization_failure_outcome(hook_events: Vec<HookCompletedEvent>) -> PreToo
#[cfg(test)]
mod tests {
use std::path::PathBuf;
use codex_protocol::ThreadId;
use codex_protocol::protocol::HookEventName;
use codex_protocol::protocol::HookOutputEntry;
use codex_protocol::protocol::HookOutputEntryKind;
use codex_protocol::protocol::HookRunStatus;
use codex_utils_absolute_path::test_support::PathBufExt;
use codex_utils_absolute_path::test_support::test_path_buf;
use pretty_assertions::assert_eq;
use super::PreToolUseHandlerData;
@@ -471,7 +472,13 @@ mod tests {
let runs = preview(&[handler()], &request);
assert_eq!(runs.len(), 1);
assert_eq!(runs[0].id, "pre-tool-use:0:/tmp/hooks.json:tool-call-123");
assert_eq!(
runs[0].id,
format!(
"pre-tool-use:0:{}:tool-call-123",
test_path_buf("/tmp/hooks.json").display()
)
);
let parsed = parse_completed(
&handler(),
@@ -506,7 +513,7 @@ mod tests {
command: "echo hook".to_string(),
timeout_sec: 5,
status_message: None,
source_path: PathBuf::from("/tmp/hooks.json"),
source_path: test_path_buf("/tmp/hooks.json").abs(),
display_order: 0,
}
}
@@ -527,7 +534,7 @@ mod tests {
super::PreToolUseRequest {
session_id: ThreadId::new(),
turn_id: "turn-1".to_string(),
cwd: PathBuf::from("/tmp"),
cwd: test_path_buf("/tmp").abs(),
transcript_path: None,
model: "gpt-test".to_string(),
permission_mode: "default".to_string(),

View File

@@ -7,6 +7,7 @@ use codex_protocol::protocol::HookOutputEntry;
use codex_protocol::protocol::HookOutputEntryKind;
use codex_protocol::protocol::HookRunStatus;
use codex_protocol::protocol::HookRunSummary;
use codex_utils_absolute_path::AbsolutePathBuf;
use super::common;
use crate::engine::CommandShell;
@@ -36,7 +37,7 @@ impl SessionStartSource {
#[derive(Debug, Clone)]
pub struct SessionStartRequest {
pub session_id: ThreadId,
pub cwd: PathBuf,
pub cwd: AbsolutePathBuf,
pub transcript_path: Option<PathBuf>,
pub model: String,
pub permission_mode: String,
@@ -247,12 +248,12 @@ fn serialization_failure_outcome(hook_events: Vec<HookCompletedEvent>) -> Sessio
#[cfg(test)]
mod tests {
use std::path::PathBuf;
use codex_protocol::protocol::HookEventName;
use codex_protocol::protocol::HookOutputEntry;
use codex_protocol::protocol::HookOutputEntryKind;
use codex_protocol::protocol::HookRunStatus;
use codex_utils_absolute_path::test_support::PathBufExt;
use codex_utils_absolute_path::test_support::test_path_buf;
use pretty_assertions::assert_eq;
use super::SessionStartHandlerData;
@@ -359,7 +360,7 @@ mod tests {
command: "echo hook".to_string(),
timeout_sec: 600,
status_message: None,
source_path: PathBuf::from("/tmp/hooks.json"),
source_path: test_path_buf("/tmp/hooks.json").abs(),
display_order: 0,
}
}

View File

@@ -8,6 +8,7 @@ use codex_protocol::protocol::HookOutputEntry;
use codex_protocol::protocol::HookOutputEntryKind;
use codex_protocol::protocol::HookRunStatus;
use codex_protocol::protocol::HookRunSummary;
use codex_utils_absolute_path::AbsolutePathBuf;
use super::common;
use crate::engine::CommandShell;
@@ -22,7 +23,7 @@ use crate::schema::StopCommandInput;
pub struct StopRequest {
pub session_id: ThreadId,
pub turn_id: String,
pub cwd: PathBuf,
pub cwd: AbsolutePathBuf,
pub transcript_path: Option<PathBuf>,
pub model: String,
pub permission_mode: String,
@@ -310,12 +311,12 @@ fn serialization_failure_outcome(hook_events: Vec<HookCompletedEvent>) -> StopOu
#[cfg(test)]
mod tests {
use std::path::PathBuf;
use codex_protocol::protocol::HookEventName;
use codex_protocol::protocol::HookOutputEntry;
use codex_protocol::protocol::HookOutputEntryKind;
use codex_protocol::protocol::HookRunStatus;
use codex_utils_absolute_path::test_support::PathBufExt;
use codex_utils_absolute_path::test_support::test_path_buf;
use pretty_assertions::assert_eq;
use codex_protocol::items::HookPromptFragment;
@@ -526,7 +527,7 @@ mod tests {
command: "echo hook".to_string(),
timeout_sec: 600,
status_message: None,
source_path: PathBuf::from("/tmp/hooks.json"),
source_path: test_path_buf("/tmp/hooks.json").abs(),
display_order: 0,
}
}

View File

@@ -7,6 +7,7 @@ use codex_protocol::protocol::HookOutputEntry;
use codex_protocol::protocol::HookOutputEntryKind;
use codex_protocol::protocol::HookRunStatus;
use codex_protocol::protocol::HookRunSummary;
use codex_utils_absolute_path::AbsolutePathBuf;
use super::common;
use crate::engine::CommandShell;
@@ -21,7 +22,7 @@ use crate::schema::UserPromptSubmitCommandInput;
pub struct UserPromptSubmitRequest {
pub session_id: ThreadId,
pub turn_id: String,
pub cwd: PathBuf,
pub cwd: AbsolutePathBuf,
pub transcript_path: Option<PathBuf>,
pub model: String,
pub permission_mode: String,
@@ -268,12 +269,12 @@ fn serialization_failure_outcome(hook_events: Vec<HookCompletedEvent>) -> UserPr
#[cfg(test)]
mod tests {
use std::path::PathBuf;
use codex_protocol::protocol::HookEventName;
use codex_protocol::protocol::HookOutputEntry;
use codex_protocol::protocol::HookOutputEntryKind;
use codex_protocol::protocol::HookRunStatus;
use codex_utils_absolute_path::test_support::PathBufExt;
use codex_utils_absolute_path::test_support::test_path_buf;
use pretty_assertions::assert_eq;
use super::UserPromptSubmitHandlerData;
@@ -417,7 +418,7 @@ mod tests {
command: "echo hook".to_string(),
timeout_sec: 5,
status_message: None,
source_path: PathBuf::from("/tmp/hooks.json"),
source_path: test_path_buf("/tmp/hooks.json").abs(),
display_order: 0,
}
}

View File

@@ -76,20 +76,22 @@ pub fn notify_hook(argv: Vec<String>) -> Hook {
mod tests {
use anyhow::Result;
use codex_protocol::ThreadId;
use codex_utils_absolute_path::test_support::PathBufExt;
use codex_utils_absolute_path::test_support::test_path_buf;
use pretty_assertions::assert_eq;
use serde_json::Value;
use serde_json::json;
use std::path::Path;
use super::*;
use crate::HookEventAfterAgent;
fn expected_notification_json() -> Value {
let cwd = test_path_buf("/Users/example/project");
json!({
"type": "agent-turn-complete",
"thread-id": "b5f6c1c2-1111-2222-3333-444455556666",
"turn-id": "12345",
"cwd": "/Users/example/project",
"cwd": cwd.display().to_string(),
"client": "codex-tui",
"input-messages": ["Rename `foo` to `bar` and update the callsites."],
"last-assistant-message": "Rename complete and verified `cargo build` succeeds.",
@@ -101,7 +103,9 @@ mod tests {
let notification = UserNotification::AgentTurnComplete {
thread_id: "b5f6c1c2-1111-2222-3333-444455556666".to_string(),
turn_id: "12345".to_string(),
cwd: "/Users/example/project".to_string(),
cwd: test_path_buf("/Users/example/project")
.display()
.to_string(),
client: Some("codex-tui".to_string()),
input_messages: vec!["Rename `foo` to `bar` and update the callsites.".to_string()],
last_assistant_message: Some(
@@ -118,7 +122,7 @@ mod tests {
fn legacy_notify_json_matches_historical_wire_shape() -> Result<()> {
let payload = HookPayload {
session_id: ThreadId::new(),
cwd: Path::new("/Users/example/project").to_path_buf(),
cwd: test_path_buf("/Users/example/project").abs(),
client: Some("codex-tui".to_string()),
triggered_at: chrono::Utc::now(),
hook_event: HookEvent::AfterAgent {

View File

@@ -1,4 +1,3 @@
use std::path::PathBuf;
use std::sync::Arc;
use chrono::DateTime;
@@ -6,6 +5,7 @@ use chrono::SecondsFormat;
use chrono::Utc;
use codex_protocol::ThreadId;
use codex_protocol::models::SandboxPermissions;
use codex_utils_absolute_path::AbsolutePathBuf;
use futures::future::BoxFuture;
use serde::Serialize;
use serde::Serializer;
@@ -64,7 +64,7 @@ impl Hook {
#[serde(rename_all = "snake_case")]
pub struct HookPayload {
pub session_id: ThreadId,
pub cwd: PathBuf,
pub cwd: AbsolutePathBuf,
#[serde(skip_serializing_if = "Option::is_none")]
pub client: Option<String>,
#[serde(serialize_with = "serialize_triggered_at")]
@@ -159,12 +159,12 @@ pub enum HookEvent {
#[cfg(test)]
mod tests {
use std::path::PathBuf;
use chrono::TimeZone;
use chrono::Utc;
use codex_protocol::ThreadId;
use codex_protocol::models::SandboxPermissions;
use codex_utils_absolute_path::test_support::PathBufExt;
use codex_utils_absolute_path::test_support::test_path_buf;
use pretty_assertions::assert_eq;
use serde_json::json;
@@ -180,9 +180,10 @@ mod tests {
fn hook_payload_serializes_stable_wire_shape() {
let session_id = ThreadId::new();
let thread_id = ThreadId::new();
let cwd = test_path_buf("/tmp").abs();
let payload = HookPayload {
session_id,
cwd: PathBuf::from("tmp"),
cwd: cwd.clone(),
client: None,
triggered_at: Utc
.with_ymd_and_hms(2025, 1, 1, 0, 0, 0)
@@ -201,7 +202,7 @@ mod tests {
let actual = serde_json::to_value(payload).expect("serialize hook payload");
let expected = json!({
"session_id": session_id.to_string(),
"cwd": "tmp",
"cwd": cwd.display().to_string(),
"triggered_at": "2025-01-01T00:00:00Z",
"hook_event": {
"event_type": "after_agent",
@@ -218,9 +219,10 @@ mod tests {
#[test]
fn after_tool_use_payload_serializes_stable_wire_shape() {
let session_id = ThreadId::new();
let cwd = test_path_buf("/tmp").abs();
let payload = HookPayload {
session_id,
cwd: PathBuf::from("tmp"),
cwd: cwd.clone(),
client: None,
triggered_at: Utc
.with_ymd_and_hms(2025, 1, 1, 0, 0, 0)
@@ -256,7 +258,7 @@ mod tests {
let actual = serde_json::to_value(payload).expect("serialize hook payload");
let expected = json!({
"session_id": session_id.to_string(),
"cwd": "tmp",
"cwd": cwd.display().to_string(),
"triggered_at": "2025-01-01T00:00:00Z",
"hook_event": {
"event_type": "after_tool_use",

View File

@@ -81,6 +81,8 @@ pub fn notify_hook(argv: Vec<String>) -> Hook {
mod tests {
use anyhow::Result;
use codex_protocol::ThreadId;
use codex_utils_absolute_path::test_support::PathBufExt;
use codex_utils_absolute_path::test_support::test_path_buf;
use pretty_assertions::assert_eq;
use serde_json::Value;
use serde_json::json;
@@ -88,11 +90,12 @@ mod tests {
use super::*;
fn expected_notification_json() -> Value {
let cwd = test_path_buf("/Users/example/project");
json!({
"type": "agent-turn-complete",
"thread-id": "b5f6c1c2-1111-2222-3333-444455556666",
"turn-id": "12345",
"cwd": "/Users/example/project",
"cwd": cwd.display().to_string(),
"client": "codex-tui",
"input-messages": ["Rename `foo` to `bar` and update the callsites."],
"last-assistant-message": "Rename complete and verified `cargo build` succeeds.",
@@ -104,7 +107,9 @@ mod tests {
let notification = UserNotification::AgentTurnComplete {
thread_id: "b5f6c1c2-1111-2222-3333-444455556666".to_string(),
turn_id: "12345".to_string(),
cwd: "/Users/example/project".to_string(),
cwd: test_path_buf("/Users/example/project")
.display()
.to_string(),
client: Some("codex-tui".to_string()),
input_messages: vec!["Rename `foo` to `bar` and update the callsites.".to_string()],
last_assistant_message: Some(
@@ -121,7 +126,7 @@ mod tests {
fn legacy_notify_json_matches_historical_wire_shape() -> Result<()> {
let payload = HookPayload {
session_id: ThreadId::new(),
cwd: std::path::Path::new("/Users/example/project").to_path_buf(),
cwd: test_path_buf("/Users/example/project").abs(),
client: Some("codex-tui".to_string()),
triggered_at: chrono::Utc::now(),
hook_event: HookEvent::AfterAgent {