fix(worktree): refresh changed discovery metadata

This commit is contained in:
Bohdan Triapitsyn
2026-07-12 00:49:28 +03:00
parent 711289a606
commit fb173067f5
2 changed files with 27 additions and 10 deletions
@@ -153,6 +153,18 @@ describe('worktreeMapsEqual', () => {
expect(worktreeMapsEqual(a, b)).toBe(false);
});
test('returns false when head state changes without a branch change', () => {
const a = new Map([['/repo', [wt('/r/main', '', { headState: 'unborn' })]]]);
const b = new Map([['/repo', [wt('/r/main', '', { headState: 'detached' })]]]);
expect(worktreeMapsEqual(a, b)).toBe(false);
});
test('returns false when discovered display metadata changes', () => {
const a = new Map([['/repo', [wt('/r/main', '', { name: 'old', label: 'old' })]]]);
const b = new Map([['/repo', [wt('/r/main', '', { name: 'new', label: 'new' })]]]);
expect(worktreeMapsEqual(a, b)).toBe(false);
});
test('returns false when paths differ', () => {
const a = new Map([['/repo', [wt('/r/main', 'main')]]]);
const b = new Map([['/repo', [wt('/r/other', 'main')]]]);
@@ -231,7 +231,7 @@ const toCreatePayload = (args: {
/**
* Compare two worktree-by-project maps for equality.
* Compares per-element `path` and `branch` (not reference equality)
* Compares discovery-owned metadata (not reference equality)
* because readStableProjectWorktrees creates new object instances on
* each call, making reference checks always report changed.
*
@@ -246,22 +246,27 @@ const toCreatePayload = (args: {
* flow through `setStoredWorktreeStatus`, which writes a new Map
* reference that the persist subscriber picks up directly.
*
* Generic over `T extends { path: string; branch: string }` so the
* helper documents its equality contract at the type level and
* stays reusable for any future map-of-arrays shape that has both
* fields.
*/
export const worktreeMapsEqual = <T extends { path: string; branch: string }>(
a: Map<string, T[]>,
b: Map<string, T[]>,
export const worktreeMapsEqual = (
a: Map<string, WorktreeMetadata[]>,
b: Map<string, WorktreeMetadata[]>,
): boolean => {
if (a.size !== b.size) return false;
for (const [key, value] of a) {
const existing = b.get(key);
if (!existing || existing.length !== value.length) return false;
for (let i = 0; i < value.length; i++) {
if (value[i].path !== existing[i].path) return false;
if (value[i].branch !== existing[i].branch) return false;
const next = value[i];
const current = existing[i];
if (next.path !== current.path
|| next.branch !== current.branch
|| next.name !== current.name
|| next.label !== current.label
|| next.projectDirectory !== current.projectDirectory
|| next.worktreeRoot !== current.worktreeRoot
|| next.headState !== current.headState
|| next.worktreeSource !== current.worktreeSource
|| next.source !== current.source) return false;
}
}
return true;