Skip to content
Merged
Changes from all commits
Commits
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
40 changes: 33 additions & 7 deletions crates/trodden/src/hook.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ use trodden_store::{Cue, Injection, Patience, Store};

use crate::output::Output;

const MAX_INPUT_BYTES: u64 = 1 << 20;

#[derive(Debug)]
pub(crate) struct Hook;

Expand Down Expand Up @@ -56,11 +54,7 @@ impl Hook {
if !home.is_initialized() {
return Ok(());
}
let mut raw = String::new();
io::stdin()
.take(MAX_INPUT_BYTES)
.read_to_string(&mut raw)
.context("read the hook payload")?;
let raw = Self::read_payload(io::stdin().lock())?;
let Some(mut event) = harness.event(&raw, &Redactor::new())? else {
return Ok(());
};
Expand All @@ -72,6 +66,14 @@ impl Hook {
Self::respond(harness, &home, &event, out)
}

fn read_payload(mut input: impl Read) -> Result<String> {
let mut raw = String::new();
input
.read_to_string(&mut raw)
.context("read the hook payload")?;
Ok(raw)
}

fn respond(
harness: Harness,
home: &Home,
Expand Down Expand Up @@ -849,4 +851,28 @@ mod tests {
which has not run since your last change. Run it once before finishing."
);
}

#[test]
fn a_payload_over_a_mebibyte_is_read_whole() {
let prompt = format!("Fix the paging bug\n{}", "x".repeat(3 << 20));
let payload = json!({
"session_id": "s1",
"transcript_path": "/home/dev/.claude/projects/shop/s1.jsonl",
"cwd": CWD,
"hook_event_name": "UserPromptSubmit",
"prompt": prompt,
})
.to_string();

let raw = Hook::read_payload(payload.as_bytes()).expect("payload is valid UTF-8");
let event = Harness::ClaudeCode
.event(&raw, &Redactor::new())
.expect("payload parses")
.expect("prompt is a hook event");

assert_eq!(raw.len(), payload.len());
assert!(
matches!(event.moment, Moment::Prompt(text) if text.starts_with("Fix the paging bug"))
);
}
}
Loading