fix(proximity): isolate diff headers and preserve partial probes

This commit is contained in:
Huanyi Xie
2026-10-06 20:12:07 +03:00
parent 3989e50ab3
commit 52cc44f40a
2 changed files with 32 additions and 4 deletions
+11 -3
View File
@@ -28,9 +28,13 @@ function parseDiffRanges(diff) {
const byFile = new Map();
let current = null;
for (const line of String(diff || '').split('\n')) {
if (line.startsWith('diff --git ')) {
current = null;
continue;
}
const fileMatch = line.match(/^\+\+\+ b\/(.+)$/);
if (fileMatch) {
const name = fileMatch[1].trim();
const name = fileMatch[1].replace(/\t$/, '');
current = name === '/dev/null' ? null : name;
if (current && !byFile.has(current)) byFile.set(current, []);
continue;
@@ -80,8 +84,12 @@ function defaultWorkingSetFor(session) {
try {
const ranges = parseDiffRanges(runGitDiff(wt.path, base, ['--unified=0']));
// Deletions, binary changes and quoted paths have no usable new-side hunks.
for (const file of runGitDiff(wt.path, base, ['--name-only', '-z']).split('\0').filter(Boolean)) {
if (!ranges.has(file)) ranges.set(file, []);
try {
for (const file of runGitDiff(wt.path, base, ['--name-only', '-z']).split('\0').filter(Boolean)) {
if (!ranges.has(file)) ranges.set(file, []);
}
} catch {
// Preserve ranges already read if the supplementary filename probe fails.
}
for (const file of untrackedFiles(wt.path)) ranges.set(file, []);
return [...ranges.entries()].map(([path, lines]) => (lines.length > 0 ? { path, lines } : { path }));
+21 -1
View File
@@ -153,6 +153,7 @@ test('quoted staged paths and untracked paths share identity, and untracked fail
const wt = path.join(dir, name);
git(repo, 'worktree', 'add', '-q', '-b', name, wt, 'main');
fs.writeFileSync(path.join(wt, file), `export const value = '${name}';\n`);
if (name === 'a') fs.writeFileSync(path.join(wt, 'README'), 'changed\n');
return { id: name, worktree: { path: wt, base: 'main' } };
});
git(worktrees[0].worktree.path, 'add', file);
@@ -169,7 +170,14 @@ test('quoted staged paths and untracked paths share identity, and untracked fail
const fresh = require(modulePath);
const [tracked] = fresh.sessionsToAgents([worktrees[0]]);
assert.ok(tracked, `${code}: tracked changes must survive`);
assert.deepStrictEqual(tracked.files.map(entry => entry.path), [file]);
assert.deepStrictEqual(tracked.files.map(entry => entry.path).sort(), ['README', file].sort());
childProcess.execFileSync = (command, args, options) => {
if (args.includes('--name-only')) throw Object.assign(new Error('tracked names unavailable'), { code });
return originalExec(command, args, options);
};
delete require.cache[modulePath];
const partial = require(modulePath).sessionsToAgents([worktrees[0]]);
assert.deepStrictEqual(partial[0].files.map(entry => entry.path), ['README']);
}
} finally {
childProcess.execFileSync = originalExec;
@@ -221,6 +229,18 @@ test('parseDiffRanges: extracts new-side line ranges per file', () => {
]);
});
test('diff headers isolate quoted/deleted hunks and preserve trailing-space paths', () => {
const ranges = parseDiffRanges([
'diff --git a/first.js b/first.js', '+++ b/first.js', '@@ -1 +1 @@',
'diff --git "a/café.js" "b/café.js"', '+++ "b/café.js"', '@@ -20 +20 @@',
'diff --git a/deleted.js b/deleted.js', '+++ /dev/null', '@@ -30 +0,0 @@',
'diff --git a/trailing b/trailing', '+++ b/trailing ', '@@ -40 +40 @@',
].join('\n'));
assert.deepStrictEqual(ranges.get('first.js'), [[1, 1]]);
assert.deepStrictEqual(ranges.get('trailing '), [[40, 40]]);
assert.strictEqual(ranges.has('trailing'), false);
});
test('line-range channel: same file but disjoint ranges ⇒ no resolution', () => {
// Two agents in the same file, far-apart functions. workingSetFor provides ranges.
const workingSetFor = s =>