diff --git a/README.md b/README.md index 893991e..dd88b36 100644 --- a/README.md +++ b/README.md @@ -97,9 +97,10 @@ part of the review and are sent whether or not its folder is listed. ## Inside Herdr Install [Herdr Annotate](https://github.com/plannotator/herdr-annotate); it bundles this binary, -opens it in a pane with `prefix+o` (folder) or `prefix+shift+o` (agent's last reply) or by -Ctrl-clicking a `file://…md` link, and the header button sends the review straight back to -the agent as its next message: `Send 3 new ▸ claude in w1:p2 (E)`. Folder reviews show +opens it in a pane with `prefix+o` (folder) or `prefix+shift+o` (agent's last reply), and the +header button sends the review straight back to the agent as its next message: +`Send 3 new ▸ claude in w1:p2 (E)`. Ctrl-clicking a `file://…md` link opens it in Annotate only +if you install the add-on: `herdr plugin install plannotator/herdr-annotate/links`. Folder reviews show `Send 3 new across 2 files` and send one combined feedback message. ```toml diff --git a/crates/plannotator-tui-hosts/tests/claude.rs b/crates/plannotator-tui-hosts/tests/claude.rs index b7989c1..641c279 100644 --- a/crates/plannotator-tui-hosts/tests/claude.rs +++ b/crates/plannotator-tui-hosts/tests/claude.rs @@ -81,5 +81,8 @@ fn a_dangling_parent_makes_the_chain_untrusted_and_file_order_applies() { #[test] fn garbage_input_yields_no_messages_rather_than_an_error() { - assert!(parse_messages("not json\n{\"type\":\"progress\"}\n", 3).is_empty()); + assert_eq!( + parse_messages("not json\n{\"type\":\"progress\"}\n", 3), + [] as [plannotator_tui_hosts::Message; 0] + ); } diff --git a/crates/plannotator-tui-hosts/tests/codex.rs b/crates/plannotator-tui-hosts/tests/codex.rs index ab952f7..77c4a45 100644 --- a/crates/plannotator-tui-hosts/tests/codex.rs +++ b/crates/plannotator-tui-hosts/tests/codex.rs @@ -58,5 +58,5 @@ fn when_every_turn_has_completed_the_whole_thread_counts_newest_first() { #[test] fn an_unknown_thread_has_no_files() { - assert!(find_transcripts(home(), Some("nope")).is_empty()); + assert_eq!(find_transcripts(home(), Some("nope")), [] as [std::path::PathBuf; 0]); } diff --git a/crates/plannotator-tui-hosts/tests/exact_session.rs b/crates/plannotator-tui-hosts/tests/exact_session.rs index 5f53b8f..1804c5c 100644 --- a/crates/plannotator-tui-hosts/tests/exact_session.rs +++ b/crates/plannotator-tui-hosts/tests/exact_session.rs @@ -72,7 +72,7 @@ fn exact_file_host_ids_prefer_the_current_windows_path_bucket() { &codex_home.join("sessions/2026/08/31").join(format!("rollout-2026-08-31T10-00-00-{OTHER_ID}.jsonl")), ); assert_eq!(codex::find_transcripts_by_id(&codex_home, ID).expect("codex"), vec![codex_file]); - assert!(codex::find_transcripts_by_id(&codex_home, "missing").expect("miss").is_empty()); + assert_eq!(codex::find_transcripts_by_id(&codex_home, "missing").expect("miss"), [] as [PathBuf; 0]); let copilot_home = root.join("copilot root"); let copilot_session = copilot_home.join("session-state").join(ID); diff --git a/crates/plannotator-tui-hosts/tests/pi.rs b/crates/plannotator-tui-hosts/tests/pi.rs index dde8863..cfcb4eb 100644 --- a/crates/plannotator-tui-hosts/tests/pi.rs +++ b/crates/plannotator-tui-hosts/tests/pi.rs @@ -86,7 +86,7 @@ fn tool_calls_tool_results_and_thinking_are_not_messages() { #[test] fn an_unreconstructable_chain_yields_nothing_rather_than_the_wrong_messages() { - assert!(parse_messages(&fixture("pi-dangling.jsonl"), 25).is_empty()); + assert_eq!(parse_messages(&fixture("pi-dangling.jsonl"), 25), [] as [plannotator_tui_hosts::Message; 0]); } #[test] diff --git a/crates/plannotator-tui/src/app/feedback/tests.rs b/crates/plannotator-tui/src/app/feedback/tests.rs index d69924f..9bcf6fc 100644 --- a/crates/plannotator-tui/src/app/feedback/tests.rs +++ b/crates/plannotator-tui/src/app/feedback/tests.rs @@ -216,7 +216,7 @@ fn reply_reviews_keep_sending_the_whole_transient_review() { assert!(calls[1].contains("> A") && calls[1].contains("> B")); press(&mut app, 'F'); assert_eq!(app.open.store.len(), 2); - assert!(app.open.store.archived().is_empty()); + assert_eq!(app.open.store.archived(), []); assert!(app.open.store.is_transient()); assert!(!draw(&mut app, 80, 24).contains("Review \u{25be}"), "a reply review has no Review menu"); std::fs::remove_dir_all(root).expect("cleanup"); diff --git a/crates/plannotator-tui/src/app/review/tests.rs b/crates/plannotator-tui/src/app/review/tests.rs index 2c83824..c45d38e 100644 --- a/crates/plannotator-tui/src/app/review/tests.rs +++ b/crates/plannotator-tui/src/app/review/tests.rs @@ -28,7 +28,7 @@ fn finish_undo_and_restore_keep_pending_edits_and_preserve_sent_status() { click(&mut app, undo); assert_eq!(app.open.store.len(), 3); assert_eq!(app.send_count(), 2, "undo did not make A pending"); - assert!(app.open.store.archived().is_empty()); + assert_eq!(app.open.store.archived(), []); press(&mut app, 'F'); reopen(&mut app); diff --git a/crates/plannotator-tui/src/store/review/tests.rs b/crates/plannotator-tui/src/store/review/tests.rs index 3a8e00e..f168911 100644 --- a/crates/plannotator-tui/src/store/review/tests.rs +++ b/crates/plannotator-tui/src/store/review/tests.rs @@ -193,7 +193,7 @@ fn archiving_keeps_pending_notes_and_restores_complete_annotations_and_history() let restored = store.annotations.iter().find(|a| a.id == original.id).expect("same id"); assert_eq!(restored, &original); assert!(!store.is_pending(restored), "restoring must not resend it"); - assert!(store.archived().is_empty()); + assert_eq!(store.archived(), []); assert_eq!(store.deliveries, history); std::fs::remove_dir_all(root).expect("cleanup"); } @@ -208,7 +208,7 @@ fn archive_and_restore_failures_leave_memory_and_disk_intact() { std::fs::create_dir(&blocked_tmp).expect("block temporary file"); assert!(store.archive_sent().is_err()); assert_eq!(store.len(), 1); - assert!(store.archived().is_empty()); + assert_eq!(store.archived(), []); assert_eq!(std::fs::read(&location.record).expect("record"), before); std::fs::remove_dir(&blocked_tmp).expect("unblock"); diff --git a/crates/plannotator-tui/tests/codex_pid.rs b/crates/plannotator-tui/tests/codex_pid.rs index 618caf8..0fb4446 100644 --- a/crates/plannotator-tui/tests/codex_pid.rs +++ b/crates/plannotator-tui/tests/codex_pid.rs @@ -146,7 +146,7 @@ fn ambiguous_pid_does_not_read_the_newest_session() { let process = HoldingProcess::new(&fixture.selected, Some(&fixture.other)); let out = fixture.command(process.0.id()).output().expect("runs"); assert!(out.status.success(), "--print reports discovery failures without aborting its caller"); - assert!(out.stdout.is_empty()); + assert_eq!(out.stdout, [] as [u8; 0]); assert!(String::from_utf8_lossy(&out.stderr).contains("2 open transcripts")); } @@ -156,7 +156,7 @@ fn pid_without_an_open_transcript_does_not_read_another_session() { let process = HoldingProcess::new(Path::new("/dev/null"), None); let out = fixture.command(process.0.id()).output().expect("runs"); assert!(out.status.success()); - assert!(out.stdout.is_empty()); + assert_eq!(out.stdout, [] as [u8; 0]); assert!(String::from_utf8_lossy(&out.stderr).contains("0 open transcripts")); } diff --git a/crates/plannotator-tui/tests/last.rs b/crates/plannotator-tui/tests/last.rs index 10c3532..ef30133 100644 --- a/crates/plannotator-tui/tests/last.rs +++ b/crates/plannotator-tui/tests/last.rs @@ -168,7 +168,7 @@ fn print_never_fails_the_caller_when_nothing_is_found() { let missing = fixtures().join("does-not-exist.jsonl"); let out = bin().args(["last", "--session"]).arg(&missing).arg("--print").output().expect("runs"); assert!(out.status.success(), "exit 0 is the contract"); - assert!(out.stdout.is_empty()); + assert_eq!(out.stdout, [] as [u8; 0]); assert!(String::from_utf8_lossy(&out.stderr).contains("does-not-exist.jsonl")); } diff --git a/crates/plannotator-tui/tests/terminal.rs b/crates/plannotator-tui/tests/terminal.rs index bbae608..962efd1 100644 --- a/crates/plannotator-tui/tests/terminal.rs +++ b/crates/plannotator-tui/tests/terminal.rs @@ -157,7 +157,7 @@ fn an_action_without_a_focused_pane_reads_nothing() { assert!(!out.status.success()); assert!(String::from_utf8_lossy(&out.stderr).contains("no focused pane to read")); - assert!(calls(&fake).is_empty()); + assert_eq!(calls(&fake), [] as [Value; 0]); std::fs::remove_dir_all(root).expect("cleanup"); }