@gitkraken/core-gitlens 0.15.7 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,6 +3,7 @@ import { CancellationError, isCancellationError, raceWithSignal } from "../../ut
3
3
  import { Logger as _logger } from "../../utils/logger.js";
4
4
  import { Emitter } from "../../utils/event.js";
5
5
  import { getRepositoryKey } from "../../utils/uri.js";
6
+ import { getRefChangeKind } from "./changeEvent.js";
6
7
  //#region ../git/src/watching/worktreeSummary.ts
7
8
  /** Read groups, as bit flags so a pending set is a number rather than an allocation per event */
8
9
  const dirtyField = 1;
@@ -12,6 +13,11 @@ const baseField = 4;
12
13
  const baseKeysField = 8;
13
14
  /** Re-reads the provider's Git config inputs before deciding whether the base needs a refresh */
14
15
  const baseConfigField = 16;
16
+ /**
17
+ * Refreshes the base after only refs it depends on moved, each named exactly (in {@link SummaryEntry.baseMoves}): when
18
+ * the base's own ref just moved forward, it is re-measured rather than resolved again. {@link baseField} overrides it.
19
+ */
20
+ const baseMoveField = 32;
15
21
  /** Every group a full read covers — a base read refreshes the {@link BaseKeys} snapshot itself */
16
22
  const allFields = 7;
17
23
  const maxConcurrentReadsPerRepository = 4;
