From 5a78501576c026db4fbffc69cf1a1e7c30758778 Mon Sep 17 00:00:00 2001 From: Jean Mertz Date: Thu, 26 Mar 2026 23:43:45 +0100 Subject: [PATCH 1/2] chore(tools): Exclude intent-to-add files from `git_diff` staged output When a file is staged with `git add --intent-to-add`, it appears in `git diff-index` output as a zero-sized blob, polluting the staged diff with files that have no actual staged content. This caused the `git_diff` tool and the committer persona's diff attachment to include ITA entries alongside genuinely staged changes. Adding `--ita-invisible-in-index` to all `diff-index` invocations suppresses these ITA entries so only real staged hunks are reported. The committer persona's diff attachment command is updated to match. Signed-off-by: Jean Mertz --- .config/jp/tools/src/git/diff.rs | 4 ++-- .config/jp/tools/tests/git_tests.rs | 36 +++++++++++++++++++++++++++++ .jp/config/personas/committer.toml | 2 +- 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/.config/jp/tools/src/git/diff.rs b/.config/jp/tools/src/git/diff.rs index c0a43533..c8e60999 100644 --- a/.config/jp/tools/src/git/diff.rs +++ b/.config/jp/tools/src/git/diff.rs @@ -41,8 +41,8 @@ fn git_diff_impl( env: &[(&str, &str)], ) -> ToolResult { let mut args = match status { - DiffStatus::All => vec!["diff-index", "-p", "HEAD"], - DiffStatus::Staged => vec!["diff-index", "--cached", "-p", "HEAD"], + DiffStatus::All => vec!["diff-index", "--ita-invisible-in-index", "-p", "HEAD"], + DiffStatus::Staged => vec!["diff-index", "--cached", "--ita-invisible-in-index", "-p", "HEAD"], DiffStatus::Unstaged => vec!["diff-files", "-p"], }; diff --git a/.config/jp/tools/tests/git_tests.rs b/.config/jp/tools/tests/git_tests.rs index f7bbda25..50428213 100644 --- a/.config/jp/tools/tests/git_tests.rs +++ b/.config/jp/tools/tests/git_tests.rs @@ -1169,6 +1169,42 @@ async fn diff_commit_no_match_for_path() { assert!(content.contains("No diff found")); } +#[tokio::test] +async fn staged_diff_excludes_intent_to_add_files() { + if !has_git() { + return; + } + + let (_dir, root) = init_repo(); + + // Also stage a real change so we can verify the diff isn't just empty. + commit_then_modify(&root, "tracked.rs", "old\n", "new\n"); + git(&root, &["add", "tracked.rs"]); + + // Create an untracked file and mark it intent-to-add. + fs::write(root.join("ita.rs"), "intent to add content\n").unwrap(); + git(&root, &["add", "--intent-to-add", "ita.rs"]); + + let content = run_ok( + ctx(&root), + tool("git_diff", &json!({"status": "staged"})), + ) + .await; + + // The real staged change must be present. + assert!( + content.contains("tracked.rs"), + "staged diff should contain the genuinely staged file" + ); + + // The intent-to-add file must NOT appear in staged output. + assert!( + !content.contains("ita.rs"), + "staged diff must not contain intent-to-add file, got: {content}" + ); +} + + #[tokio::test] async fn sequential_staging_across_tools() { if !has_git() { diff --git a/.jp/config/personas/committer.toml b/.jp/config/personas/committer.toml index 7722cb9d..e5ffbc37 100644 --- a/.jp/config/personas/committer.toml +++ b/.jp/config/personas/committer.toml @@ -23,7 +23,7 @@ title.generate.auto = false tools.'*' = { enable = false, run = "unattended" } attachments = [ "cmd:git branch --show-current?description=Current branch name", - "cmd:git diff-index --cached -p HEAD -- . :^crates/jp_llm/tests/fixtures :^Cargo.lock :^.jp/conversations?description=Diff of current cached/changed hunks (excluding test fixtures and Cargo.lock)", + "cmd:git diff-index --cached --ita-invisible-in-index -p HEAD -- . :^crates/jp_llm/tests/fixtures :^Cargo.lock :^.jp/conversations?description=Diff of current cached/changed hunks (excluding test fixtures and Cargo.lock)", ] [style] From 048e31e6b24cff26baea011414de56dce82d0c0e Mon Sep 17 00:00:00 2001 From: Jean Mertz Date: Thu, 26 Mar 2026 23:46:33 +0100 Subject: [PATCH 2/2] fixup! chore(tools): Exclude intent-to-add files from `git_diff` staged output Signed-off-by: Jean Mertz --- .config/jp/tools/src/git/diff.rs | 8 +++++++- .config/jp/tools/tests/git_tests.rs | 7 +------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.config/jp/tools/src/git/diff.rs b/.config/jp/tools/src/git/diff.rs index c8e60999..e66bb028 100644 --- a/.config/jp/tools/src/git/diff.rs +++ b/.config/jp/tools/src/git/diff.rs @@ -42,7 +42,13 @@ fn git_diff_impl( ) -> ToolResult { let mut args = match status { DiffStatus::All => vec!["diff-index", "--ita-invisible-in-index", "-p", "HEAD"], - DiffStatus::Staged => vec!["diff-index", "--cached", "--ita-invisible-in-index", "-p", "HEAD"], + DiffStatus::Staged => vec![ + "diff-index", + "--cached", + "--ita-invisible-in-index", + "-p", + "HEAD", + ], DiffStatus::Unstaged => vec!["diff-files", "-p"], }; diff --git a/.config/jp/tools/tests/git_tests.rs b/.config/jp/tools/tests/git_tests.rs index 50428213..cb13f19a 100644 --- a/.config/jp/tools/tests/git_tests.rs +++ b/.config/jp/tools/tests/git_tests.rs @@ -1185,11 +1185,7 @@ async fn staged_diff_excludes_intent_to_add_files() { fs::write(root.join("ita.rs"), "intent to add content\n").unwrap(); git(&root, &["add", "--intent-to-add", "ita.rs"]); - let content = run_ok( - ctx(&root), - tool("git_diff", &json!({"status": "staged"})), - ) - .await; + let content = run_ok(ctx(&root), tool("git_diff", &json!({"status": "staged"}))).await; // The real staged change must be present. assert!( @@ -1204,7 +1200,6 @@ async fn staged_diff_excludes_intent_to_add_files() { ); } - #[tokio::test] async fn sequential_staging_across_tools() { if !has_git() {