@@ -80,11 +86,15 @@ var SummarySubscription = class {
80
86
  * **Field-scoped recompute.** The summary is read in three groups — `dirty` (working changes), `branch` (branch,
81
87
  * HEAD's commit, upstream, ahead/behind) and `base` (ahead of base, the base's tip, and the refs it depends on) — and
82
88
  * an event recomputes only the groups it can affect: a working-tree edit, an index or ignore-rule change reads only
83
- * `dirty`; the upstream moving reads only `branch`; a ref the base depends on reads only `base`; a `gk` config change
89
+ * `dirty`; the upstream moving reads only `branch`; a ref the base depends on reads only `base`, and when the refs that
90
+ * moved are named and include the base's own ref, as a fetch names them, the provider first tries re-measuring the
91
+ * base from the previous one (one count per worktree when it only moved forward); a `gk` config change
84
92
  * (mostly bookkeeping writes to the shared `.git/gk/config`), or core's own write of the branch's merge target or
85
93
  * base, re-reads the branch's stored merge targets and recorded base, and reads `base` only when one of them changed;
86
- * a `.git/config` change reads `branch` and the provider's config inputs to the base (one cached read per checkout), and
87
- * reads `base` only when they, the stored values, HEAD's commit or the upstream changed, unless it was confined to the
94
+ * a `.git/config` change reads `branch` and the provider's config inputs to the base (one cached read shared by the
95
+ * repository's checkouts, or one per checkout where config can differ by checkout), and reads `base` only when the
96
+ * inputs its last base read consulted (every branch's tracking but those of branches it didn't depend on), the stored
97
+ * values, HEAD's commit or the upstream changed, unless it was confined to the
88
98
  * `branch.<name>` sections of branches the summary neither is on, tracks nor bases on (its `configBranches`), which
89
99
  * reads nothing; the checked-out branch moving, or a HEAD change, reads all of them. Stash, unrelated tags and
90
100
  * branches, and the like read nothing. One run is in flight per worktree at a time, at most four per repository (the
@@ -113,12 +123,14 @@ var WorktreeSummaryService = class {
113
123
  watchService;
114
124
  getRepository;
115
125
  getCommonPath;
126
+ verifyBaseRemeasure;
116
127
  mergeTargetsListener;
117
128
  _disposed = false;
118
129
  constructor(options) {
119
130
  this.watchService = options.watchService;
120
131
  this.getRepository = options.getRepository;
121
132
  this.getCommonPath = options.getCommonPath;
133
+ this.verifyBaseRemeasure = options.verifyBaseRemeasure;
122
134
  this.mergeTargetsListener = options.onDidChangeMergeTargets?.((e) => this.onMergeTargetsChanged(e));
123
135
  }
124
136
  [Symbol.dispose]() {
@@ -170,7 +182,7 @@ var WorktreeSummaryService = class {
170
182
  if (entry == null) {
171
183
  const repo = this.getRepository(key);
172
184
  if (repo == null) throw new Error(`No repository found for '${key}'`);
173
- return (await readSummary(repo, key, allFields, void 0, void 0, void 0, cancellation)).summary;
185
+ return (await readSummary(repo, key, allFields, void 0, void 0, void 0, void 0, void 0, cancellation, this.verifyBaseRemeasure)).summary;
174
186
  }
175
187
  if (entry.running != null) await (cancellation != null ? raceWithSignal(entry.running, cancellation) : entry.running);
176
188
  if (entry.disposed) throw new CancellationError();
@@ -229,13 +241,22 @@ var WorktreeSummaryService = class {
229
241
  if (e.changed("gkConfig")) fields |= baseKeysField;
230
242
  if (value.branch != null && e.mayHaveChangedRef(`refs/heads/${value.branch}`)) fields |= allFields;
231
243
  if (value.upstream != null && (e.mayHaveChangedRef(`refs/remotes/${value.upstream.name}`) || e.mayHaveChangedRef(`refs/heads/${value.upstream.name}`))) fields |= branchField;
244
+ let baseMoves;
232
245
  if ((fields & baseField) === 0) {
233
- for (const ref of value.baseDependsOn) if (e.mayHaveChangedRef(ref)) {
234
- fields |= baseField;
235
- break;
246
+ for (const ref of value.baseDependsOn) {
247
+ if (!e.mayHaveChangedRef(ref)) continue;
248
+ const kind = getRefChangeKind(ref);
249
+ if (!e.refs.has(ref) || kind == null || e.unnamedRefKinds.has(kind)) {
250
+ fields |= baseField;
251
+ baseMoves = void 0;
252
+ break;
253
+ }
254
+ baseMoves ??= [];
255
+ baseMoves.push(ref);
236
256
  }
257
+ if (baseMoves != null) fields |= baseMoveField;
237
258
  }
238
- this.queue(entry, fields);
259
+ this.queue(entry, fields, baseMoves);
239
260
  }
240
261
  /**
241
262
  * Queued synchronously, so a store awaited before `getSummary` finds the run in flight. The watcher's later
@@ -251,9 +272,13 @@ var WorktreeSummaryService = class {
251
272
  this.queue(entry, baseKeysField);
252
273
  }
253
274
  }
254
- queue(entry, fields) {
275
+ queue(entry, fields, baseMoves) {
255
276
  if (entry.disposed || fields === 0) return;
256
277
  entry.pending |= entry.value == null || entry.value.stale ? fields | 23 : fields;
278
+ if (baseMoves != null) {
279
+ entry.baseMoves ??= /* @__PURE__ */ new Set();
280
+ for (const ref of baseMoves) entry.baseMoves.add(ref);
281
+ }
257
282
  entry.running ??= this.drain(entry);
258
283
  }
259
284
  /** Runs until nothing is pending. Never rejects — every failure becomes entry state. */
@@ -263,8 +288,10 @@ var WorktreeSummaryService = class {
263
288
  try {
264
289
  if (entry.disposed) break;
265
290
  const fields = entry.pending;
291
+ const baseMoves = entry.baseMoves;
266
292
  entry.pending = 0;
267
- await this.run(entry, fields);
293
+ entry.baseMoves = void 0;
294
+ await this.run(entry, fields, baseMoves);
268
295
  } finally {
269
296
  this.releaseRead(entry);
270
297
  }
@@ -308,13 +335,13 @@ var WorktreeSummaryService = class {
308
335
  this.activeReads++;
309
336
  return true;
310
337
  }
311
- async run(entry, fields) {
338
+ async run(entry, fields, baseMoves) {
312
339
  const previous = entry.value;
313
340
  let result;
314
341
  try {
315
342
  const repo = this.getRepository(entry.key);
316
343
  if (repo == null) throw new Error(`No repository found for '${entry.key}'`);
317
- result = await readSummary(repo, entry.key, fields, previous, entry.baseKeys, entry.baseConfigKey, entry.abort.signal);
344
+ result = await readSummary(repo, entry.key, fields, previous, entry.baseKeys, entry.baseConfigKey, entry.baseDefaultBranch, baseMoves, entry.abort.signal, this.verifyBaseRemeasure);
318
345
  } catch (ex) {
319
346
  if (entry.disposed || isCancellationError(ex)) return;
320
347
  this.fail(entry, ex);
@@ -325,6 +352,7 @@ var WorktreeSummaryService = class {
325
352
  entry.error = void 0;
326
353
  entry.baseKeys = result.baseKeys;
327
354
  entry.baseConfigKey = entry.pending & baseConfigField ? void 0 : result.baseConfigKey;
355
+ entry.baseDefaultBranch = result.baseDefaultBranch;
328
356
  if (previous != null && summariesEqual(previous, result.summary)) return;
329
357
  entry.value = result.summary;
330
358
  this.fireChange(entry, result.summary);
@@ -368,7 +396,9 @@ var WorktreeSummaryService = class {
368
396
  entry.value = void 0;
369
397
  entry.baseKeys = void 0;
370
398
  entry.baseConfigKey = void 0;
399
+ entry.baseDefaultBranch = void 0;
371
400
  entry.pending = 0;
401
+ entry.baseMoves = void 0;
372
402
  entry.running = void 0;
373
403
  if (this.entries.get(entry.key) === entry) this.entries.delete(entry.key);
374
404
  }
@@ -393,8 +423,10 @@ function createEntry(key) {
393
423
  value: void 0,
394
424
  baseKeys: void 0,
395
425
  baseConfigKey: void 0,
426
+ baseDefaultBranch: void 0,
396
427
  error: void 0,
397
428
  pending: 0,
429
+ baseMoves: void 0,
398
430
  running: void 0,
399
431
  disposed: false
400
432
  };
@@ -403,10 +435,13 @@ function createEntry(key) {
403
435
  * Reads the due groups and fills the rest from `previous` (every group when there is none). The branch read comes
404
436
  * before the base read, which needs its name; the dirty read runs alongside both. A branch read that finds a
405
437
  * different branch (or detached state) also reads the base and dirty groups, and stored base values that differ
406
- * from `previousBaseKeys` read the base group. A failed base read doesn't fail the rest: the summary comes back stale,
407
- * keeping the previous base and `baseDependsOn` only while the branch is the same.
438
+ * from `previousBaseKeys` read the base group. A base due only because `baseMoves` moved, with HEAD, the stored
439
+ * values and the config inputs as before, is first re-measured from `previous` and the default branch its read
440
+ * resolved, `previousBaseDefaultBranch` (see `getAheadOfBaseAfterBaseMove`), and read in full only when that can't
441
+ * answer. A failed base read doesn't fail the rest: the summary comes back stale, keeping the previous
442
+ * base and `baseDependsOn` only while the branch is the same.
408
443
  */
409
- async function readSummary(repo, key, fields, previous, previousBaseKeys, previousBaseConfigKey, signal) {
444
+ async function readSummary(repo, key, fields, previous, previousBaseKeys, previousBaseConfigKey, previousBaseDefaultBranch, baseMoves, signal, verifyBaseRemeasure) {
410
445
  if (previous == null) fields |= allFields;
411
446
  let dirtyRead = fields & dirtyField ? readDirty(repo, signal) : void 0;
412
447
  let branch = previous?.branch;
@@ -433,33 +468,59 @@ async function readSummary(repo, key, fields, previous, previousBaseKeys, previo
433
468
  let baseKeys = previousBaseKeys;
434
469
  let baseKeysRead = false;
435
470
  let baseConfigKey = previousBaseConfigKey;
436
- let baseConfigKeyRead = false;
471
+ let baseConfig;
472
+ let baseConfigRead = false;
473
+ let baseDefaultBranch = previousBaseDefaultBranch;
437
474
  let baseFailed = false;
438
475
  let baseError;
439
476
  const baseReadable = repo.branches.getAheadOfBase != null && (detached || branch != null);
440
477
  if (fields & baseConfigField && !(fields & baseField) && baseReadable) {
441
- baseConfigKey = await readBaseConfigKey(repo, signal);
442
- baseConfigKeyRead = true;
443
- if (baseConfigKey == null || baseConfigKey !== previousBaseConfigKey || sha !== previous?.sha || !upstreamsEqual(upstream, previous?.upstream)) fields |= baseField;
478
+ baseConfig = await readBaseConfig(repo, signal);
479
+ baseConfigRead = true;
480
+ const key = previous != null ? getBaseConfigKey(baseConfig, previous) : void 0;
481
+ if (key == null || key !== previousBaseConfigKey || sha !== previous?.sha || !upstreamsEqual(upstream, previous?.upstream)) fields |= baseField;
444
482
  }
445
483
  if (fields & baseKeysField && !(fields & baseField) && baseReadable) {
446
484
  baseKeys = await readBaseKeys(repo, branch);
447
485
  baseKeysRead = true;
448
486
  if (baseKeys == null || previousBaseKeys == null || !baseKeysEqual(baseKeys, previousBaseKeys)) fields |= baseField;
449
487
  }
450
- if (fields & baseField) {
488
+ if (fields & 36) {
451
489
  if (!baseReadable) {
452
490
  base = void 0;
453
491
  dependsOn = emptyRefs;
454
492
  baseKeys = void 0;
455
493
  baseConfigKey = void 0;
494
+ baseDefaultBranch = void 0;
456
495
  } else {
457
496
  if (!baseKeysRead) baseKeys = await readBaseKeys(repo, branch);
458
- if (!baseConfigKeyRead && (previous != null || (fields & baseConfigField) !== 0)) baseConfigKey = await readBaseConfigKey(repo, signal);
497
+ if (!baseConfigRead && (previous != null || (fields & baseConfigField) !== 0)) {
498
+ baseConfig = await readBaseConfig(repo, signal);
499
+ baseConfigRead = true;
500
+ }
459
501
  try {
460
- const aheadOfBase = await repo.branches.getAheadOfBase?.(branch, void 0, signal);
502
+ let aheadOfBase;
503
+ if (!(fields & baseField) && baseMoves != null && baseMoves.size !== 0 && previous?.base != null && sha != null && sha === previous.sha && baseKeys != null && previousBaseKeys != null && baseKeysEqual(baseKeys, previousBaseKeys) && getBaseConfigKey(baseConfig, previous) === previousBaseConfigKey) {
504
+ aheadOfBase = await repo.branches.getAheadOfBaseAfterBaseMove?.(branch, {
505
+ head: sha,
506
+ base: previous.base,
507
+ dependsOn: previous.baseDependsOn,
508
+ ...previousBaseDefaultBranch !== void 0 ? { defaultBranch: previousBaseDefaultBranch } : void 0
509
+ }, [...baseMoves], signal);
510
+ if (aheadOfBase != null && verifyBaseRemeasure != null) {
511
+ let full;
512
+ try {
513
+ full = await repo.branches.getAheadOfBase?.(branch, void 0, signal);
514
+ } catch (ex) {
515
+ if (isCancellationError(ex)) throw ex;
516
+ }
517
+ verifyBaseRemeasure(aheadOfBase, full);
518
+ }
519
+ }
520
+ aheadOfBase ??= await repo.branches.getAheadOfBase?.(branch, void 0, signal);
461
521
  base = aheadOfBase?.base;
462
522
  dependsOn = aheadOfBase?.dependsOn ?? emptyRefs;
523
+ baseDefaultBranch = aheadOfBase?.defaultBranch;
463
524
  } catch (ex) {
464
525
  if (isCancellationError(ex)) throw ex;
465
526
  baseFailed = true;
@@ -468,32 +529,38 @@ async function readSummary(repo, key, fields, previous, previousBaseKeys, previo
468
529
  base = sameBranch ? previous.base : void 0;
469
530
  dependsOn = sameBranch ? previous.baseDependsOn : emptyRefs;
470
531
  baseKeys = void 0;
532
+ baseConfigRead = false;
471
533
  baseConfigKey = void 0;
534
+ baseDefaultBranch = void 0;
472
535
  }
473
536
  }
474
537
  }
475
538
  const dirty = dirtyRead != null ? await dirtyRead : previous?.dirty ?? false;
539
+ const summary = {
540
+ repoPath: key,
541
+ branch,
542
+ detached,
543
+ sha,
544
+ upstream,
545
+ ahead,
546
+ behind,
547
+ dirty,
548
+ base,
549
+ baseDependsOn: dependsOn,
550
+ stale: baseFailed
551
+ };
552
+ if (baseConfigRead) baseConfigKey = getBaseConfigKey(baseConfig, summary);
476
553
  return {
477
- summary: {
478
- repoPath: key,
479
- branch,
480
- detached,
481
- sha,
482
- upstream,
483
- ahead,
484
- behind,
485
- dirty,
486
- base,
487
- baseDependsOn: dependsOn,
488
- stale: baseFailed
489
- },
554
+ summary,
490
555
  baseKeys,
491
556
  baseConfigKey,
557
+ baseDefaultBranch,
492
558
  baseError
493
559
  };
494
560
  }
495
- async function readBaseConfigKey(repo, signal) {
561
+ async function readBaseConfig(repo, signal) {
496
562
  try {
563
+ if (repo.branches.getAheadOfBaseConfigEntries != null) return await repo.branches.getAheadOfBaseConfigEntries(signal);
497
564
  return await repo.branches.getAheadOfBaseConfigKey?.(signal);
498
565
  } catch (ex) {
499
566
  if (isCancellationError(ex)) throw ex;
@@ -501,6 +568,24 @@ async function readBaseConfigKey(repo, signal) {
501
568
  }
502
569
  }
503
570
  /**
571
+ * The key of the config inputs a base read for `value` consulted: every entry except the `branch.<name>` ones of local
572
+ * branches outside its {@link getConfigRelevantRefs}, which the read never resolved. So a write to another branch's
573
+ * section, confined (which wakes no summary but changes the inputs) or not, leaves the base alone. An opaque key is
574
+ * taken whole.
575
+ */
576
+ function getBaseConfigKey(config, value) {
577
+ if (config == null || typeof config === "string") return config;
578
+ const branches = /* @__PURE__ */ new Set();
579
+ for (const ref of getConfigRelevantRefs(value)) if (ref.startsWith("refs/heads/")) branches.add(ref.substring(11));
580
+ let key = "";
581
+ for (const [name, entry] of config) {
582
+ const last = name.lastIndexOf(".");
583
+ if (name.startsWith("branch.") && last > 7 && !branches.has(name.substring(7, last))) continue;
584
+ key += entry != null ? `${name}\n${entry}\0` : `${name}\0`;
585
+ }
586
+ return key;
587
+ }
588
+ /**
504
589
  * Reads {@link BaseKeys} for `branch`, normalized the way `getAheadOfBase` reads them. `undefined` when any read
505
590
  * failed — an unknown snapshot, so the next `gk` config change reads the base rather than trusting it. A detached
506
591
  * HEAD (`branch` undefined) has no stored values to read.
@@ -1 +1 @@
1
- {"version":3,"file":"worktreeSummary.js","names":[],"sources":["../../../../git/src/watching/worktreeSummary.ts"],"sourcesContent":["import { areEqual } from '@gitlens/utils/array.js';\nimport { CancellationError, isCancellationError, raceWithSignal } from '@gitlens/utils/cancellation.js';\nimport type { UnifiedDisposable } from '@gitlens/utils/disposable.js';\nimport type { Event } from '@gitlens/utils/event.js';\nimport { Emitter } from '@gitlens/utils/event.js';\nimport { Logger } from '@gitlens/utils/logger.js';\nimport type { ResourceUsage } from '@gitlens/utils/resourceUsage.js';\nimport { getRepositoryKey } from '@gitlens/utils/uri.js';\nimport type { MergeTargetsChangeEvent } from '../cache.js';\nimport type { GitTrackingUpstream } from '../models/branch.js';\nimport type { GitDir } from '../models/repository.js';\nimport type { AheadOfBaseTier } from '../providers/branches.js';\nimport type { RepositoryService } from '../repositoryService.js';\nimport type { WatcherRepoChangeEvent } from './changeEvent.js';\nimport type { RepositoryWatchService, WatchHandle } from './watchService.js';\nimport type { RepositoryWatchSession } from './watchSession.js';\n\nexport interface WorktreeSummaryUpstream {\n\t/** The upstream's short name (`origin/main`) */\n\treadonly name: string;\n\t/**\n\t * The remote it tracks, as git reported it; on git too old to report it, the longest of the repository's remote\n\t * names that {@link name} starts with, followed by `/` (a remote name can hold a slash). `undefined`, with\n\t * {@link branch}, when it names no known remote (a branch tracking another local branch, or a remote since removed)\n\t */\n\treadonly remote: string | undefined;\n\t/**\n\t * The branch on {@link remote} — git's name for it there, which a custom fetch refspec can make differ from the end\n\t * of {@link name}; `undefined` whenever {@link remote} is\n\t */\n\treadonly branch: string | undefined;\n\treadonly missing: boolean;\n}\n\nexport interface WorktreeSummaryBase {\n\t/** The ref the count was taken against (see `AheadOfBase.base`) */\n\treadonly ref: string;\n\treadonly ahead: number;\n\t/** The commit {@link ref} pointed at when the count was read; `undefined` when it couldn't be resolved */\n\treadonly sha: string | undefined;\n\t/** Where HEAD forked from {@link ref} (see `AheadOfBase.base`) */\n\treadonly forkPoint: string | undefined;\n\t/** The source the base came from (see `AheadOfBase.base`) */\n\treadonly tier: AheadOfBaseTier;\n}\n\nexport interface WorktreeSummary {\n\t/** The repository path in {@link getRepositoryKey} form */\n\treadonly repoPath: string;\n\t/** The checked-out branch; `undefined` when detached (or unborn with no name) */\n\treadonly branch: string | undefined;\n\treadonly detached: boolean;\n\t/** HEAD's commit; `undefined` when HEAD has no commit yet */\n\treadonly sha: string | undefined;\n\treadonly upstream: WorktreeSummaryUpstream | undefined;\n\t/** Commits ahead of the upstream; 0 without one */\n\treadonly ahead: number;\n\t/** Commits behind the upstream; 0 without one */\n\treadonly behind: number;\n\t/** Whether there is any staged, unstaged or untracked (non-ignored) change */\n\treadonly dirty: boolean;\n\t/**\n\t * How far the branch — or a detached HEAD, measured against the default branch — is past its base; `undefined` when\n\t * unsupported or there is no base\n\t */\n\treadonly base: WorktreeSummaryBase | undefined;\n\t/**\n\t * Full ref names whose movement can change {@link base}, as `getAheadOfBase` reports them (see\n\t * `AheadOfBase.dependsOn`) — given with or without a base, so a watcher also learns when one appears. Empty when\n\t * the base isn't read (an unborn HEAD with no name, or a provider without `getAheadOfBase`), and when the base read\n\t * failed with no earlier list for this HEAD (the first read, or the one after a checkout).\n\t */\n\treadonly baseDependsOn: readonly string[];\n\t/**\n\t * The latest recompute failed (worktree gone, lock contention); the other fields hold the last values read. Also set\n\t * when only the base read failed: the other fields are fresh, and `base` and `baseDependsOn` are their last values,\n\t * or `undefined` and empty if the branch changed.\n\t */\n\treadonly stale: boolean;\n}\n\nexport interface WorktreeSummarySubscribeOptions {\n\t/** Debounce for repo (`.git`) changes this subscriber asks of the watch session; the shortest across subscribers wins */\n\treadonly delayMs?: number;\n\t/** Cap on how long continuous repo activity can defer a recompute; `Infinity` means no cap */\n\treadonly maxWaitMs?: number;\n\t/** Debounce for working-tree changes this subscriber asks of the watch session */\n\treadonly workingTreeDelayMs?: number;\n\t/** Cap on how long continuous working-tree activity can defer a recompute; `Infinity` means no cap */\n\treadonly workingTreeMaxWaitMs?: number;\n}\n\nexport interface WorktreeSummarySubscription extends UnifiedDisposable {\n\t/** The latest summary; `undefined` until the first read succeeds, or after disposal */\n\treadonly current: WorktreeSummary | undefined;\n\t/** Fires when the summary's value changes */\n\treadonly onDidChange: Event<WorktreeSummary>;\n}\n\nexport interface WorktreeSummaryServiceOptions {\n\treadonly watchService: RepositoryWatchService;\n\treadonly getRepository: (repoPath: string) => RepositoryService | undefined;\n\t/**\n\t * Fires as core writes a branch's merge target or base, before the store's promise resolves; the summary re-reads\n\t * that branch's stored values then, so a `getSummary` right after an awaited store sees the new base\n\t */\n\treadonly onDidChangeMergeTargets?: Event<MergeTargetsChangeEvent>;\n\t/**\n\t * Maps a worktree path to the repository common path that {@link onDidChangeMergeTargets} events carry; only that\n\t * repository's summaries react. Without it, or when it returns `undefined`, every summary reacts.\n\t */\n\treadonly getCommonPath?: (repoPath: string) => string | undefined;\n}\n\n/** Read groups, as bit flags so a pending set is a number rather than an allocation per event */\nconst dirtyField = 1;\nconst branchField = 2;\nconst baseField = 4;\n/** Re-reads only the stored values the base read consults, and the base itself only when they changed */\nconst baseKeysField = 8;\n/** Re-reads the provider's Git config inputs before deciding whether the base needs a refresh */\nconst baseConfigField = 16;\n/** Every group a full read covers — a base read refreshes the {@link BaseKeys} snapshot itself */\nconst allFields = dirtyField | branchField | baseField;\n\n// Shared config and ref changes reach every checkout of a repository together; bound that repository's Git fan-out so\n// input can keep moving. Per repository, so a burst in one, or reads hung in it, never holds up another's.\nconst maxConcurrentReadsPerRepository = 4;\n// And across repositories, so a start (or an overflow rescan) over many of them never runs four reads for each at once.\n// Each read runs a couple of git processes side by side, so eight leave most of the process queue to foreground\n// commands and the CPU to the host; a hung read still frees its slot once git's command timeout ends it.\nconst maxConcurrentReads = 8;\n\nconst emptyRefs: readonly string[] = Object.freeze([]);\n\n/**\n * The current branch's stored merge targets (user, detected) and recorded base, as `getAheadOfBase` consults them.\n * A detached HEAD has no stored values, so it holds {@link noBaseKeys}.\n */\ntype BaseKeys = readonly [string | undefined, string | undefined, string | undefined];\n\nconst noBaseKeys: BaseKeys = [undefined, undefined, undefined];\n\ninterface ReadResult {\n\treadonly summary: WorktreeSummary;\n\treadonly baseKeys: BaseKeys | undefined;\n\treadonly baseConfigKey: string | undefined;\n\t/** Why the base read failed when the rest of the summary was read; the summary is then stale */\n\treadonly baseError: unknown;\n}\n\ninterface SummaryEntry {\n\treadonly key: string;\n\t/**\n\t * The repository's common git directory, which keys its read slots; set once the watch starts, and kept after the\n\t * last subscriber leaves, since a read still in flight then frees the slots it took under it\n\t */\n\tslotsKey: string | undefined;\n\t/** Aborted when the last subscriber leaves, cancelling any in-flight read */\n\treadonly abort: AbortController;\n\treadonly subscribers: Set<SummarySubscription>;\n\thandle: WatchHandle | undefined;\n\t/** The timing-neutral listening subscriptions and their event listeners */\n\tlisteners: UnifiedDisposable[] | undefined;\n\tvalue: WorktreeSummary | undefined;\n\t/** The stored base values as of the last base read; a `gk` config change re-reads the base only when they differ */\n\tbaseKeys: BaseKeys | undefined;\n\tbaseConfigKey: string | undefined;\n\t/** Why the latest read failed while there was no value to keep */\n\terror: Error | undefined;\n\t/** Read groups due on the next run */\n\tpending: number;\n\t/** The active run (or the start-up, which ends in one); cleared in the same turn the loop sees nothing pending */\n\trunning: Promise<void> | undefined;\n\tdisposed: boolean;\n}\n\nclass SummarySubscription implements WorktreeSummarySubscription {\n\tprivate readonly emitter = new Emitter<WorktreeSummary>();\n\t/** Listener-less session subscriptions that carry this subscriber's timing into the session */\n\tprivate timing: UnifiedDisposable[] | undefined;\n\tprivate disposed = false;\n\n\tconstructor(\n\t\tprivate readonly entry: SummaryEntry,\n\t\tprivate readonly options: WorktreeSummarySubscribeOptions | undefined,\n\t\tprivate readonly onDispose: (subscription: SummarySubscription) => void,\n\t) {}\n\n\tget current(): WorktreeSummary | undefined {\n\t\treturn this.disposed ? undefined : this.entry.value;\n\t}\n\n\tget onDidChange(): Event<WorktreeSummary> {\n\t\treturn this.emitter.event;\n\t}\n\n\t[Symbol.dispose](): void {\n\t\tthis.dispose();\n\t}\n\n\tdispose(): void {\n\t\tif (this.disposed) return;\n\n\t\tthis.disposed = true;\n\t\tif (this.timing != null) {\n\t\t\tfor (const d of this.timing) {\n\t\t\t\td.dispose();\n\t\t\t}\n\t\t\tthis.timing = undefined;\n\t\t}\n\t\tthis.emitter.dispose();\n\t\tthis.onDispose(this);\n\t}\n\n\tattach(session: RepositoryWatchSession): void {\n\t\tif (this.disposed || this.timing != null) return;\n\n\t\tthis.timing = [\n\t\t\tsession.subscribe({ delayMs: this.options?.delayMs, maxWaitMs: this.options?.maxWaitMs }),\n\t\t\tsession.subscribeToWorkingTree({\n\t\t\t\tdelayMs: this.options?.workingTreeDelayMs,\n\t\t\t\tmaxWaitMs: this.options?.workingTreeMaxWaitMs,\n\t\t\t}),\n\t\t];\n\t}\n\n\tfire(summary: WorktreeSummary): void {\n\t\tthis.emitter.fire(summary);\n\t}\n}\n\n/**\n * A cached, change-notifying summary of each subscribed worktree — its branch, upstream and ahead/behind, whether it\n * has working changes, and how far it is past its base — kept current by the repository watch layer.\n *\n * **Lifecycle.** Entries are per repository key and ref-counted across {@link subscribe} calls. The first subscriber\n * starts watching the worktree and reads everything; the last one to leave aborts any in-flight read, releases the\n * watch and drops the value. Each subscriber's timing options join the watch session's cadence (the shortest wins);\n * the service's own listening subscriptions never constrain it.\n *\n * **Field-scoped recompute.** The summary is read in three groups — `dirty` (working changes), `branch` (branch,\n * HEAD's commit, upstream, ahead/behind) and `base` (ahead of base, the base's tip, and the refs it depends on) — and\n * an event recomputes only the groups it can affect: a working-tree edit, an index or ignore-rule change reads only\n * `dirty`; the upstream moving reads only `branch`; a ref the base depends on reads only `base`; a `gk` config change\n * (mostly bookkeeping writes to the shared `.git/gk/config`), or core's own write of the branch's merge target or\n * base, re-reads the branch's stored merge targets and recorded base, and reads `base` only when one of them changed;\n * a `.git/config` change reads `branch` and the provider's config inputs to the base (one cached read per checkout), and\n * reads `base` only when they, the stored values, HEAD's commit or the upstream changed, unless it was confined to the\n * `branch.<name>` sections of branches the summary neither is on, tracks nor bases on (its `configBranches`), which\n * reads nothing; the checked-out branch moving, or a HEAD change, reads all of them. Stash, unrelated tags and\n * branches, and the like read nothing. One run is in flight per worktree at a time, at most four per repository (the\n * worktrees sharing a common git directory), and at most eight across the service. Runs take turns first come, first\n * served, except that one whose repository is at its cap lets later runs of other repositories go first, so a burst in\n * one repository never delays another's reads: events while a run waits for its turn join it, and events during a run\n * are merged into a single follow-up run.\n *\n * **Value-change-only notification.** {@link WorktreeSummarySubscription.onDidChange} and {@link onDidChangeSummary}\n * fire only when some field's value differs from the previous summary — a recompute that reads the same answer is\n * silent, so a consumer can re-render on every event without diffing. A failed recompute keeps the last values and\n * sets `stale` (firing once); the next successful one clears it.\n */\nexport class WorktreeSummaryService implements UnifiedDisposable {\n\tprivate readonly _onDidChangeSummary = new Emitter<WorktreeSummary>();\n\t/** Fires when the summary of any subscribed worktree changes value */\n\tget onDidChangeSummary(): Event<WorktreeSummary> {\n\t\treturn this._onDidChangeSummary.event;\n\t}\n\n\tprivate readonly entries = new Map<string, SummaryEntry>();\n\t/** Reads running for each repository, by its slots key; a repository with none has no entry */\n\tprivate readonly activeReadsByRepository = new Map<string, number>();\n\tprivate activeReads = 0;\n\t/** Entries waiting for a read slot, oldest first */\n\tprivate readonly readWaiters = new Map<SummaryEntry, (acquired: boolean) => void>();\n\tprivate readonly watchService: RepositoryWatchService;\n\tprivate readonly getRepository: (repoPath: string) => RepositoryService | undefined;\n\tprivate readonly getCommonPath: ((repoPath: string) => string | undefined) | undefined;\n\tprivate readonly mergeTargetsListener: UnifiedDisposable | undefined;\n\tprivate _disposed = false;\n\n\tconstructor(options: WorktreeSummaryServiceOptions) {\n\t\tthis.watchService = options.watchService;\n\t\tthis.getRepository = options.getRepository;\n\t\tthis.getCommonPath = options.getCommonPath;\n\t\tthis.mergeTargetsListener = options.onDidChangeMergeTargets?.(e => this.onMergeTargetsChanged(e));\n\t}\n\n\t[Symbol.dispose](): void {\n\t\tthis.dispose();\n\t}\n\n\tdispose(): void {\n\t\tif (this._disposed) return;\n\n\t\tthis._disposed = true;\n\t\tfor (const resolve of this.readWaiters.values()) {\n\t\t\tresolve(false);\n\t\t}\n\t\tthis.readWaiters.clear();\n\t\tthis.mergeTargetsListener?.dispose();\n\t\tfor (const entry of [...this.entries.values()]) {\n\t\t\tfor (const subscription of [...entry.subscribers]) {\n\t\t\t\tsubscription.dispose();\n\t\t\t}\n\t\t}\n\t\tthis.entries.clear();\n\t\tthis._onDidChangeSummary.dispose();\n\t}\n\n\t/** Subscribes to a worktree's summary, starting to watch and read it if this is its first subscriber */\n\tsubscribe(repoPath: string, options?: WorktreeSummarySubscribeOptions): WorktreeSummarySubscription {\n\t\tconst key = getRepositoryKey(repoPath);\n\n\t\tlet entry = this._disposed ? undefined : this.entries.get(key);\n\t\tconst isNew = entry == null;\n\t\tif (entry == null) {\n\t\t\tentry = createEntry(key);\n\t\t\tif (this._disposed) {\n\t\t\t\tentry.disposed = true;\n\t\t\t} else {\n\t\t\t\tthis.entries.set(key, entry);\n\t\t\t}\n\t\t}\n\n\t\tconst target = entry;\n\t\tconst subscription = new SummarySubscription(target, options, s => this.release(target, s));\n\t\ttarget.subscribers.add(subscription);\n\n\t\tif (isNew) {\n\t\t\tif (!target.disposed) {\n\t\t\t\ttarget.pending = allFields | baseConfigField;\n\t\t\t\ttarget.running = this.start(target);\n\t\t\t}\n\t\t} else if (target.handle != null) {\n\t\t\tsubscription.attach(target.handle.session);\n\t\t} else if (target.running == null && !target.disposed) {\n\t\t\t// The start failed (no repository or git directory yet); a new subscriber retries it\n\t\t\ttarget.pending = allFields | baseConfigField;\n\t\t\ttarget.running = this.start(target);\n\t\t}\n\n\t\treturn subscription;\n\t}\n\n\t/**\n\t * Returns a worktree's summary. For a subscribed worktree, the cached value — after waiting for any run in flight\n\t * or pending; it rejects with the read's error when there is still no value. Otherwise a one-off full read that\n\t * is neither cached nor watched.\n\t */\n\tasync getSummary(repoPath: string, cancellation?: AbortSignal): Promise<WorktreeSummary> {\n\t\tconst key = getRepositoryKey(repoPath);\n\t\tconst entry = this.entries.get(key);\n\t\tif (entry == null) {\n\t\t\tconst repo = this.getRepository(key);\n\t\t\tif (repo == null) throw new Error(`No repository found for '${key}'`);\n\n\t\t\tconst result = await readSummary(repo, key, allFields, undefined, undefined, undefined, cancellation);\n\t\t\treturn result.summary;\n\t\t}\n\n\t\tif (entry.running != null) {\n\t\t\tawait (cancellation != null ? raceWithSignal(entry.running, cancellation) : entry.running);\n\t\t}\n\t\tif (entry.disposed) throw new CancellationError();\n\t\tif (entry.value != null) return entry.value;\n\n\t\tthrow entry.error ?? new Error(`No summary available for '${key}'`);\n\t}\n\n\tgetResourceUsage(): ResourceUsage {\n\t\treturn { 'worktreeSummary.entries.count': this.entries.size };\n\t}\n\n\tprivate async start(entry: SummaryEntry): Promise<void> {\n\t\tlet gitDir: GitDir | undefined;\n\t\ttry {\n\t\t\tgitDir = await this.getRepository(entry.key)?.config.getGitDir?.();\n\t\t} catch (ex) {\n\t\t\tif (entry.disposed) return;\n\n\t\t\tentry.running = undefined;\n\t\t\tif (!isCancellationError(ex)) {\n\t\t\t\tthis.fail(entry, ex);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (entry.disposed) return;\n\n\t\tconst handle = gitDir != null ? this.watchService.watch(entry.key, gitDir) : undefined;\n\t\tif (gitDir == null || handle == null) {\n\t\t\tentry.running = undefined;\n\t\t\tthis.fail(entry, new Error(`Unable to watch '${entry.key}': no repository or git directory`));\n\t\t\treturn;\n\t\t}\n\n\t\tentry.handle = handle;\n\t\tentry.slotsKey = getRepositoryKey(gitDir.commonUri ?? gitDir.uri);\n\t\tconst session = handle.session;\n\t\t// Timing-neutral: the cadence comes from the subscribers' own session subscriptions (see `attach`)\n\t\tconst repoSub = session.subscribe({ delayMs: Infinity, maxWaitMs: Infinity });\n\t\tconst workingTreeSub = session.subscribeToWorkingTree({ delayMs: Infinity, maxWaitMs: Infinity });\n\t\tentry.listeners = [\n\t\t\trepoSub.onDidChange(e => this.onRepoChanged(entry, e)),\n\t\t\tworkingTreeSub.onDidChangeWorkingTree(() => this.queue(entry, dirtyField)),\n\t\t\trepoSub,\n\t\t\tworkingTreeSub,\n\t\t];\n\t\tfor (const subscription of entry.subscribers) {\n\t\t\tsubscription.attach(session);\n\t\t}\n\n\t\tawait this.drain(entry);\n\t}\n\n\tprivate onRepoChanged(entry: SummaryEntry, e: WatcherRepoChangeEvent): void {\n\t\tconst value = entry.value;\n\t\tif (value == null || e.changed('unknown', 'head')) {\n\t\t\tthis.queue(entry, allFields | (e.changed('config') ? baseConfigField : 0));\n\t\t\treturn;\n\t\t}\n\n\t\tlet fields = 0;\n\t\tif (e.changed('index', 'ignores')) {\n\t\t\tfields |= dirtyField;\n\t\t}\n\t\tif (e.changed('config') && e.mayHaveChangedConfig(getConfigRelevantRefs(value))) {\n\t\t\tfields |= branchField | baseKeysField | baseConfigField;\n\t\t}\n\t\tif (e.changed('gkConfig')) {\n\t\t\tfields |= baseKeysField;\n\t\t}\n\t\tif (value.branch != null && e.mayHaveChangedRef(`refs/heads/${value.branch}`)) {\n\t\t\tfields |= allFields;\n\t\t}\n\t\t// The upstream's short name doesn't say whether it's remote or local (`--track main`), so test both forms\n\t\tif (\n\t\t\tvalue.upstream != null &&\n\t\t\t(e.mayHaveChangedRef(`refs/remotes/${value.upstream.name}`) ||\n\t\t\t\te.mayHaveChangedRef(`refs/heads/${value.upstream.name}`))\n\t\t) {\n\t\t\tfields |= branchField;\n\t\t}\n\t\tif ((fields & baseField) === 0) {\n\t\t\tfor (const ref of value.baseDependsOn) {\n\t\t\t\tif (e.mayHaveChangedRef(ref)) {\n\t\t\t\t\tfields |= baseField;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.queue(entry, fields);\n\t}\n\n\t/**\n\t * Queued synchronously, so a store awaited before `getSummary` finds the run in flight. The watcher's later\n\t * `gkConfig` event for the same write then finds the keys unchanged and leaves the base alone.\n\t */\n\tprivate onMergeTargetsChanged(e: MergeTargetsChangeEvent): void {\n\t\tfor (const entry of this.entries.values()) {\n\t\t\t// Before the watch starts there's nothing to refresh: the start's own read comes after the write\n\t\t\tif (entry.handle == null) continue;\n\n\t\t\t// With no value yet, the first read may have read the stored values before the write, so `queue` reads\n\t\t\t// everything again\n\t\t\tconst value = entry.value;\n\t\t\tif (value != null && (value.branch == null || (e.refs != null && !e.refs.has(value.branch)))) continue;\n\n\t\t\tconst commonPath = this.getCommonPath?.(entry.key);\n\t\t\tif (commonPath != null && commonPath !== e.repoPath) continue;\n\n\t\t\tthis.queue(entry, baseKeysField);\n\t\t}\n\t}\n\n\tprivate queue(entry: SummaryEntry, fields: number): void {\n\t\tif (entry.disposed || fields === 0) return;\n\n\t\t// Without a value a partial read has nothing to merge into, and a stale value's fields can't be trusted: a\n\t\t// partial read would clear `stale` while vouching for groups it never re-read\n\t\tentry.pending |= entry.value == null || entry.value.stale ? fields | allFields | baseConfigField : fields;\n\t\tentry.running ??= this.drain(entry);\n\t}\n\n\t/** Runs until nothing is pending. Never rejects — every failure becomes entry state. */\n\tprivate async drain(entry: SummaryEntry): Promise<void> {\n\t\twhile (entry.pending !== 0 && !entry.disposed) {\n\t\t\tif (!(await this.acquireRead(entry))) break;\n\n\t\t\ttry {\n\t\t\t\tif (entry.disposed) break;\n\n\t\t\t\t// Consume after acquiring: changes that arrived while queued belong to this same read.\n\t\t\t\tconst fields = entry.pending;\n\t\t\t\tentry.pending = 0;\n\t\t\t\tawait this.run(entry, fields);\n\t\t\t} finally {\n\t\t\t\tthis.releaseRead(entry);\n\t\t\t}\n\t\t}\n\t\t// Same turn as the loop's last check, so an event can't queue fields that no run will pick up\n\t\tentry.running = undefined;\n\t}\n\n\t/**\n\t * A read takes one of its repository's slots and one of the service's. Each release hands what it frees to the\n\t * waiters first, so a new read takes a slot only when no waiter can use it.\n\t */\n\tprivate acquireRead(entry: SummaryEntry): Promise<boolean> {\n\t\tif (entry.disposed || this._disposed) return Promise.resolve(false);\n\n\t\tif (this.tryTakeReadSlots(entry)) return Promise.resolve(true);\n\n\t\treturn new Promise(resolve => this.readWaiters.set(entry, resolve));\n\t}\n\n\tprivate releaseRead(entry: SummaryEntry): void {\n\t\tconst key = entry.slotsKey ?? entry.key;\n\t\tconst active = this.activeReadsByRepository.get(key);\n\t\tif (active == null) return;\n\n\t\tif (active > 1) {\n\t\t\tthis.activeReadsByRepository.set(key, active - 1);\n\t\t} else {\n\t\t\tthis.activeReadsByRepository.delete(key);\n\t\t}\n\t\tthis.activeReads--;\n\n\t\t// The oldest waiter whose repository has a free slot goes next, so a repository at its own cap never holds up\n\t\t// another's waiters, and a busy checkout rejoins the tail for a follow-up rather than starving its siblings\n\t\tfor (const [waiter, resolve] of this.readWaiters) {\n\t\t\tif (this.activeReads >= maxConcurrentReads) break;\n\n\t\t\tif (waiter.disposed || this._disposed) {\n\t\t\t\tthis.readWaiters.delete(waiter);\n\t\t\t\tresolve(false);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (!this.tryTakeReadSlots(waiter)) continue;\n\n\t\t\tthis.readWaiters.delete(waiter);\n\t\t\tresolve(true);\n\t\t}\n\t}\n\n\tprivate tryTakeReadSlots(entry: SummaryEntry): boolean {\n\t\tif (this.activeReads >= maxConcurrentReads) return false;\n\n\t\tconst key = entry.slotsKey ?? entry.key;\n\t\tconst active = this.activeReadsByRepository.get(key) ?? 0;\n\t\tif (active >= maxConcurrentReadsPerRepository) return false;\n\n\t\tthis.activeReadsByRepository.set(key, active + 1);\n\t\tthis.activeReads++;\n\t\treturn true;\n\t}\n\n\tprivate async run(entry: SummaryEntry, fields: number): Promise<void> {\n\t\tconst previous = entry.value;\n\n\t\tlet result: ReadResult;\n\t\ttry {\n\t\t\tconst repo = this.getRepository(entry.key);\n\t\t\tif (repo == null) throw new Error(`No repository found for '${entry.key}'`);\n\n\t\t\tresult = await readSummary(\n\t\t\t\trepo,\n\t\t\t\tentry.key,\n\t\t\t\tfields,\n\t\t\t\tprevious,\n\t\t\t\tentry.baseKeys,\n\t\t\t\tentry.baseConfigKey,\n\t\t\t\tentry.abort.signal,\n\t\t\t);\n\t\t} catch (ex) {\n\t\t\tif (entry.disposed || isCancellationError(ex)) return;\n\n\t\t\tthis.fail(entry, ex);\n\t\t\treturn;\n\t\t}\n\t\tif (entry.disposed) return;\n\n\t\tif (result.summary.stale && (previous == null || !previous.stale)) {\n\t\t\tLogger.warn(\n\t\t\t\t`WorktreeSummaryService: reading the base of '${entry.key}' failed: ${String(result.baseError)}`,\n\t\t\t);\n\t\t}\n\n\t\tentry.error = undefined;\n\t\tentry.baseKeys = result.baseKeys;\n\t\tentry.baseConfigKey = entry.pending & baseConfigField ? undefined : result.baseConfigKey;\n\t\tif (previous != null && summariesEqual(previous, result.summary)) return;\n\n\t\tentry.value = result.summary;\n\t\tthis.fireChange(entry, result.summary);\n\t}\n\n\tprivate fail(entry: SummaryEntry, ex: unknown): void {\n\t\tconst previous = entry.value;\n\t\tif (previous == null) {\n\t\t\tif (entry.error == null) {\n\t\t\t\tLogger.warn(`WorktreeSummaryService: reading '${entry.key}' failed: ${String(ex)}`);\n\t\t\t}\n\t\t\tentry.error = ex instanceof Error ? ex : new Error(String(ex));\n\t\t\treturn;\n\t\t}\n\t\tif (previous.stale) return;\n\n\t\tLogger.warn(`WorktreeSummaryService: refreshing '${entry.key}' failed: ${String(ex)}`);\n\t\tconst summary: WorktreeSummary = { ...previous, stale: true };\n\t\tentry.value = summary;\n\t\tthis.fireChange(entry, summary);\n\t}\n\n\tprivate fireChange(entry: SummaryEntry, summary: WorktreeSummary): void {\n\t\tfor (const subscription of entry.subscribers) {\n\t\t\tsubscription.fire(summary);\n\t\t}\n\t\tthis._onDidChangeSummary.fire(summary);\n\t}\n\n\tprivate release(entry: SummaryEntry, subscription: SummarySubscription): void {\n\t\tentry.subscribers.delete(subscription);\n\t\tif (entry.subscribers.size !== 0) return;\n\n\t\tentry.disposed = true;\n\t\t// A waiter holds no slot, so dropping it frees none\n\t\tconst cancelRead = this.readWaiters.get(entry);\n\t\tif (cancelRead != null) {\n\t\t\tthis.readWaiters.delete(entry);\n\t\t\tcancelRead(false);\n\t\t}\n\t\tentry.abort.abort();\n\t\tif (entry.listeners != null) {\n\t\t\tfor (const d of entry.listeners) {\n\t\t\t\td.dispose();\n\t\t\t}\n\t\t\tentry.listeners = undefined;\n\t\t}\n\t\tentry.handle?.dispose();\n\t\tentry.handle = undefined;\n\t\tentry.value = undefined;\n\t\tentry.baseKeys = undefined;\n\t\tentry.baseConfigKey = undefined;\n\t\tentry.pending = 0;\n\t\tentry.running = undefined;\n\n\t\tif (this.entries.get(entry.key) === entry) {\n\t\t\tthis.entries.delete(entry.key);\n\t\t}\n\t}\n}\n\n/**\n * The local branches whose config sections a summary reads: its branch's (upstream and base keys), and those of the\n * branches it tracks or bases on. The upstream's short name doesn't say whether it's local, so it counts as local too.\n */\nfunction* getConfigRelevantRefs(value: WorktreeSummary): Iterable<string> {\n\tif (value.branch != null) {\n\t\tyield `refs/heads/${value.branch}`;\n\t}\n\tif (value.upstream != null) {\n\t\tyield `refs/heads/${value.upstream.name}`;\n\t}\n\tyield* value.baseDependsOn;\n}\n\nfunction createEntry(key: string): SummaryEntry {\n\treturn {\n\t\tkey: key,\n\t\tslotsKey: undefined,\n\t\tabort: new AbortController(),\n\t\tsubscribers: new Set(),\n\t\thandle: undefined,\n\t\tlisteners: undefined,\n\t\tvalue: undefined,\n\t\tbaseKeys: undefined,\n\t\tbaseConfigKey: undefined,\n\t\terror: undefined,\n\t\tpending: 0,\n\t\trunning: undefined,\n\t\tdisposed: false,\n\t};\n}\n\n/**\n * Reads the due groups and fills the rest from `previous` (every group when there is none). The branch read comes\n * before the base read, which needs its name; the dirty read runs alongside both. A branch read that finds a\n * different branch (or detached state) also reads the base and dirty groups, and stored base values that differ\n * from `previousBaseKeys` read the base group. A failed base read doesn't fail the rest: the summary comes back stale,\n * keeping the previous base and `baseDependsOn` only while the branch is the same.\n */\nasync function readSummary(\n\trepo: RepositoryService,\n\tkey: string,\n\tfields: number,\n\tprevious: WorktreeSummary | undefined,\n\tpreviousBaseKeys: BaseKeys | undefined,\n\tpreviousBaseConfigKey: string | undefined,\n\tsignal: AbortSignal | undefined,\n): Promise<ReadResult> {\n\tif (previous == null) {\n\t\tfields |= allFields;\n\t}\n\n\tlet dirtyRead = fields & dirtyField ? readDirty(repo, signal) : undefined;\n\n\tlet branch = previous?.branch;\n\tlet detached = previous?.detached ?? false;\n\tlet sha = previous?.sha;\n\tlet upstream = previous?.upstream;\n\tlet ahead = previous?.ahead ?? 0;\n\tlet behind = previous?.behind ?? 0;\n\tif (fields & branchField) {\n\t\tconst current = await repo.branches.getBranch(undefined, undefined, signal);\n\t\tdetached = current?.detached ?? false;\n\t\tbranch = detached ? undefined : current?.name || undefined;\n\t\tsha = current?.sha;\n\t\tupstream = current?.upstream != null ? await toSummaryUpstream(repo, current.upstream, signal) : undefined;\n\t\tahead = current?.upstream?.state.ahead ?? 0;\n\t\tbehind = current?.upstream?.state.behind ?? 0;\n\n\t\tif (previous != null && (branch !== previous.branch || detached !== previous.detached)) {\n\t\t\tfields |= baseField;\n\t\t\tdirtyRead ??= readDirty(repo, signal);\n\t\t}\n\t}\n\n\tlet base = previous?.base;\n\tlet dependsOn = previous?.baseDependsOn ?? emptyRefs;\n\tlet baseKeys = previousBaseKeys;\n\tlet baseKeysRead = false;\n\tlet baseConfigKey = previousBaseConfigKey;\n\tlet baseConfigKeyRead = false;\n\tlet baseFailed = false;\n\tlet baseError: unknown;\n\t// A detached HEAD is measured as `undefined`; an unborn HEAD with no name has nothing to measure\n\tconst baseReadable = repo.branches.getAheadOfBase != null && (detached || branch != null);\n\tif (fields & baseConfigField && !(fields & baseField) && baseReadable) {\n\t\tbaseConfigKey = await readBaseConfigKey(repo, signal);\n\t\tbaseConfigKeyRead = true;\n\t\tif (\n\t\t\tbaseConfigKey == null ||\n\t\t\tbaseConfigKey !== previousBaseConfigKey ||\n\t\t\tsha !== previous?.sha ||\n\t\t\t!upstreamsEqual(upstream, previous?.upstream)\n\t\t) {\n\t\t\tfields |= baseField;\n\t\t}\n\t}\n\tif (fields & baseKeysField && !(fields & baseField) && baseReadable) {\n\t\tbaseKeys = await readBaseKeys(repo, branch);\n\t\tbaseKeysRead = true;\n\t\tif (baseKeys == null || previousBaseKeys == null || !baseKeysEqual(baseKeys, previousBaseKeys)) {\n\t\t\tfields |= baseField;\n\t\t}\n\t}\n\tif (fields & baseField) {\n\t\tif (!baseReadable) {\n\t\t\tbase = undefined;\n\t\t\tdependsOn = emptyRefs;\n\t\t\tbaseKeys = undefined;\n\t\t\tbaseConfigKey = undefined;\n\t\t} else {\n\t\t\t// Snapshot before the base read, so a write it misses is one the next `gk` config event sees as a change\n\t\t\tif (!baseKeysRead) {\n\t\t\t\tbaseKeys = await readBaseKeys(repo, branch);\n\t\t\t}\n\t\t\tif (!baseConfigKeyRead && (previous != null || (fields & baseConfigField) !== 0)) {\n\t\t\t\tbaseConfigKey = await readBaseConfigKey(repo, signal);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst aheadOfBase = await repo.branches.getAheadOfBase?.(branch, undefined, signal);\n\t\t\t\tbase = aheadOfBase?.base;\n\t\t\t\tdependsOn = aheadOfBase?.dependsOn ?? emptyRefs;\n\t\t\t} catch (ex) {\n\t\t\t\tif (isCancellationError(ex)) throw ex;\n\n\t\t\t\tbaseFailed = true;\n\t\t\t\tbaseError = ex;\n\t\t\t\t// Keep `baseDependsOn` for the same branch: a fetch moving one of its refs is what retries the base\n\t\t\t\tconst sameBranch = previous != null && branch === previous.branch && detached === previous.detached;\n\t\t\t\tbase = sameBranch ? previous.base : undefined;\n\t\t\t\tdependsOn = sameBranch ? previous.baseDependsOn : emptyRefs;\n\t\t\t\tbaseKeys = undefined;\n\t\t\t\tbaseConfigKey = undefined;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst dirty = dirtyRead != null ? await dirtyRead : (previous?.dirty ?? false);\n\n\treturn {\n\t\tsummary: {\n\t\t\trepoPath: key,\n\t\t\tbranch: branch,\n\t\t\tdetached: detached,\n\t\t\tsha: sha,\n\t\t\tupstream: upstream,\n\t\t\tahead: ahead,\n\t\t\tbehind: behind,\n\t\t\tdirty: dirty,\n\t\t\tbase: base,\n\t\t\tbaseDependsOn: dependsOn,\n\t\t\tstale: baseFailed,\n\t\t},\n\t\tbaseKeys: baseKeys,\n\t\tbaseConfigKey: baseConfigKey,\n\t\tbaseError: baseError,\n\t};\n}\n\nasync function readBaseConfigKey(\n\trepo: RepositoryService,\n\tsignal: AbortSignal | undefined,\n): Promise<string | undefined> {\n\ttry {\n\t\treturn await repo.branches.getAheadOfBaseConfigKey?.(signal);\n\t} catch (ex) {\n\t\tif (isCancellationError(ex)) throw ex;\n\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Reads {@link BaseKeys} for `branch`, normalized the way `getAheadOfBase` reads them. `undefined` when any read\n * failed — an unknown snapshot, so the next `gk` config change reads the base rather than trusting it. A detached\n * HEAD (`branch` undefined) has no stored values to read.\n */\nasync function readBaseKeys(repo: RepositoryService, branch: string | undefined): Promise<BaseKeys | undefined> {\n\tif (branch == null) return noBaseKeys;\n\n\ttry {\n\t\tconst [user, detected, recorded] = await Promise.all([\n\t\t\trepo.branches.getStoredUserMergeTargetBranchName?.(branch),\n\t\t\trepo.branches.getStoredDetectedMergeTargetBranchName?.(branch),\n\t\t\trepo.config.getGkConfig?.(`branch.${branch}.gk-merge-base`),\n\t\t]);\n\t\treturn [user?.trim() || undefined, detected?.trim() || undefined, recorded?.trim() || undefined];\n\t} catch (ex) {\n\t\tif (isCancellationError(ex)) throw ex;\n\n\t\treturn undefined;\n\t}\n}\n\nfunction baseKeysEqual(a: BaseKeys, b: BaseKeys): boolean {\n\treturn a[0] === b[0] && a[1] === b[1] && a[2] === b[2];\n}\n\nfunction readDirty(repo: RepositoryService, signal: AbortSignal | undefined): Promise<boolean> {\n\tconst read = repo.status.hasWorkingChanges({ untracked: true }, signal);\n\t// Awaited only after the branch and base reads; if one of those throws first, this rejection has no other handler\n\tread.catch(noop);\n\treturn read;\n}\n\nfunction noop(): void {}\n\n/**\n * Uses the remote and branch git reported for the upstream; only when it reported neither does this split the name\n * at the longest remote name it starts with (no split when none matches or nothing follows it)\n */\nasync function toSummaryUpstream(\n\trepo: RepositoryService,\n\tupstream: GitTrackingUpstream,\n\tsignal: AbortSignal | undefined,\n): Promise<WorktreeSummaryUpstream> {\n\tconst { name, missing } = upstream;\n\n\tif (upstream.local) return { name: name, remote: undefined, branch: undefined, missing: missing };\n\n\tif (upstream.remote) {\n\t\tconst { remote } = upstream;\n\t\tconst branch =\n\t\t\tupstream.remoteBranch || (name.startsWith(`${remote}/`) ? name.substring(remote.length + 1) : undefined);\n\t\treturn { name: name, remote: branch ? remote : undefined, branch: branch || undefined, missing: missing };\n\t}\n\n\tlet remote: string | undefined;\n\tfor (const r of await repo.remotes.getRemotes(undefined, signal)) {\n\t\tif (r.name && name.startsWith(`${r.name}/`) && (remote == null || r.name.length > remote.length)) {\n\t\t\tremote = r.name;\n\t\t}\n\t}\n\n\tconst branch = remote != null ? name.substring(remote.length + 1) : undefined;\n\treturn {\n\t\tname: name,\n\t\tremote: branch ? remote : undefined,\n\t\tbranch: branch || undefined,\n\t\tmissing: missing,\n\t};\n}\n\nfunction upstreamsEqual(a: WorktreeSummaryUpstream | undefined, b: WorktreeSummaryUpstream | undefined): boolean {\n\treturn (\n\t\ta === b ||\n\t\t(a != null &&\n\t\t\tb != null &&\n\t\t\ta.name === b.name &&\n\t\t\ta.remote === b.remote &&\n\t\t\ta.branch === b.branch &&\n\t\t\ta.missing === b.missing)\n\t);\n}\n\nfunction summariesEqual(a: WorktreeSummary, b: WorktreeSummary): boolean {\n\treturn (\n\t\ta.repoPath === b.repoPath &&\n\t\ta.branch === b.branch &&\n\t\ta.detached === b.detached &&\n\t\ta.sha === b.sha &&\n\t\ta.ahead === b.ahead &&\n\t\ta.behind === b.behind &&\n\t\ta.dirty === b.dirty &&\n\t\ta.stale === b.stale &&\n\t\tareEqual(a.baseDependsOn, b.baseDependsOn) &&\n\t\tupstreamsEqual(a.upstream, b.upstream) &&\n\t\t(a.base === b.base ||\n\t\t\t(a.base != null &&\n\t\t\t\tb.base != null &&\n\t\t\t\ta.base.ref === b.base.ref &&\n\t\t\t\ta.base.ahead === b.base.ahead &&\n\t\t\t\ta.base.sha === b.base.sha &&\n\t\t\t\ta.base.forkPoint === b.base.forkPoint &&\n\t\t\t\ta.base.tier === b.base.tier))\n\t);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"worktreeSummary.js","names":[],"sources":["../../../../git/src/watching/worktreeSummary.ts"],"sourcesContent":["import { areEqual } from '@gitlens/utils/array.js';\nimport { CancellationError, isCancellationError, raceWithSignal } from '@gitlens/utils/cancellation.js';\nimport type { UnifiedDisposable } from '@gitlens/utils/disposable.js';\nimport type { Event } from '@gitlens/utils/event.js';\nimport { Emitter } from '@gitlens/utils/event.js';\nimport { Logger } from '@gitlens/utils/logger.js';\nimport type { ResourceUsage } from '@gitlens/utils/resourceUsage.js';\nimport { getRepositoryKey } from '@gitlens/utils/uri.js';\nimport type { MergeTargetsChangeEvent } from '../cache.js';\nimport type { GitTrackingUpstream } from '../models/branch.js';\nimport type { GitDir } from '../models/repository.js';\nimport type { AheadOfBase, AheadOfBaseTier } from '../providers/branches.js';\nimport type { RepositoryService } from '../repositoryService.js';\nimport type { WatcherRepoChangeEvent } from './changeEvent.js';\nimport { getRefChangeKind } from './changeEvent.js';\nimport type { RepositoryWatchService, WatchHandle } from './watchService.js';\nimport type { RepositoryWatchSession } from './watchSession.js';\n\nexport interface WorktreeSummaryUpstream {\n\t/** The upstream's short name (`origin/main`) */\n\treadonly name: string;\n\t/**\n\t * The remote it tracks, as git reported it; on git too old to report it, the longest of the repository's remote\n\t * names that {@link name} starts with, followed by `/` (a remote name can hold a slash). `undefined`, with\n\t * {@link branch}, when it names no known remote (a branch tracking another local branch, or a remote since removed)\n\t */\n\treadonly remote: string | undefined;\n\t/**\n\t * The branch on {@link remote} — git's name for it there, which a custom fetch refspec can make differ from the end\n\t * of {@link name}; `undefined` whenever {@link remote} is\n\t */\n\treadonly branch: string | undefined;\n\treadonly missing: boolean;\n}\n\nexport interface WorktreeSummaryBase {\n\t/** The ref the count was taken against (see `AheadOfBase.base`) */\n\treadonly ref: string;\n\treadonly ahead: number;\n\t/** The commit {@link ref} pointed at when the count was read; `undefined` when it couldn't be resolved */\n\treadonly sha: string | undefined;\n\t/** Where HEAD forked from {@link ref} (see `AheadOfBase.base`) */\n\treadonly forkPoint: string | undefined;\n\t/** The source the base came from (see `AheadOfBase.base`) */\n\treadonly tier: AheadOfBaseTier;\n}\n\nexport interface WorktreeSummary {\n\t/** The repository path in {@link getRepositoryKey} form */\n\treadonly repoPath: string;\n\t/** The checked-out branch; `undefined` when detached (or unborn with no name) */\n\treadonly branch: string | undefined;\n\treadonly detached: boolean;\n\t/** HEAD's commit; `undefined` when HEAD has no commit yet */\n\treadonly sha: string | undefined;\n\treadonly upstream: WorktreeSummaryUpstream | undefined;\n\t/** Commits ahead of the upstream; 0 without one */\n\treadonly ahead: number;\n\t/** Commits behind the upstream; 0 without one */\n\treadonly behind: number;\n\t/** Whether there is any staged, unstaged or untracked (non-ignored) change */\n\treadonly dirty: boolean;\n\t/**\n\t * How far the branch — or a detached HEAD, measured against the default branch — is past its base; `undefined` when\n\t * unsupported or there is no base\n\t */\n\treadonly base: WorktreeSummaryBase | undefined;\n\t/**\n\t * Full ref names whose movement can change {@link base}, as `getAheadOfBase` reports them (see\n\t * `AheadOfBase.dependsOn`) — given with or without a base, so a watcher also learns when one appears. Empty when\n\t * the base isn't read (an unborn HEAD with no name, or a provider without `getAheadOfBase`), and when the base read\n\t * failed with no earlier list for this HEAD (the first read, or the one after a checkout).\n\t */\n\treadonly baseDependsOn: readonly string[];\n\t/**\n\t * The latest recompute failed (worktree gone, lock contention); the other fields hold the last values read. Also set\n\t * when only the base read failed: the other fields are fresh, and `base` and `baseDependsOn` are their last values,\n\t * or `undefined` and empty if the branch changed.\n\t */\n\treadonly stale: boolean;\n}\n\nexport interface WorktreeSummarySubscribeOptions {\n\t/** Debounce for repo (`.git`) changes this subscriber asks of the watch session; the shortest across subscribers wins */\n\treadonly delayMs?: number;\n\t/** Cap on how long continuous repo activity can defer a recompute; `Infinity` means no cap */\n\treadonly maxWaitMs?: number;\n\t/** Debounce for working-tree changes this subscriber asks of the watch session */\n\treadonly workingTreeDelayMs?: number;\n\t/** Cap on how long continuous working-tree activity can defer a recompute; `Infinity` means no cap */\n\treadonly workingTreeMaxWaitMs?: number;\n}\n\nexport interface WorktreeSummarySubscription extends UnifiedDisposable {\n\t/** The latest summary; `undefined` until the first read succeeds, or after disposal */\n\treadonly current: WorktreeSummary | undefined;\n\t/** Fires when the summary's value changes */\n\treadonly onDidChange: Event<WorktreeSummary>;\n}\n\nexport interface WorktreeSummaryServiceOptions {\n\treadonly watchService: RepositoryWatchService;\n\treadonly getRepository: (repoPath: string) => RepositoryService | undefined;\n\t/**\n\t * Fires as core writes a branch's merge target or base, before the store's promise resolves; the summary re-reads\n\t * that branch's stored values then, so a `getSummary` right after an awaited store sees the new base\n\t */\n\treadonly onDidChangeMergeTargets?: Event<MergeTargetsChangeEvent>;\n\t/**\n\t * Maps a worktree path to the repository common path that {@link onDidChangeMergeTargets} events carry; only that\n\t * repository's summaries react. Without it, or when it returns `undefined`, every summary reacts.\n\t */\n\treadonly getCommonPath?: (repoPath: string) => string | undefined;\n\t/**\n\t * For tests only; production never passes it. Called whenever the base re-measure answers in place of a full base\n\t * read, with its answer and what a full `getAheadOfBase` of the same branch answers right after (`undefined` when\n\t * that rejects or the provider has none), so a test can fail where the shortcut keeps an answer the full read would\n\t * not. The summary keeps the re-measure's answer either way. The full read goes through the same provider and\n\t * caches as the shortcut, so it checks the shortcut's reasoning, not whether those caches are current. The callback\n\t * should record a mismatch for the test to fail on rather than throw: a throw is taken for a failed base read.\n\t * Unset, it costs one check of the option.\n\t */\n\treadonly verifyBaseRemeasure?: (remeasured: AheadOfBase, full: AheadOfBase | undefined) => void;\n}\n\n/** Read groups, as bit flags so a pending set is a number rather than an allocation per event */\nconst dirtyField = 1;\nconst branchField = 2;\nconst baseField = 4;\n/** Re-reads only the stored values the base read consults, and the base itself only when they changed */\nconst baseKeysField = 8;\n/** Re-reads the provider's Git config inputs before deciding whether the base needs a refresh */\nconst baseConfigField = 16;\n/**\n * Refreshes the base after only refs it depends on moved, each named exactly (in {@link SummaryEntry.baseMoves}): when\n * the base's own ref just moved forward, it is re-measured rather than resolved again. {@link baseField} overrides it.\n */\nconst baseMoveField = 32;\n/** Every group a full read covers — a base read refreshes the {@link BaseKeys} snapshot itself */\nconst allFields = dirtyField | branchField | baseField;\n\n// Shared config and ref changes reach every checkout of a repository together; bound that repository's Git fan-out so\n// input can keep moving. Per repository, so a burst in one, or reads hung in it, never holds up another's.\nconst maxConcurrentReadsPerRepository = 4;\n// And across repositories, so a start (or an overflow rescan) over many of them never runs four reads for each at once.\n// Each read runs a couple of git processes side by side, so eight leave most of the process queue to foreground\n// commands and the CPU to the host; a hung read still frees its slot once git's command timeout ends it.\nconst maxConcurrentReads = 8;\n\nconst emptyRefs: readonly string[] = Object.freeze([]);\n\n/**\n * The current branch's stored merge targets (user, detected) and recorded base, as `getAheadOfBase` consults them.\n * A detached HEAD has no stored values, so it holds {@link noBaseKeys}.\n */\ntype BaseKeys = readonly [string | undefined, string | undefined, string | undefined];\n\nconst noBaseKeys: BaseKeys = [undefined, undefined, undefined];\n\n/**\n * The provider's Git config inputs to the base as one read found them: its entries (see\n * `getAheadOfBaseConfigEntries`), or the opaque key of a provider without them\n */\ntype BaseConfig = readonly (readonly [key: string, value: string | undefined])[] | string;\n\ninterface ReadResult {\n\treadonly summary: WorktreeSummary;\n\treadonly baseKeys: BaseKeys | undefined;\n\treadonly baseConfigKey: string | undefined;\n\t/** The default branch the base read resolved (see `AheadOfBase.defaultBranch`); `undefined` when unknown */\n\treadonly baseDefaultBranch: string | null | undefined;\n\t/** Why the base read failed when the rest of the summary was read; the summary is then stale */\n\treadonly baseError: unknown;\n}\n\ninterface SummaryEntry {\n\treadonly key: string;\n\t/**\n\t * The repository's common git directory, which keys its read slots; set once the watch starts, and kept after the\n\t * last subscriber leaves, since a read still in flight then frees the slots it took under it\n\t */\n\tslotsKey: string | undefined;\n\t/** Aborted when the last subscriber leaves, cancelling any in-flight read */\n\treadonly abort: AbortController;\n\treadonly subscribers: Set<SummarySubscription>;\n\thandle: WatchHandle | undefined;\n\t/** The timing-neutral listening subscriptions and their event listeners */\n\tlisteners: UnifiedDisposable[] | undefined;\n\tvalue: WorktreeSummary | undefined;\n\t/** The stored base values as of the last base read; a `gk` config change re-reads the base only when they differ */\n\tbaseKeys: BaseKeys | undefined;\n\t/**\n\t * The config inputs the last base read consulted, as of just before it (see {@link getBaseConfigKey}); a config\n\t * change re-reads the base only when they differ\n\t */\n\tbaseConfigKey: string | undefined;\n\t/** The default branch the last base read resolved, for a re-measure to check; `undefined` when unknown */\n\tbaseDefaultBranch: string | null | undefined;\n\t/** Why the latest read failed while there was no value to keep */\n\terror: Error | undefined;\n\t/** Read groups due on the next run */\n\tpending: number;\n\t/** The refs the base depends on that moved, by name, for a pending {@link baseMoveField} */\n\tbaseMoves: Set<string> | undefined;\n\t/** The active run (or the start-up, which ends in one); cleared in the same turn the loop sees nothing pending */\n\trunning: Promise<void> | undefined;\n\tdisposed: boolean;\n}\n\nclass SummarySubscription implements WorktreeSummarySubscription {\n\tprivate readonly emitter = new Emitter<WorktreeSummary>();\n\t/** Listener-less session subscriptions that carry this subscriber's timing into the session */\n\tprivate timing: UnifiedDisposable[] | undefined;\n\tprivate disposed = false;\n\n\tconstructor(\n\t\tprivate readonly entry: SummaryEntry,\n\t\tprivate readonly options: WorktreeSummarySubscribeOptions | undefined,\n\t\tprivate readonly onDispose: (subscription: SummarySubscription) => void,\n\t) {}\n\n\tget current(): WorktreeSummary | undefined {\n\t\treturn this.disposed ? undefined : this.entry.value;\n\t}\n\n\tget onDidChange(): Event<WorktreeSummary> {\n\t\treturn this.emitter.event;\n\t}\n\n\t[Symbol.dispose](): void {\n\t\tthis.dispose();\n\t}\n\n\tdispose(): void {\n\t\tif (this.disposed) return;\n\n\t\tthis.disposed = true;\n\t\tif (this.timing != null) {\n\t\t\tfor (const d of this.timing) {\n\t\t\t\td.dispose();\n\t\t\t}\n\t\t\tthis.timing = undefined;\n\t\t}\n\t\tthis.emitter.dispose();\n\t\tthis.onDispose(this);\n\t}\n\n\tattach(session: RepositoryWatchSession): void {\n\t\tif (this.disposed || this.timing != null) return;\n\n\t\tthis.timing = [\n\t\t\tsession.subscribe({ delayMs: this.options?.delayMs, maxWaitMs: this.options?.maxWaitMs }),\n\t\t\tsession.subscribeToWorkingTree({\n\t\t\t\tdelayMs: this.options?.workingTreeDelayMs,\n\t\t\t\tmaxWaitMs: this.options?.workingTreeMaxWaitMs,\n\t\t\t}),\n\t\t];\n\t}\n\n\tfire(summary: WorktreeSummary): void {\n\t\tthis.emitter.fire(summary);\n\t}\n}\n\n/**\n * A cached, change-notifying summary of each subscribed worktree — its branch, upstream and ahead/behind, whether it\n * has working changes, and how far it is past its base — kept current by the repository watch layer.\n *\n * **Lifecycle.** Entries are per repository key and ref-counted across {@link subscribe} calls. The first subscriber\n * starts watching the worktree and reads everything; the last one to leave aborts any in-flight read, releases the\n * watch and drops the value. Each subscriber's timing options join the watch session's cadence (the shortest wins);\n * the service's own listening subscriptions never constrain it.\n *\n * **Field-scoped recompute.** The summary is read in three groups — `dirty` (working changes), `branch` (branch,\n * HEAD's commit, upstream, ahead/behind) and `base` (ahead of base, the base's tip, and the refs it depends on) — and\n * an event recomputes only the groups it can affect: a working-tree edit, an index or ignore-rule change reads only\n * `dirty`; the upstream moving reads only `branch`; a ref the base depends on reads only `base`, and when the refs that\n * moved are named and include the base's own ref, as a fetch names them, the provider first tries re-measuring the\n * base from the previous one (one count per worktree when it only moved forward); a `gk` config change\n * (mostly bookkeeping writes to the shared `.git/gk/config`), or core's own write of the branch's merge target or\n * base, re-reads the branch's stored merge targets and recorded base, and reads `base` only when one of them changed;\n * a `.git/config` change reads `branch` and the provider's config inputs to the base (one cached read shared by the\n * repository's checkouts, or one per checkout where config can differ by checkout), and reads `base` only when the\n * inputs its last base read consulted (every branch's tracking but those of branches it didn't depend on), the stored\n * values, HEAD's commit or the upstream changed, unless it was confined to the\n * `branch.<name>` sections of branches the summary neither is on, tracks nor bases on (its `configBranches`), which\n * reads nothing; the checked-out branch moving, or a HEAD change, reads all of them. Stash, unrelated tags and\n * branches, and the like read nothing. One run is in flight per worktree at a time, at most four per repository (the\n * worktrees sharing a common git directory), and at most eight across the service. Runs take turns first come, first\n * served, except that one whose repository is at its cap lets later runs of other repositories go first, so a burst in\n * one repository never delays another's reads: events while a run waits for its turn join it, and events during a run\n * are merged into a single follow-up run.\n *\n * **Value-change-only notification.** {@link WorktreeSummarySubscription.onDidChange} and {@link onDidChangeSummary}\n * fire only when some field's value differs from the previous summary — a recompute that reads the same answer is\n * silent, so a consumer can re-render on every event without diffing. A failed recompute keeps the last values and\n * sets `stale` (firing once); the next successful one clears it.\n */\nexport class WorktreeSummaryService implements UnifiedDisposable {\n\tprivate readonly _onDidChangeSummary = new Emitter<WorktreeSummary>();\n\t/** Fires when the summary of any subscribed worktree changes value */\n\tget onDidChangeSummary(): Event<WorktreeSummary> {\n\t\treturn this._onDidChangeSummary.event;\n\t}\n\n\tprivate readonly entries = new Map<string, SummaryEntry>();\n\t/** Reads running for each repository, by its slots key; a repository with none has no entry */\n\tprivate readonly activeReadsByRepository = new Map<string, number>();\n\tprivate activeReads = 0;\n\t/** Entries waiting for a read slot, oldest first */\n\tprivate readonly readWaiters = new Map<SummaryEntry, (acquired: boolean) => void>();\n\tprivate readonly watchService: RepositoryWatchService;\n\tprivate readonly getRepository: (repoPath: string) => RepositoryService | undefined;\n\tprivate readonly getCommonPath: ((repoPath: string) => string | undefined) | undefined;\n\tprivate readonly verifyBaseRemeasure: WorktreeSummaryServiceOptions['verifyBaseRemeasure'];\n\tprivate readonly mergeTargetsListener: UnifiedDisposable | undefined;\n\tprivate _disposed = false;\n\n\tconstructor(options: WorktreeSummaryServiceOptions) {\n\t\tthis.watchService = options.watchService;\n\t\tthis.getRepository = options.getRepository;\n\t\tthis.getCommonPath = options.getCommonPath;\n\t\tthis.verifyBaseRemeasure = options.verifyBaseRemeasure;\n\t\tthis.mergeTargetsListener = options.onDidChangeMergeTargets?.(e => this.onMergeTargetsChanged(e));\n\t}\n\n\t[Symbol.dispose](): void {\n\t\tthis.dispose();\n\t}\n\n\tdispose(): void {\n\t\tif (this._disposed) return;\n\n\t\tthis._disposed = true;\n\t\tfor (const resolve of this.readWaiters.values()) {\n\t\t\tresolve(false);\n\t\t}\n\t\tthis.readWaiters.clear();\n\t\tthis.mergeTargetsListener?.dispose();\n\t\tfor (const entry of [...this.entries.values()]) {\n\t\t\tfor (const subscription of [...entry.subscribers]) {\n\t\t\t\tsubscription.dispose();\n\t\t\t}\n\t\t}\n\t\tthis.entries.clear();\n\t\tthis._onDidChangeSummary.dispose();\n\t}\n\n\t/** Subscribes to a worktree's summary, starting to watch and read it if this is its first subscriber */\n\tsubscribe(repoPath: string, options?: WorktreeSummarySubscribeOptions): WorktreeSummarySubscription {\n\t\tconst key = getRepositoryKey(repoPath);\n\n\t\tlet entry = this._disposed ? undefined : this.entries.get(key);\n\t\tconst isNew = entry == null;\n\t\tif (entry == null) {\n\t\t\tentry = createEntry(key);\n\t\t\tif (this._disposed) {\n\t\t\t\tentry.disposed = true;\n\t\t\t} else {\n\t\t\t\tthis.entries.set(key, entry);\n\t\t\t}\n\t\t}\n\n\t\tconst target = entry;\n\t\tconst subscription = new SummarySubscription(target, options, s => this.release(target, s));\n\t\ttarget.subscribers.add(subscription);\n\n\t\tif (isNew) {\n\t\t\tif (!target.disposed) {\n\t\t\t\ttarget.pending = allFields | baseConfigField;\n\t\t\t\ttarget.running = this.start(target);\n\t\t\t}\n\t\t} else if (target.handle != null) {\n\t\t\tsubscription.attach(target.handle.session);\n\t\t} else if (target.running == null && !target.disposed) {\n\t\t\t// The start failed (no repository or git directory yet); a new subscriber retries it\n\t\t\ttarget.pending = allFields | baseConfigField;\n\t\t\ttarget.running = this.start(target);\n\t\t}\n\n\t\treturn subscription;\n\t}\n\n\t/**\n\t * Returns a worktree's summary. For a subscribed worktree, the cached value — after waiting for any run in flight\n\t * or pending; it rejects with the read's error when there is still no value. Otherwise a one-off full read that\n\t * is neither cached nor watched.\n\t */\n\tasync getSummary(repoPath: string, cancellation?: AbortSignal): Promise<WorktreeSummary> {\n\t\tconst key = getRepositoryKey(repoPath);\n\t\tconst entry = this.entries.get(key);\n\t\tif (entry == null) {\n\t\t\tconst repo = this.getRepository(key);\n\t\t\tif (repo == null) throw new Error(`No repository found for '${key}'`);\n\n\t\t\tconst result = await readSummary(\n\t\t\t\trepo,\n\t\t\t\tkey,\n\t\t\t\tallFields,\n\t\t\t\tundefined,\n\t\t\t\tundefined,\n\t\t\t\tundefined,\n\t\t\t\tundefined,\n\t\t\t\tundefined,\n\t\t\t\tcancellation,\n\t\t\t\tthis.verifyBaseRemeasure,\n\t\t\t);\n\t\t\treturn result.summary;\n\t\t}\n\n\t\tif (entry.running != null) {\n\t\t\tawait (cancellation != null ? raceWithSignal(entry.running, cancellation) : entry.running);\n\t\t}\n\t\tif (entry.disposed) throw new CancellationError();\n\t\tif (entry.value != null) return entry.value;\n\n\t\tthrow entry.error ?? new Error(`No summary available for '${key}'`);\n\t}\n\n\tgetResourceUsage(): ResourceUsage {\n\t\treturn { 'worktreeSummary.entries.count': this.entries.size };\n\t}\n\n\tprivate async start(entry: SummaryEntry): Promise<void> {\n\t\tlet gitDir: GitDir | undefined;\n\t\ttry {\n\t\t\tgitDir = await this.getRepository(entry.key)?.config.getGitDir?.();\n\t\t} catch (ex) {\n\t\t\tif (entry.disposed) return;\n\n\t\t\tentry.running = undefined;\n\t\t\tif (!isCancellationError(ex)) {\n\t\t\t\tthis.fail(entry, ex);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (entry.disposed) return;\n\n\t\tconst handle = gitDir != null ? this.watchService.watch(entry.key, gitDir) : undefined;\n\t\tif (gitDir == null || handle == null) {\n\t\t\tentry.running = undefined;\n\t\t\tthis.fail(entry, new Error(`Unable to watch '${entry.key}': no repository or git directory`));\n\t\t\treturn;\n\t\t}\n\n\t\tentry.handle = handle;\n\t\tentry.slotsKey = getRepositoryKey(gitDir.commonUri ?? gitDir.uri);\n\t\tconst session = handle.session;\n\t\t// Timing-neutral: the cadence comes from the subscribers' own session subscriptions (see `attach`)\n\t\tconst repoSub = session.subscribe({ delayMs: Infinity, maxWaitMs: Infinity });\n\t\tconst workingTreeSub = session.subscribeToWorkingTree({ delayMs: Infinity, maxWaitMs: Infinity });\n\t\tentry.listeners = [\n\t\t\trepoSub.onDidChange(e => this.onRepoChanged(entry, e)),\n\t\t\tworkingTreeSub.onDidChangeWorkingTree(() => this.queue(entry, dirtyField)),\n\t\t\trepoSub,\n\t\t\tworkingTreeSub,\n\t\t];\n\t\tfor (const subscription of entry.subscribers) {\n\t\t\tsubscription.attach(session);\n\t\t}\n\n\t\tawait this.drain(entry);\n\t}\n\n\tprivate onRepoChanged(entry: SummaryEntry, e: WatcherRepoChangeEvent): void {\n\t\tconst value = entry.value;\n\t\tif (value == null || e.changed('unknown', 'head')) {\n\t\t\tthis.queue(entry, allFields | (e.changed('config') ? baseConfigField : 0));\n\t\t\treturn;\n\t\t}\n\n\t\tlet fields = 0;\n\t\tif (e.changed('index', 'ignores')) {\n\t\t\tfields |= dirtyField;\n\t\t}\n\t\tif (e.changed('config') && e.mayHaveChangedConfig(getConfigRelevantRefs(value))) {\n\t\t\tfields |= branchField | baseKeysField | baseConfigField;\n\t\t}\n\t\tif (e.changed('gkConfig')) {\n\t\t\tfields |= baseKeysField;\n\t\t}\n\t\tif (value.branch != null && e.mayHaveChangedRef(`refs/heads/${value.branch}`)) {\n\t\t\tfields |= allFields;\n\t\t}\n\t\t// The upstream's short name doesn't say whether it's remote or local (`--track main`), so test both forms\n\t\tif (\n\t\t\tvalue.upstream != null &&\n\t\t\t(e.mayHaveChangedRef(`refs/remotes/${value.upstream.name}`) ||\n\t\t\t\te.mayHaveChangedRef(`refs/heads/${value.upstream.name}`))\n\t\t) {\n\t\t\tfields |= branchField;\n\t\t}\n\t\tlet baseMoves: string[] | undefined;\n\t\tif ((fields & baseField) === 0) {\n\t\t\tfor (const ref of value.baseDependsOn) {\n\t\t\t\tif (!e.mayHaveChangedRef(ref)) continue;\n\n\t\t\t\t// Only a ref named exactly is known to be the one that moved: a ref directory or a ref kind that changed\n\t\t\t\t// without names (a packed-refs rewrite, an overflow, a poll) may hide any move\n\t\t\t\tconst kind = getRefChangeKind(ref);\n\t\t\t\tif (!e.refs.has(ref) || kind == null || e.unnamedRefKinds.has(kind)) {\n\t\t\t\t\tfields |= baseField;\n\t\t\t\t\tbaseMoves = undefined;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tbaseMoves ??= [];\n\t\t\t\tbaseMoves.push(ref);\n\t\t\t}\n\t\t\tif (baseMoves != null) {\n\t\t\t\tfields |= baseMoveField;\n\t\t\t}\n\t\t}\n\n\t\tthis.queue(entry, fields, baseMoves);\n\t}\n\n\t/**\n\t * Queued synchronously, so a store awaited before `getSummary` finds the run in flight. The watcher's later\n\t * `gkConfig` event for the same write then finds the keys unchanged and leaves the base alone.\n\t */\n\tprivate onMergeTargetsChanged(e: MergeTargetsChangeEvent): void {\n\t\tfor (const entry of this.entries.values()) {\n\t\t\t// Before the watch starts there's nothing to refresh: the start's own read comes after the write\n\t\t\tif (entry.handle == null) continue;\n\n\t\t\t// With no value yet, the first read may have read the stored values before the write, so `queue` reads\n\t\t\t// everything again\n\t\t\tconst value = entry.value;\n\t\t\tif (value != null && (value.branch == null || (e.refs != null && !e.refs.has(value.branch)))) continue;\n\n\t\t\tconst commonPath = this.getCommonPath?.(entry.key);\n\t\t\tif (commonPath != null && commonPath !== e.repoPath) continue;\n\n\t\t\tthis.queue(entry, baseKeysField);\n\t\t}\n\t}\n\n\tprivate queue(entry: SummaryEntry, fields: number, baseMoves?: readonly string[]): void {\n\t\tif (entry.disposed || fields === 0) return;\n\n\t\t// Without a value a partial read has nothing to merge into, and a stale value's fields can't be trusted: a\n\t\t// partial read would clear `stale` while vouching for groups it never re-read\n\t\tentry.pending |= entry.value == null || entry.value.stale ? fields | allFields | baseConfigField : fields;\n\t\tif (baseMoves != null) {\n\t\t\tentry.baseMoves ??= new Set();\n\t\t\tfor (const ref of baseMoves) {\n\t\t\t\tentry.baseMoves.add(ref);\n\t\t\t}\n\t\t}\n\t\tentry.running ??= this.drain(entry);\n\t}\n\n\t/** Runs until nothing is pending. Never rejects — every failure becomes entry state. */\n\tprivate async drain(entry: SummaryEntry): Promise<void> {\n\t\twhile (entry.pending !== 0 && !entry.disposed) {\n\t\t\tif (!(await this.acquireRead(entry))) break;\n\n\t\t\ttry {\n\t\t\t\tif (entry.disposed) break;\n\n\t\t\t\t// Consume after acquiring: changes that arrived while queued belong to this same read.\n\t\t\t\tconst fields = entry.pending;\n\t\t\t\tconst baseMoves = entry.baseMoves;\n\t\t\t\tentry.pending = 0;\n\t\t\t\tentry.baseMoves = undefined;\n\t\t\t\tawait this.run(entry, fields, baseMoves);\n\t\t\t} finally {\n\t\t\t\tthis.releaseRead(entry);\n\t\t\t}\n\t\t}\n\t\t// Same turn as the loop's last check, so an event can't queue fields that no run will pick up\n\t\tentry.running = undefined;\n\t}\n\n\t/**\n\t * A read takes one of its repository's slots and one of the service's. Each release hands what it frees to the\n\t * waiters first, so a new read takes a slot only when no waiter can use it.\n\t */\n\tprivate acquireRead(entry: SummaryEntry): Promise<boolean> {\n\t\tif (entry.disposed || this._disposed) return Promise.resolve(false);\n\n\t\tif (this.tryTakeReadSlots(entry)) return Promise.resolve(true);\n\n\t\treturn new Promise(resolve => this.readWaiters.set(entry, resolve));\n\t}\n\n\tprivate releaseRead(entry: SummaryEntry): void {\n\t\tconst key = entry.slotsKey ?? entry.key;\n\t\tconst active = this.activeReadsByRepository.get(key);\n\t\tif (active == null) return;\n\n\t\tif (active > 1) {\n\t\t\tthis.activeReadsByRepository.set(key, active - 1);\n\t\t} else {\n\t\t\tthis.activeReadsByRepository.delete(key);\n\t\t}\n\t\tthis.activeReads--;\n\n\t\t// The oldest waiter whose repository has a free slot goes next, so a repository at its own cap never holds up\n\t\t// another's waiters, and a busy checkout rejoins the tail for a follow-up rather than starving its siblings\n\t\tfor (const [waiter, resolve] of this.readWaiters) {\n\t\t\tif (this.activeReads >= maxConcurrentReads) break;\n\n\t\t\tif (waiter.disposed || this._disposed) {\n\t\t\t\tthis.readWaiters.delete(waiter);\n\t\t\t\tresolve(false);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (!this.tryTakeReadSlots(waiter)) continue;\n\n\t\t\tthis.readWaiters.delete(waiter);\n\t\t\tresolve(true);\n\t\t}\n\t}\n\n\tprivate tryTakeReadSlots(entry: SummaryEntry): boolean {\n\t\tif (this.activeReads >= maxConcurrentReads) return false;\n\n\t\tconst key = entry.slotsKey ?? entry.key;\n\t\tconst active = this.activeReadsByRepository.get(key) ?? 0;\n\t\tif (active >= maxConcurrentReadsPerRepository) return false;\n\n\t\tthis.activeReadsByRepository.set(key, active + 1);\n\t\tthis.activeReads++;\n\t\treturn true;\n\t}\n\n\tprivate async run(entry: SummaryEntry, fields: number, baseMoves: ReadonlySet<string> | undefined): Promise<void> {\n\t\tconst previous = entry.value;\n\n\t\tlet result: ReadResult;\n\t\ttry {\n\t\t\tconst repo = this.getRepository(entry.key);\n\t\t\tif (repo == null) throw new Error(`No repository found for '${entry.key}'`);\n\n\t\t\tresult = await readSummary(\n\t\t\t\trepo,\n\t\t\t\tentry.key,\n\t\t\t\tfields,\n\t\t\t\tprevious,\n\t\t\t\tentry.baseKeys,\n\t\t\t\tentry.baseConfigKey,\n\t\t\t\tentry.baseDefaultBranch,\n\t\t\t\tbaseMoves,\n\t\t\t\tentry.abort.signal,\n\t\t\t\tthis.verifyBaseRemeasure,\n\t\t\t);\n\t\t} catch (ex) {\n\t\t\tif (entry.disposed || isCancellationError(ex)) return;\n\n\t\t\tthis.fail(entry, ex);\n\t\t\treturn;\n\t\t}\n\t\tif (entry.disposed) return;\n\n\t\tif (result.summary.stale && (previous == null || !previous.stale)) {\n\t\t\tLogger.warn(\n\t\t\t\t`WorktreeSummaryService: reading the base of '${entry.key}' failed: ${String(result.baseError)}`,\n\t\t\t);\n\t\t}\n\n\t\tentry.error = undefined;\n\t\tentry.baseKeys = result.baseKeys;\n\t\tentry.baseConfigKey = entry.pending & baseConfigField ? undefined : result.baseConfigKey;\n\t\tentry.baseDefaultBranch = result.baseDefaultBranch;\n\t\tif (previous != null && summariesEqual(previous, result.summary)) return;\n\n\t\tentry.value = result.summary;\n\t\tthis.fireChange(entry, result.summary);\n\t}\n\n\tprivate fail(entry: SummaryEntry, ex: unknown): void {\n\t\tconst previous = entry.value;\n\t\tif (previous == null) {\n\t\t\tif (entry.error == null) {\n\t\t\t\tLogger.warn(`WorktreeSummaryService: reading '${entry.key}' failed: ${String(ex)}`);\n\t\t\t}\n\t\t\tentry.error = ex instanceof Error ? ex : new Error(String(ex));\n\t\t\treturn;\n\t\t}\n\t\tif (previous.stale) return;\n\n\t\tLogger.warn(`WorktreeSummaryService: refreshing '${entry.key}' failed: ${String(ex)}`);\n\t\tconst summary: WorktreeSummary = { ...previous, stale: true };\n\t\tentry.value = summary;\n\t\tthis.fireChange(entry, summary);\n\t}\n\n\tprivate fireChange(entry: SummaryEntry, summary: WorktreeSummary): void {\n\t\tfor (const subscription of entry.subscribers) {\n\t\t\tsubscription.fire(summary);\n\t\t}\n\t\tthis._onDidChangeSummary.fire(summary);\n\t}\n\n\tprivate release(entry: SummaryEntry, subscription: SummarySubscription): void {\n\t\tentry.subscribers.delete(subscription);\n\t\tif (entry.subscribers.size !== 0) return;\n\n\t\tentry.disposed = true;\n\t\t// A waiter holds no slot, so dropping it frees none\n\t\tconst cancelRead = this.readWaiters.get(entry);\n\t\tif (cancelRead != null) {\n\t\t\tthis.readWaiters.delete(entry);\n\t\t\tcancelRead(false);\n\t\t}\n\t\tentry.abort.abort();\n\t\tif (entry.listeners != null) {\n\t\t\tfor (const d of entry.listeners) {\n\t\t\t\td.dispose();\n\t\t\t}\n\t\t\tentry.listeners = undefined;\n\t\t}\n\t\tentry.handle?.dispose();\n\t\tentry.handle = undefined;\n\t\tentry.value = undefined;\n\t\tentry.baseKeys = undefined;\n\t\tentry.baseConfigKey = undefined;\n\t\tentry.baseDefaultBranch = undefined;\n\t\tentry.pending = 0;\n\t\tentry.baseMoves = undefined;\n\t\tentry.running = undefined;\n\n\t\tif (this.entries.get(entry.key) === entry) {\n\t\t\tthis.entries.delete(entry.key);\n\t\t}\n\t}\n}\n\n/**\n * The local branches whose config sections a summary reads: its branch's (upstream and base keys), and those of the\n * branches it tracks or bases on. The upstream's short name doesn't say whether it's local, so it counts as local too.\n */\nfunction* getConfigRelevantRefs(value: WorktreeSummary): Iterable<string> {\n\tif (value.branch != null) {\n\t\tyield `refs/heads/${value.branch}`;\n\t}\n\tif (value.upstream != null) {\n\t\tyield `refs/heads/${value.upstream.name}`;\n\t}\n\tyield* value.baseDependsOn;\n}\n\nfunction createEntry(key: string): SummaryEntry {\n\treturn {\n\t\tkey: key,\n\t\tslotsKey: undefined,\n\t\tabort: new AbortController(),\n\t\tsubscribers: new Set(),\n\t\thandle: undefined,\n\t\tlisteners: undefined,\n\t\tvalue: undefined,\n\t\tbaseKeys: undefined,\n\t\tbaseConfigKey: undefined,\n\t\tbaseDefaultBranch: undefined,\n\t\terror: undefined,\n\t\tpending: 0,\n\t\tbaseMoves: undefined,\n\t\trunning: undefined,\n\t\tdisposed: false,\n\t};\n}\n\n/**\n * Reads the due groups and fills the rest from `previous` (every group when there is none). The branch read comes\n * before the base read, which needs its name; the dirty read runs alongside both. A branch read that finds a\n * different branch (or detached state) also reads the base and dirty groups, and stored base values that differ\n * from `previousBaseKeys` read the base group. A base due only because `baseMoves` moved, with HEAD, the stored\n * values and the config inputs as before, is first re-measured from `previous` and the default branch its read\n * resolved, `previousBaseDefaultBranch` (see `getAheadOfBaseAfterBaseMove`), and read in full only when that can't\n * answer. A failed base read doesn't fail the rest: the summary comes back stale, keeping the previous\n * base and `baseDependsOn` only while the branch is the same.\n */\nasync function readSummary(\n\trepo: RepositoryService,\n\tkey: string,\n\tfields: number,\n\tprevious: WorktreeSummary | undefined,\n\tpreviousBaseKeys: BaseKeys | undefined,\n\tpreviousBaseConfigKey: string | undefined,\n\tpreviousBaseDefaultBranch: string | null | undefined,\n\tbaseMoves: ReadonlySet<string> | undefined,\n\tsignal: AbortSignal | undefined,\n\tverifyBaseRemeasure: WorktreeSummaryServiceOptions['verifyBaseRemeasure'],\n): Promise<ReadResult> {\n\tif (previous == null) {\n\t\tfields |= allFields;\n\t}\n\n\tlet dirtyRead = fields & dirtyField ? readDirty(repo, signal) : undefined;\n\n\tlet branch = previous?.branch;\n\tlet detached = previous?.detached ?? false;\n\tlet sha = previous?.sha;\n\tlet upstream = previous?.upstream;\n\tlet ahead = previous?.ahead ?? 0;\n\tlet behind = previous?.behind ?? 0;\n\tif (fields & branchField) {\n\t\tconst current = await repo.branches.getBranch(undefined, undefined, signal);\n\t\tdetached = current?.detached ?? false;\n\t\tbranch = detached ? undefined : current?.name || undefined;\n\t\tsha = current?.sha;\n\t\tupstream = current?.upstream != null ? await toSummaryUpstream(repo, current.upstream, signal) : undefined;\n\t\tahead = current?.upstream?.state.ahead ?? 0;\n\t\tbehind = current?.upstream?.state.behind ?? 0;\n\n\t\tif (previous != null && (branch !== previous.branch || detached !== previous.detached)) {\n\t\t\tfields |= baseField;\n\t\t\tdirtyRead ??= readDirty(repo, signal);\n\t\t}\n\t}\n\n\tlet base = previous?.base;\n\tlet dependsOn = previous?.baseDependsOn ?? emptyRefs;\n\tlet baseKeys = previousBaseKeys;\n\tlet baseKeysRead = false;\n\tlet baseConfigKey = previousBaseConfigKey;\n\tlet baseConfig: BaseConfig | undefined;\n\tlet baseConfigRead = false;\n\tlet baseDefaultBranch = previousBaseDefaultBranch;\n\tlet baseFailed = false;\n\tlet baseError: unknown;\n\t// A detached HEAD is measured as `undefined`; an unborn HEAD with no name has nothing to measure\n\tconst baseReadable = repo.branches.getAheadOfBase != null && (detached || branch != null);\n\tif (fields & baseConfigField && !(fields & baseField) && baseReadable) {\n\t\tbaseConfig = await readBaseConfig(repo, signal);\n\t\tbaseConfigRead = true;\n\t\t// Without a base read due, the branch and upstream are as before, so the inputs to compare are the ones the last\n\t\t// base read consulted\n\t\tconst key = previous != null ? getBaseConfigKey(baseConfig, previous) : undefined;\n\t\tif (\n\t\t\tkey == null ||\n\t\t\tkey !== previousBaseConfigKey ||\n\t\t\tsha !== previous?.sha ||\n\t\t\t!upstreamsEqual(upstream, previous?.upstream)\n\t\t) {\n\t\t\tfields |= baseField;\n\t\t}\n\t}\n\tif (fields & baseKeysField && !(fields & baseField) && baseReadable) {\n\t\tbaseKeys = await readBaseKeys(repo, branch);\n\t\tbaseKeysRead = true;\n\t\tif (baseKeys == null || previousBaseKeys == null || !baseKeysEqual(baseKeys, previousBaseKeys)) {\n\t\t\tfields |= baseField;\n\t\t}\n\t}\n\tif (fields & (baseField | baseMoveField)) {\n\t\tif (!baseReadable) {\n\t\t\tbase = undefined;\n\t\t\tdependsOn = emptyRefs;\n\t\t\tbaseKeys = undefined;\n\t\t\tbaseConfigKey = undefined;\n\t\t\tbaseDefaultBranch = undefined;\n\t\t} else {\n\t\t\t// Snapshot before the base read, so a write it misses is one the next `gk` config event sees as a change\n\t\t\tif (!baseKeysRead) {\n\t\t\t\tbaseKeys = await readBaseKeys(repo, branch);\n\t\t\t}\n\t\t\tif (!baseConfigRead && (previous != null || (fields & baseConfigField) !== 0)) {\n\t\t\t\tbaseConfig = await readBaseConfig(repo, signal);\n\t\t\t\tbaseConfigRead = true;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tlet aheadOfBase: AheadOfBase | undefined;\n\t\t\t\t// The config inputs too, though no config change is due: a write can land between the last read and its\n\t\t\t\t// event (core evicts its own write's caches before the event fires), and the re-measure reads no config,\n\t\t\t\t// so the key kept with it would vouch for config the base never saw\n\t\t\t\tif (\n\t\t\t\t\t!(fields & baseField) &&\n\t\t\t\t\tbaseMoves != null &&\n\t\t\t\t\tbaseMoves.size !== 0 &&\n\t\t\t\t\tprevious?.base != null &&\n\t\t\t\t\tsha != null &&\n\t\t\t\t\tsha === previous.sha &&\n\t\t\t\t\tbaseKeys != null &&\n\t\t\t\t\tpreviousBaseKeys != null &&\n\t\t\t\t\tbaseKeysEqual(baseKeys, previousBaseKeys) &&\n\t\t\t\t\tgetBaseConfigKey(baseConfig, previous) === previousBaseConfigKey\n\t\t\t\t) {\n\t\t\t\t\taheadOfBase = await repo.branches.getAheadOfBaseAfterBaseMove?.(\n\t\t\t\t\t\tbranch,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\thead: sha,\n\t\t\t\t\t\t\tbase: previous.base,\n\t\t\t\t\t\t\tdependsOn: previous.baseDependsOn,\n\t\t\t\t\t\t\t...(previousBaseDefaultBranch !== undefined\n\t\t\t\t\t\t\t\t? { defaultBranch: previousBaseDefaultBranch }\n\t\t\t\t\t\t\t\t: undefined),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t[...baseMoves],\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t);\n\t\t\t\t\tif (aheadOfBase != null && verifyBaseRemeasure != null) {\n\t\t\t\t\t\tlet full: AheadOfBase | undefined;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tfull = await repo.branches.getAheadOfBase?.(branch, undefined, signal);\n\t\t\t\t\t\t} catch (ex) {\n\t\t\t\t\t\t\tif (isCancellationError(ex)) throw ex;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tverifyBaseRemeasure(aheadOfBase, full);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\taheadOfBase ??= await repo.branches.getAheadOfBase?.(branch, undefined, signal);\n\t\t\t\tbase = aheadOfBase?.base;\n\t\t\t\tdependsOn = aheadOfBase?.dependsOn ?? emptyRefs;\n\t\t\t\tbaseDefaultBranch = aheadOfBase?.defaultBranch;\n\t\t\t} catch (ex) {\n\t\t\t\tif (isCancellationError(ex)) throw ex;\n\n\t\t\t\tbaseFailed = true;\n\t\t\t\tbaseError = ex;\n\t\t\t\t// Keep `baseDependsOn` for the same branch: a fetch moving one of its refs is what retries the base\n\t\t\t\tconst sameBranch = previous != null && branch === previous.branch && detached === previous.detached;\n\t\t\t\tbase = sameBranch ? previous.base : undefined;\n\t\t\t\tdependsOn = sameBranch ? previous.baseDependsOn : emptyRefs;\n\t\t\t\tbaseKeys = undefined;\n\t\t\t\tbaseConfigRead = false;\n\t\t\t\tbaseConfigKey = undefined;\n\t\t\t\tbaseDefaultBranch = undefined;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst dirty = dirtyRead != null ? await dirtyRead : (previous?.dirty ?? false);\n\n\tconst summary: WorktreeSummary = {\n\t\trepoPath: key,\n\t\tbranch: branch,\n\t\tdetached: detached,\n\t\tsha: sha,\n\t\tupstream: upstream,\n\t\tahead: ahead,\n\t\tbehind: behind,\n\t\tdirty: dirty,\n\t\tbase: base,\n\t\tbaseDependsOn: dependsOn,\n\t\tstale: baseFailed,\n\t};\n\t// Keyed on what this run's base read (or the one it kept) consulted, from the inputs read before it\n\tif (baseConfigRead) {\n\t\tbaseConfigKey = getBaseConfigKey(baseConfig, summary);\n\t}\n\n\treturn {\n\t\tsummary: summary,\n\t\tbaseKeys: baseKeys,\n\t\tbaseConfigKey: baseConfigKey,\n\t\tbaseDefaultBranch: baseDefaultBranch,\n\t\tbaseError: baseError,\n\t};\n}\n\nasync function readBaseConfig(\n\trepo: RepositoryService,\n\tsignal: AbortSignal | undefined,\n): Promise<BaseConfig | undefined> {\n\ttry {\n\t\tif (repo.branches.getAheadOfBaseConfigEntries != null) {\n\t\t\treturn await repo.branches.getAheadOfBaseConfigEntries(signal);\n\t\t}\n\t\treturn await repo.branches.getAheadOfBaseConfigKey?.(signal);\n\t} catch (ex) {\n\t\tif (isCancellationError(ex)) throw ex;\n\n\t\treturn undefined;\n\t}\n}\n\n/**\n * The key of the config inputs a base read for `value` consulted: every entry except the `branch.<name>` ones of local\n * branches outside its {@link getConfigRelevantRefs}, which the read never resolved. So a write to another branch's\n * section, confined (which wakes no summary but changes the inputs) or not, leaves the base alone. An opaque key is\n * taken whole.\n */\nfunction getBaseConfigKey(config: BaseConfig | undefined, value: WorktreeSummary): string | undefined {\n\tif (config == null || typeof config === 'string') return config;\n\n\tconst branches = new Set<string>();\n\tfor (const ref of getConfigRelevantRefs(value)) {\n\t\tif (ref.startsWith('refs/heads/')) {\n\t\t\tbranches.add(ref.substring('refs/heads/'.length));\n\t\t}\n\t}\n\n\tlet key = '';\n\tfor (const [name, entry] of config) {\n\t\t// The subsection is everything between the first and last dot, so a branch name can hold dots\n\t\tconst last = name.lastIndexOf('.');\n\t\tif (\n\t\t\tname.startsWith('branch.') &&\n\t\t\tlast > 'branch.'.length &&\n\t\t\t!branches.has(name.substring('branch.'.length, last))\n\t\t) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tkey += entry != null ? `${name}\\n${entry}\\0` : `${name}\\0`;\n\t}\n\treturn key;\n}\n\n/**\n * Reads {@link BaseKeys} for `branch`, normalized the way `getAheadOfBase` reads them. `undefined` when any read\n * failed — an unknown snapshot, so the next `gk` config change reads the base rather than trusting it. A detached\n * HEAD (`branch` undefined) has no stored values to read.\n */\nasync function readBaseKeys(repo: RepositoryService, branch: string | undefined): Promise<BaseKeys | undefined> {\n\tif (branch == null) return noBaseKeys;\n\n\ttry {\n\t\tconst [user, detected, recorded] = await Promise.all([\n\t\t\trepo.branches.getStoredUserMergeTargetBranchName?.(branch),\n\t\t\trepo.branches.getStoredDetectedMergeTargetBranchName?.(branch),\n\t\t\trepo.config.getGkConfig?.(`branch.${branch}.gk-merge-base`),\n\t\t]);\n\t\treturn [user?.trim() || undefined, detected?.trim() || undefined, recorded?.trim() || undefined];\n\t} catch (ex) {\n\t\tif (isCancellationError(ex)) throw ex;\n\n\t\treturn undefined;\n\t}\n}\n\nfunction baseKeysEqual(a: BaseKeys, b: BaseKeys): boolean {\n\treturn a[0] === b[0] && a[1] === b[1] && a[2] === b[2];\n}\n\nfunction readDirty(repo: RepositoryService, signal: AbortSignal | undefined): Promise<boolean> {\n\tconst read = repo.status.hasWorkingChanges({ untracked: true }, signal);\n\t// Awaited only after the branch and base reads; if one of those throws first, this rejection has no other handler\n\tread.catch(noop);\n\treturn read;\n}\n\nfunction noop(): void {}\n\n/**\n * Uses the remote and branch git reported for the upstream; only when it reported neither does this split the name\n * at the longest remote name it starts with (no split when none matches or nothing follows it)\n */\nasync function toSummaryUpstream(\n\trepo: RepositoryService,\n\tupstream: GitTrackingUpstream,\n\tsignal: AbortSignal | undefined,\n): Promise<WorktreeSummaryUpstream> {\n\tconst { name, missing } = upstream;\n\n\tif (upstream.local) return { name: name, remote: undefined, branch: undefined, missing: missing };\n\n\tif (upstream.remote) {\n\t\tconst { remote } = upstream;\n\t\tconst branch =\n\t\t\tupstream.remoteBranch || (name.startsWith(`${remote}/`) ? name.substring(remote.length + 1) : undefined);\n\t\treturn { name: name, remote: branch ? remote : undefined, branch: branch || undefined, missing: missing };\n\t}\n\n\tlet remote: string | undefined;\n\tfor (const r of await repo.remotes.getRemotes(undefined, signal)) {\n\t\tif (r.name && name.startsWith(`${r.name}/`) && (remote == null || r.name.length > remote.length)) {\n\t\t\tremote = r.name;\n\t\t}\n\t}\n\n\tconst branch = remote != null ? name.substring(remote.length + 1) : undefined;\n\treturn {\n\t\tname: name,\n\t\tremote: branch ? remote : undefined,\n\t\tbranch: branch || undefined,\n\t\tmissing: missing,\n\t};\n}\n\nfunction upstreamsEqual(a: WorktreeSummaryUpstream | undefined, b: WorktreeSummaryUpstream | undefined): boolean {\n\treturn (\n\t\ta === b ||\n\t\t(a != null &&\n\t\t\tb != null &&\n\t\t\ta.name === b.name &&\n\t\t\ta.remote === b.remote &&\n\t\t\ta.branch === b.branch &&\n\t\t\ta.missing === b.missing)\n\t);\n}\n\nfunction summariesEqual(a: WorktreeSummary, b: WorktreeSummary): boolean {\n\treturn (\n\t\ta.repoPath === b.repoPath &&\n\t\ta.branch === b.branch &&\n\t\ta.detached === b.detached &&\n\t\ta.sha === b.sha &&\n\t\ta.ahead === b.ahead &&\n\t\ta.behind === b.behind &&\n\t\ta.dirty === b.dirty &&\n\t\ta.stale === b.stale &&\n\t\tareEqual(a.baseDependsOn, b.baseDependsOn) &&\n\t\tupstreamsEqual(a.upstream, b.upstream) &&\n\t\t(a.base === b.base ||\n\t\t\t(a.base != null &&\n\t\t\t\tb.base != null &&\n\t\t\t\ta.base.ref === b.base.ref &&\n\t\t\t\ta.base.ahead === b.base.ahead &&\n\t\t\t\ta.base.sha === b.base.sha &&\n\t\t\t\ta.base.forkPoint === b.base.forkPoint &&\n\t\t\t\ta.base.tier === b.base.tier))\n\t);\n}\n"],"mappings":"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"}
@@ -15,10 +15,10 @@ import { fsExists } from "../utils/env/node/exec.js";
15
15
  import { Git, batchLiteralPathspecs, gitConfigsStatus } from "./exec/git.js";
16
16
  import { foldMatchingIgnored } from "./parsers/statusParser.js";
17
17
  import { BlameGitSubProvider } from "./providers/blame.js";
18
+ import { ConfigGitSubProvider, isGitBooleanFalse, parseGitBoolean } from "./providers/config.js";
18
19
  import { BranchesGitSubProvider } from "./providers/branches.js";
19
20
  import { StashGitSubProvider } from "./providers/stash.js";
20
21
  import { CommitsGitSubProvider } from "./providers/commits.js";
21
- import { ConfigGitSubProvider, isGitBooleanFalse, parseGitBoolean } from "./providers/config.js";
22
22
  import { ContributorsGitSubProvider } from "./providers/contributors.js";
23
23
  import { DiffGitSubProvider } from "./providers/diff.js";
24
24
  import { GraphGitSubProvider } from "./providers/graph.js";