@gitkraken/core-gitlens 0.17.0 → 0.18.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.
@@ -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 { LruMap } from '@gitlens/utils/lruMap.js';\nimport { joinPaths } from '@gitlens/utils/path.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 { GitRefTip } from '../models/reference.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 WorktreeSummarySnapshot {\n\treadonly summary: WorktreeSummary;\n\t/**\n\t * When {@link WorktreeSummary.dirty} was read (`Date.now()` as the read started), for a worktree without a\n\t * subscription, whose working tree nothing watches; `undefined` for a subscribed worktree, whose summary follows\n\t * its working tree\n\t */\n\treadonly dirtyReadAt: number | undefined;\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 * Reads a path's modification time (ms) and size; `undefined` when it doesn't exist, and a rejection means unknown.\n\t * With it, a read of a worktree without a subscription re-reads the dirty flag only when the worktree's index file\n\t * moved since the last one (or when asked to); without it, on every such read.\n\t */\n\treadonly stat?: (path: string) => Promise<{ readonly mtime: number; readonly size: number } | 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// Worktrees without a subscription whose last read is kept to answer from: a host listing more than this re-reads the\n// least recently asked in full\nconst maxUnwatchedReads = 256;\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\t/** When the dirty read started; `undefined` when dirty wasn't read but kept from `previous` */\n\treadonly dirtyReadAt: number | undefined;\n}\n\n/**\n * What an unwatched read was read from, taken just before it, so a change landing during the read leaves these looking\n * older than the disk and the next read re-reads what it moved. All of it comes from core's caches, which the `.git`\n * watch drops on a HEAD or ref change, or from one stat.\n */\ninterface UnwatchedInputs {\n\t/** HEAD as `getBranch` answered it: the branch (`undefined` when detached), detached, and HEAD's commit */\n\treadonly branch: string | undefined;\n\treadonly detached: boolean;\n\treadonly sha: string | undefined;\n\t/** The upstream's short name, which a `.git/config` write can change without moving any ref */\n\treadonly upstream: string | undefined;\n\t/**\n\t * The upstream's tips as a remote-tracking and as a local branch, since its short name doesn't say which; `undefined`\n\t * without an upstream\n\t */\n\treadonly upstreamTips: string | undefined;\n\t/**\n\t * The tip of each ref the base depends on, or for a remote's `HEAD` symref the ref it points at (see\n\t * {@link getBaseInput}); `undefined` for one that doesn't exist, which counts as unchanged only while it stays out,\n\t * and `null` for one that couldn't be read, which never does\n\t */\n\treadonly baseTips: ReadonlyMap<string, string | null | undefined>;\n\t/** The size and modification time of the worktree's index file; `undefined` when unknown (no stat, or it failed) */\n\treadonly index: string | undefined;\n}\n\n/** The last read of a worktree without a subscription, answered from until its inputs move */\ninterface UnwatchedRead {\n\treadonly result: ReadResult;\n\treadonly dirtyReadAt: number;\n\treadonly inputs: UnwatchedInputs;\n\t/** Read groups due on the next read whatever the inputs say: core's own write of the branch's merge target or base */\n\tdue: number;\n}\n\n/** What an unwatched read finds of its inputs before it reads */\ninterface UnwatchedProbe {\n\treadonly branch: string | undefined;\n\treadonly detached: boolean;\n\treadonly sha: string | undefined;\n\treadonly upstream: string | undefined;\n\t/** The ref tips' commits by full name (see {@link getTipsByName}) */\n\treadonly tips: ReadonlyMap<string, string>;\n\t/** Where the `HEAD` symref of each remote it read points, by remote name (see {@link readRemoteHeads}) */\n\treadonly remoteHeads: Map<string, string | null | undefined>;\n\treadonly index: string | undefined;\n}\n\n/** A read of a worktree without a subscription, which concurrent callers share */\nclass UnwatchedFlight {\n\treadonly abort = new AbortController();\n\t/** Callers waiting for it; the read is aborted once none is */\n\tcallers = 0;\n\t/** Read groups made due while it ran, carried into what it stores */\n\tdue = 0;\n\treadonly promise: Promise<UnwatchedRead>;\n\n\tconstructor(\n\t\treadonly key: string,\n\t\t/** Whether it re-reads the dirty flag whatever its inputs say; a caller asking for that joins only such a read */\n\t\treadonly probeDirty: boolean,\n\t\t/** Set once no caller waits any longer (or the service is disposed), which aborts the read */\n\t\tpublic disposed: boolean,\n\t\tread: (flight: UnwatchedFlight) => Promise<UnwatchedRead>,\n\t) {\n\t\t// A turn later, once the caller registered it: a read failing before its first await must still find itself the\n\t\t// registered one, to drop the last read\n\t\tthis.promise = Promise.resolve().then(() => read(this));\n\t\t// Callers race it against their own cancellation, so once every one gave up its rejection has no other handler\n\t\tthis.promise.catch(noop);\n\t}\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 *\n * **Worktrees without a subscription.** {@link getSummary} and {@link getSummarySnapshot} answer one from its last read\n * (kept for the {@link maxUnwatchedReads} most recently asked), re-reading only the groups whose inputs moved since:\n * HEAD's branch or commit reads all of them; the upstream's tip, or its name, reads `branch`; a ref the base depends on\n * (where a remote's `HEAD` symref points, for one) reads `base`, re-measured from the previous one where that can\n * answer; the config inputs its base read consulted read `branch` and the base when they changed; and the worktree's\n * index file reads `dirty`. The inputs come from core's caches, so nothing moved means no git at all; only a `.git`\n * watch of the worktree (or core's own writes) keeps them current, so a host must watch the `.git` of a worktree it\n * asks about this way for others' changes to show. Its working tree is unwatched, so an edit that leaves the index\n * alone goes unseen until `dirty` is read again: the snapshot says when that was, and `probeDirty` reads it anyway.\n * Concurrent reads of a worktree share one, and take no read slot: each is a caller's foreground read, which never\n * waits behind subscribed worktrees' runs.\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\t/** The last read of each worktree without a subscription, by repository key */\n\tprivate readonly unwatchedReads = new LruMap<string, UnwatchedRead>(maxUnwatchedReads);\n\t/** The read in flight for each worktree without a subscription, by repository key */\n\tprivate readonly unwatchedFlights = new Map<string, UnwatchedFlight>();\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 stat: WorktreeSummaryServiceOptions['stat'];\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.stat = options.stat;\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\tfor (const flight of this.unwatchedFlights.values()) {\n\t\t\tflight.disposed = true;\n\t\t\tflight.abort.abort();\n\t\t}\n\t\tthis.unwatchedFlights.clear();\n\t\tthis.unwatchedReads.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\t// The subscribed value supersedes the last unwatched read, and a read still in flight no longer stores one\n\t\t\t\tthis.unwatchedReads.delete(key);\n\t\t\t\tthis.unwatchedFlights.delete(key);\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 the last read of it,\n\t * re-reading what moved since (see {@link getSummarySnapshot}).\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) return (await this.getUnwatchedSnapshot(key, false, cancellation)).summary;\n\n\t\treturn this.getSubscribedSummary(entry, cancellation);\n\t}\n\n\t/**\n\t * Returns a worktree's summary, with when its dirty flag was read. A subscribed worktree answers as\n\t * {@link getSummary} does, with `dirtyReadAt` `undefined`, since its summary follows its working tree. Any other\n\t * answers from its last read, re-reading only the groups whose inputs moved since (no git when none did), and in\n\t * full the first time, or after a failed or stale read. Its working tree is unwatched, so the dirty flag is re-read\n\t * only when the index file moved, or with `probeDirty`; a rejection drops the last read. Its inputs are core's\n\t * cached answers, which only a `.git` watch of the worktree (or core's own writes) keeps current.\n\t */\n\tasync getSummarySnapshot(\n\t\trepoPath: string,\n\t\toptions?: { probeDirty?: boolean; cancellation?: AbortSignal },\n\t): Promise<WorktreeSummarySnapshot> {\n\t\tconst key = getRepositoryKey(repoPath);\n\t\tconst entry = this.entries.get(key);\n\t\tif (entry == null) return this.getUnwatchedSnapshot(key, options?.probeDirty ?? false, options?.cancellation);\n\n\t\treturn { summary: await this.getSubscribedSummary(entry, options?.cancellation), dirtyReadAt: undefined };\n\t}\n\n\tprivate async getSubscribedSummary(\n\t\tentry: SummaryEntry,\n\t\tcancellation: AbortSignal | undefined,\n\t): Promise<WorktreeSummary> {\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 '${entry.key}'`);\n\t}\n\n\t/** Joins the read in flight for `key`, or starts one; the read is aborted only once no caller waits for it */\n\tprivate async getUnwatchedSnapshot(\n\t\tkey: string,\n\t\tprobeDirty: boolean,\n\t\tcancellation: AbortSignal | undefined,\n\t): Promise<WorktreeSummarySnapshot> {\n\t\tif (cancellation?.aborted) throw new CancellationError();\n\n\t\tlet flight = this.getJoinableFlight(key);\n\t\tif (probeDirty) {\n\t\t\t// A read that won't re-read the dirty flag can't answer a caller that asked for it; wait it out, then read\n\t\t\t// again\n\t\t\twhile (flight != null && !flight.probeDirty) {\n\t\t\t\tconst waited = flight;\n\t\t\t\ttry {\n\t\t\t\t\tawait (cancellation != null ? raceWithSignal(waited.promise, cancellation) : waited.promise);\n\t\t\t\t} catch (ex) {\n\t\t\t\t\tif (cancellation?.aborted) throw ex;\n\t\t\t\t}\n\t\t\t\tflight = this.getJoinableFlight(key);\n\t\t\t\t// Settled, though its callers haven't all let go of it yet\n\t\t\t\tif (flight === waited) {\n\t\t\t\t\tflight = undefined;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// A subscription that started meanwhile answers instead, its summary following the working tree\n\t\t\tconst entry = this.entries.get(key);\n\t\t\tif (entry != null) {\n\t\t\t\treturn { summary: await this.getSubscribedSummary(entry, cancellation), dirtyReadAt: undefined };\n\t\t\t}\n\t\t}\n\n\t\tif (flight == null) {\n\t\t\tflight = new UnwatchedFlight(key, probeDirty, this._disposed, f => this.readUnwatched(f));\n\t\t\tif (!this._disposed) {\n\t\t\t\tthis.unwatchedFlights.set(key, flight);\n\t\t\t}\n\t\t}\n\n\t\tconst current = flight;\n\t\tcurrent.callers++;\n\t\ttry {\n\t\t\tconst read = await (cancellation != null ? raceWithSignal(current.promise, cancellation) : current.promise);\n\t\t\treturn { summary: read.result.summary, dirtyReadAt: read.dirtyReadAt };\n\t\t} finally {\n\t\t\tcurrent.callers--;\n\t\t\t// Settled, or every caller gave up; either way a later caller starts a read of its own. Aborted even once\n\t\t\t// another read or a subscription took its place, which no caller waits on any longer\n\t\t\tif (current.callers === 0) {\n\t\t\t\tif (this.unwatchedFlights.get(key) === current) {\n\t\t\t\t\tthis.unwatchedFlights.delete(key);\n\t\t\t\t}\n\t\t\t\tcurrent.disposed = true;\n\t\t\t\tcurrent.abort.abort();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * The read in flight for `key`, unless core wrote a merge target or base while it ran: it may have read the stored\n\t * values before the write, and a caller after an awaited write sees them, as one of a subscribed worktree does\n\t */\n\tprivate getJoinableFlight(key: string): UnwatchedFlight | undefined {\n\t\tconst flight = this.unwatchedFlights.get(key);\n\t\treturn flight?.due === 0 ? flight : undefined;\n\t}\n\n\tprivate async readUnwatched(flight: UnwatchedFlight): Promise<UnwatchedRead> {\n\t\tconst { key } = flight;\n\t\tconst signal = flight.abort.signal;\n\t\tif (flight.disposed) throw new CancellationError();\n\n\t\t// A stale read's fields can't be trusted (see `queue`), so it is read again in full\n\t\tlet last = this.unwatchedReads.get(key);\n\t\tif (last?.result.summary.stale) {\n\t\t\tlast = undefined;\n\t\t}\n\n\t\ttry {\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\t// Core drops every remote's cached `HEAD` symref on any ref change, so after the first read only those the\n\t\t\t// base depends on are read, unless the base is read again\n\t\t\tconst headRemotes = last != null ? getHeadRemotes(last.result.summary.baseDependsOn) : undefined;\n\t\t\tconst probe = await this.probeUnwatched(repo, headRemotes, signal);\n\t\t\tif (flight.disposed) throw new CancellationError();\n\n\t\t\tlet fields: number;\n\t\t\tlet baseMoves: Set<string> | undefined;\n\t\t\tif (last == null) {\n\t\t\t\t// The config inputs too, so a later base move can be re-measured against the key they had\n\t\t\t\tfields = allFields | baseConfigField;\n\t\t\t} else {\n\t\t\t\tfields = last.due;\n\t\t\t\tconst { inputs } = last;\n\t\t\t\tconst previous = last.result.summary;\n\t\t\t\tif (probe.branch !== inputs.branch || probe.detached !== inputs.detached || probe.sha !== inputs.sha) {\n\t\t\t\t\t// The branch read only widens to the rest for a different branch, but a commit moves the base count\n\t\t\t\t\t// and can leave the working tree clean\n\t\t\t\t\tfields |= allFields;\n\t\t\t\t} else {\n\t\t\t\t\tif (probe.upstream !== inputs.upstream) {\n\t\t\t\t\t\t// The config inputs too, which read the base again when the upstream's identity changed\n\t\t\t\t\t\tfields |= branchField | baseConfigField;\n\t\t\t\t\t} else if (getUpstreamTips(probe.tips, probe.upstream) !== inputs.upstreamTips) {\n\t\t\t\t\t\tfields |= branchField;\n\t\t\t\t\t}\n\t\t\t\t\tfor (const ref of previous.baseDependsOn) {\n\t\t\t\t\t\t// An unreadable value is unknown, so it moved\n\t\t\t\t\t\tconst value = getBaseInput(probe, ref);\n\t\t\t\t\t\tif (value !== null && value === inputs.baseTips.get(ref)) continue;\n\n\t\t\t\t\t\tbaseMoves ??= new Set();\n\t\t\t\t\t\tbaseMoves.add(ref);\n\t\t\t\t\t}\n\t\t\t\t\tif (baseMoves != null) {\n\t\t\t\t\t\tfields |= baseMoveField;\n\t\t\t\t\t}\n\t\t\t\t\t// A config write the base read consulted (another branch's tracking, a remote, the default branch)\n\t\t\t\t\t// moves no ref; one cached read, as a subscribed worktree's config change reads\n\t\t\t\t\tif (\n\t\t\t\t\t\t(fields & baseConfigField) === 0 &&\n\t\t\t\t\t\tlast.result.baseConfigKey != null &&\n\t\t\t\t\t\trepo.branches.getAheadOfBase != null &&\n\t\t\t\t\t\t(probe.detached || probe.branch != null)\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst configKey = getBaseConfigKey(await readBaseConfig(repo, signal), previous);\n\t\t\t\t\t\tif (flight.disposed) throw new CancellationError();\n\n\t\t\t\t\t\t// An unreadable config is unknown, not changed\n\t\t\t\t\t\tif (configKey != null && configKey !== last.result.baseConfigKey) {\n\t\t\t\t\t\t\tfields |= branchField | baseConfigField;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (flight.probeDirty || probe.index == null || probe.index !== inputs.index) {\n\t\t\t\t\tfields |= dirtyField;\n\t\t\t\t}\n\t\t\t\tif (fields === 0) {\n\t\t\t\t\tthis.unwatchedReads.touch(key);\n\t\t\t\t\treturn last;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// A base read can come to depend on any remote's `HEAD`, so the rest are read too, before it like the other\n\t\t\t// inputs\n\t\t\tif (headRemotes != null && (fields & (baseField | baseKeysField | baseConfigField | baseMoveField)) !== 0) {\n\t\t\t\tawait readRemoteHeads(repo, probe.remoteHeads, undefined, signal);\n\t\t\t\tif (flight.disposed) throw new CancellationError();\n\t\t\t}\n\n\t\t\t// No read slot: like the one-off read it replaces, this is a caller's foreground read, which never waits\n\t\t\t// behind subscribed worktrees' runs\n\t\t\tlet result = await readSummary(\n\t\t\t\trepo,\n\t\t\t\tkey,\n\t\t\t\tfields,\n\t\t\t\tlast?.result.summary,\n\t\t\t\tlast?.result.baseKeys,\n\t\t\t\tlast?.result.baseConfigKey,\n\t\t\t\tlast?.result.baseDefaultBranch,\n\t\t\t\tbaseMoves,\n\t\t\t\tsignal,\n\t\t\t\tthis.verifyBaseRemeasure,\n\t\t\t);\n\n\t\t\t// Keep the summary the caller already has when nothing in it changed\n\t\t\tconst kept = last?.result.summary;\n\t\t\tif (kept != null && summariesEqual(kept, result.summary)) {\n\t\t\t\tresult = { ...result, summary: kept };\n\t\t\t}\n\t\t\tconst read: UnwatchedRead = {\n\t\t\t\tresult: result,\n\t\t\t\t// Without a last read every group was read, dirty included\n\t\t\t\tdirtyReadAt: result.dirtyReadAt ?? last?.dirtyReadAt ?? Date.now(),\n\t\t\t\tinputs: toUnwatchedInputs(probe, result.summary),\n\t\t\t\tdue: flight.due,\n\t\t\t};\n\t\t\tif (this.unwatchedFlights.get(key) === flight && !this.entries.has(key)) {\n\t\t\t\tthis.unwatchedReads.set(key, read);\n\t\t\t}\n\t\t\treturn read;\n\t\t} catch (ex) {\n\t\t\tif (!isCancellationError(ex) && this.unwatchedFlights.get(key) === flight) {\n\t\t\t\tthis.unwatchedReads.delete(key);\n\t\t\t}\n\t\t\tthrow ex;\n\t\t}\n\t}\n\n\t/**\n\t * Reads an unwatched read's inputs: cached answers but for the index file's stat (see {@link UnwatchedInputs}), with\n\t * the `HEAD` symrefs of `remotes` (every remote's when `undefined`)\n\t */\n\tprivate async probeUnwatched(\n\t\trepo: RepositoryService,\n\t\tremotes: ReadonlySet<string> | undefined,\n\t\tsignal: AbortSignal,\n\t): Promise<UnwatchedProbe> {\n\t\tconst remoteHeads = new Map<string, string | null | undefined>();\n\t\tconst [current, tips, gitDir] = await Promise.all([\n\t\t\trepo.branches.getBranch(undefined, undefined, signal),\n\t\t\trepo.refs.getRefTips(undefined, signal),\n\t\t\tgetGitDir(repo),\n\t\t\treadRemoteHeads(repo, remoteHeads, remotes, signal),\n\t\t]);\n\n\t\tlet index: string | undefined;\n\t\tconst stat = this.stat;\n\t\tif (stat != null && gitDir != null) {\n\t\t\ttry {\n\t\t\t\tconst stats = await stat(joinPaths(gitDir.uri.fsPath, 'index'));\n\t\t\t\tindex = stats != null ? `${stats.size}:${stats.mtime}` : '';\n\t\t\t} catch {\n\t\t\t\tindex = undefined;\n\t\t\t}\n\t\t}\n\n\t\tconst detached = current?.detached ?? false;\n\t\treturn {\n\t\t\tbranch: detached ? undefined : current?.name || undefined,\n\t\t\tdetached: detached,\n\t\t\tsha: current?.sha,\n\t\t\tupstream: current?.upstream?.name,\n\t\t\ttips: getTipsByName(tips),\n\t\t\tremoteHeads: remoteHeads,\n\t\t\tindex: index,\n\t\t};\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\tif (!this.isInRepository(entry.key, e.repoPath)) continue;\n\n\t\t\tthis.queue(entry, baseKeysField);\n\t\t}\n\n\t\t// No ref moves for such a write, so a worktree without a subscription re-reads the stored values on its next read\n\t\tfor (const read of this.unwatchedReads.values()) {\n\t\t\tconst value = read.result.summary;\n\t\t\tif (value.branch == null || (e.refs != null && !e.refs.has(value.branch))) continue;\n\t\t\tif (!this.isInRepository(value.repoPath, e.repoPath)) continue;\n\n\t\t\tread.due |= baseKeysField;\n\t\t}\n\t\t// One in flight may have read them before the write, so it takes no more callers; its branch isn't known yet,\n\t\t// so any of the repository's\n\t\tfor (const flight of this.unwatchedFlights.values()) {\n\t\t\tif (!this.isInRepository(flight.key, e.repoPath)) continue;\n\n\t\t\tflight.due |= baseKeysField;\n\t\t}\n\t}\n\n\tprivate isInRepository(key: string, commonPath: string): boolean {\n\t\tconst path = this.getCommonPath?.(key);\n\t\treturn path == null || path === commonPath;\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 dirtyReadAt: number | undefined;\n\tconst startDirtyRead = (): Promise<boolean> => {\n\t\tdirtyReadAt = Date.now();\n\t\treturn readDirty(repo, signal);\n\t};\n\tlet dirtyRead = fields & dirtyField ? startDirtyRead() : 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 ??= startDirtyRead();\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\tdirtyReadAt: dirtyReadAt,\n\t};\n}\n\nasync function getGitDir(repo: RepositoryService): Promise<GitDir | undefined> {\n\ttry {\n\t\treturn await repo.config.getGitDir?.();\n\t} catch (ex) {\n\t\tif (isCancellationError(ex)) throw ex;\n\n\t\treturn undefined;\n\t}\n}\n\n/** Each ref list's tips by full name, built once per list, which core's cache shares across a repository's worktrees */\nconst tipsByNameCache = new WeakMap<readonly GitRefTip[], ReadonlyMap<string, string>>();\n\nfunction getTipsByName(tips: readonly GitRefTip[]): ReadonlyMap<string, string> {\n\tlet byName = tipsByNameCache.get(tips);\n\tif (byName == null) {\n\t\tconst map = new Map<string, string>();\n\t\tfor (const tip of tips) {\n\t\t\tmap.set(tip.fullName, tip.sha);\n\t\t}\n\t\tbyName = map;\n\t\ttipsByNameCache.set(tips, byName);\n\t}\n\treturn byName;\n}\n\n/** The upstream's tips as a remote-tracking and as a local branch, since its short name doesn't say which */\nfunction getUpstreamTips(tips: ReadonlyMap<string, string>, upstream: string | undefined): string | undefined {\n\tif (upstream == null) return undefined;\n\n\treturn `${tips.get(`refs/remotes/${upstream}`) ?? ''}\\0${tips.get(`refs/heads/${upstream}`) ?? ''}`;\n}\n\n/**\n * Reads where the `HEAD` symref of each of `remotes` (every remote's when `undefined`) points (`origin/main`) into\n * `heads`, as core's cached local reads answer it, skipping those already there: `undefined` when it has none (a\n * remote since removed included), `null` when the read failed\n */\nasync function readRemoteHeads(\n\trepo: RepositoryService,\n\theads: Map<string, string | null | undefined>,\n\tremotes: ReadonlySet<string> | undefined,\n\tsignal: AbortSignal,\n): Promise<void> {\n\tif (remotes?.size === 0) return;\n\n\tconst names = remotes ?? (await repo.remotes.getRemotes(undefined, signal)).map(r => r.name);\n\tawait Promise.all(\n\t\tArray.from(names, async name => {\n\t\t\tif (heads.has(name)) return;\n\n\t\t\tlet target: string | null | undefined;\n\t\t\ttry {\n\t\t\t\ttarget = await repo.branches.getDefaultBranchName(name, { local: true }, signal);\n\t\t\t} catch (ex) {\n\t\t\t\tif (isCancellationError(ex)) throw ex;\n\n\t\t\t\ttarget = null;\n\t\t\t}\n\t\t\theads.set(name, target);\n\t\t}),\n\t);\n}\n\n/** The remote whose `HEAD` symref `ref` is; `undefined` for any other ref */\nfunction getHeadRemote(ref: string): string | undefined {\n\tif (!ref.startsWith('refs/remotes/') || !ref.endsWith('/HEAD')) return undefined;\n\n\t// A remote name can hold a slash, so the remote is everything between\n\treturn ref.slice('refs/remotes/'.length, -'/HEAD'.length);\n}\n\n/** The remotes whose `HEAD` symref is among `refs` */\nfunction getHeadRemotes(refs: readonly string[]): Set<string> {\n\tconst remotes = new Set<string>();\n\tfor (const ref of refs) {\n\t\tconst remote = getHeadRemote(ref);\n\t\tif (remote != null) {\n\t\t\tremotes.add(remote);\n\t\t}\n\t}\n\treturn remotes;\n}\n\n/**\n * What `probe` found of `ref`, a ref the base depends on: for a remote's `HEAD` symref, which the ref tips leave out,\n * the ref it points at, since its tip follows that ref's, itself a dependency; else its tip. `null` for a symref of a\n * remote it didn't read: only when the read found HEAD elsewhere than the probe did and read the base for that, which\n * the next probe sees as HEAD moving anyway\n */\nfunction getBaseInput(probe: UnwatchedProbe, ref: string): string | null | undefined {\n\tconst remote = getHeadRemote(ref);\n\tif (remote == null) return probe.tips.get(ref);\n\n\treturn probe.remoteHeads.has(remote) ? probe.remoteHeads.get(remote) : null;\n}\n\n/** The inputs `summary` was read from, as the probe before its read found them */\nfunction toUnwatchedInputs(probe: UnwatchedProbe, summary: WorktreeSummary): UnwatchedInputs {\n\tconst baseTips = new Map<string, string | null | undefined>();\n\tfor (const ref of summary.baseDependsOn) {\n\t\tbaseTips.set(ref, getBaseInput(probe, ref));\n\t}\n\treturn {\n\t\tbranch: probe.branch,\n\t\tdetached: probe.detached,\n\t\tsha: probe.sha,\n\t\tupstream: probe.upstream,\n\t\tupstreamTips: getUpstreamTips(probe.tips, probe.upstream),\n\t\tbaseTips: baseTips,\n\t\tindex: probe.index,\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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"}
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 { LruMap } from '@gitlens/utils/lruMap.js';\nimport { joinPaths } from '@gitlens/utils/path.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 { GitRefTip } from '../models/reference.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 WorktreeSummarySnapshot {\n\treadonly summary: WorktreeSummary;\n\t/**\n\t * When {@link WorktreeSummary.dirty} was read (`Date.now()` as the read started), for a worktree without a\n\t * subscription, whose working tree nothing watches, or a subscribed one still showing such a read's (see\n\t * {@link WorktreeSummarySubscription.dirtyReadAt}); `undefined` for a subscribed worktree whose summary follows its\n\t * working tree\n\t */\n\treadonly dirtyReadAt: number | undefined;\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/**\n\t * When {@link current}'s dirty flag was read, while it's still the one a read without a subscription found: the\n\t * working-tree watch reads it once live. `undefined` once the summary follows its working tree, or after disposal\n\t */\n\treadonly dirtyReadAt: number | undefined;\n\t/**\n\t * Fires when the summary's value changes, and with the same summary when a dirty flag kept from a read without a\n\t * subscription is read again (see {@link dirtyReadAt})\n\t */\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 * Reads a path's modification time (ms) and size; `undefined` when it doesn't exist, and a rejection means unknown.\n\t * With it, a read of a worktree without a subscription re-reads the dirty flag only when the worktree's index file\n\t * moved since the last one (or when asked to); without it, on every such read.\n\t */\n\treadonly stat?: (path: string) => Promise<{ readonly mtime: number; readonly size: number } | 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// Worktrees without a subscription whose last read is kept to answer from: a host listing more than this re-reads the\n// least recently asked in full\nconst maxUnwatchedReads = 256;\n// How long a newly subscribed worktree serves its saved dirty flag waiting for its working-tree watch to go live; past\n// it, the flag is read without the rescan, so a provider that promised a start that never comes can't leave it\n// unconfirmed\nconst maxDeferredDirtyMs = 10_000;\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\t/** When the dirty read started; `undefined` when dirty wasn't read but kept from `previous` */\n\treadonly dirtyReadAt: number | undefined;\n}\n\n/**\n * What an unwatched read was read from, taken just before it, so a change landing during the read leaves these looking\n * older than the disk and the next read re-reads what it moved. All of it comes from core's caches, which the `.git`\n * watch drops on a HEAD or ref change, or from one stat.\n */\ninterface UnwatchedInputs {\n\t/** HEAD as `getBranch` answered it: the branch (`undefined` when detached), detached, and HEAD's commit */\n\treadonly branch: string | undefined;\n\treadonly detached: boolean;\n\treadonly sha: string | undefined;\n\t/** The upstream's short name, which a `.git/config` write can change without moving any ref */\n\treadonly upstream: string | undefined;\n\t/**\n\t * The upstream's tips as a remote-tracking and as a local branch, since its short name doesn't say which; `undefined`\n\t * without an upstream\n\t */\n\treadonly upstreamTips: string | undefined;\n\t/**\n\t * The tip of each ref the base depends on, or for a remote's `HEAD` symref the ref it points at (see\n\t * {@link getBaseInput}); `undefined` for one that doesn't exist, which counts as unchanged only while it stays out,\n\t * and `null` for one that couldn't be read, which never does\n\t */\n\treadonly baseTips: ReadonlyMap<string, string | null | undefined>;\n\t/** The size and modification time of the worktree's index file; `undefined` when unknown (no stat, or it failed) */\n\treadonly index: string | undefined;\n}\n\n/** The last read of a worktree without a subscription, answered from until its inputs move */\ninterface UnwatchedRead {\n\treadonly result: ReadResult;\n\treadonly dirtyReadAt: number;\n\treadonly inputs: UnwatchedInputs;\n\t/** Read groups due on the next read whatever the inputs say: core's own write of the branch's merge target or base */\n\tdue: number;\n}\n\n/** What an unwatched read finds of its inputs before it reads */\ninterface UnwatchedProbe {\n\treadonly branch: string | undefined;\n\treadonly detached: boolean;\n\treadonly sha: string | undefined;\n\treadonly upstream: string | undefined;\n\t/** The ref tips' commits by full name (see {@link getTipsByName}) */\n\treadonly tips: ReadonlyMap<string, string>;\n\t/** Where the `HEAD` symref of each remote it read points, by remote name (see {@link readRemoteHeads}) */\n\treadonly remoteHeads: Map<string, string | null | undefined>;\n\treadonly index: string | undefined;\n}\n\n/** A read of a worktree without a subscription, which concurrent callers share */\nclass UnwatchedFlight {\n\treadonly abort = new AbortController();\n\t/** Callers waiting for it; the read is aborted once none is */\n\tcallers = 0;\n\t/** Read groups made due while it ran, carried into what it stores */\n\tdue = 0;\n\treadonly promise: Promise<UnwatchedRead>;\n\n\tconstructor(\n\t\treadonly key: string,\n\t\t/** Whether it re-reads the dirty flag whatever its inputs say; a caller asking for that joins only such a read */\n\t\treadonly probeDirty: boolean,\n\t\t/** Set once no caller waits any longer (or the service is disposed), which aborts the read */\n\t\tpublic disposed: boolean,\n\t\tread: (flight: UnwatchedFlight) => Promise<UnwatchedRead>,\n\t) {\n\t\t// A turn later, once the caller registered it: a read failing before its first await must still find itself the\n\t\t// registered one, to drop the last read\n\t\tthis.promise = Promise.resolve().then(() => read(this));\n\t\t// Callers race it against their own cancellation, so once every one gave up its rejection has no other handler\n\t\tthis.promise.catch(noop);\n\t}\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/**\n\t * The last read without a subscription, which the first run starts from; never answered, since its dirty flag\n\t * doesn't follow the working tree\n\t */\n\tseed: WorktreeSummary | undefined;\n\t/**\n\t * When the value's dirty flag was read, while it is still the saved read's (see `queueSeedStart`); `undefined` once\n\t * the value follows the working tree\n\t */\n\tdirtyReadAt: number | undefined;\n\t/** Reads the saved read's dirty flag should the working-tree watch not go live in {@link maxDeferredDirtyMs} */\n\tdirtyReadTimer: ReturnType<typeof setTimeout> | 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 dirtyReadAt(): number | undefined {\n\t\t// Nothing to date before the first value\n\t\treturn this.disposed || this.entry.value == null ? undefined : this.entry.dirtyReadAt;\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, or, for a worktree last read without a subscription, starts from\n * that read: it re-reads the groups whose inputs moved since, by the same rules as such a read, and always `dirty` —\n * unless its working-tree watch is still starting, when the rescan that watch owes reads it, and the summary keeps the\n * saved read's flag, with its `dirtyReadAt`, until then. 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. A summary still showing the dirty flag of a read\n * without a subscription fires again, unchanged, once that flag is read again (its `dirtyReadAt` cleared).\n *\n * **Worktrees without a subscription.** {@link getSummary} and {@link getSummarySnapshot} answer one from its last read\n * (kept for the {@link maxUnwatchedReads} most recently asked), re-reading only the groups whose inputs moved since:\n * HEAD's branch or commit reads all of them; the upstream's tip, or its name, reads `branch`; a ref the base depends on\n * (where a remote's `HEAD` symref points, for one) reads `base`, re-measured from the previous one where that can\n * answer; the config inputs its base read consulted read `branch` and the base when they changed; and the worktree's\n * index file reads `dirty`. The inputs come from core's caches, so nothing moved means no git at all; only a `.git`\n * watch of the worktree (or core's own writes) keeps them current, so a host must watch the `.git` of a worktree it\n * asks about this way for others' changes to show. Its working tree is unwatched, so an edit that leaves the index\n * alone goes unseen until `dirty` is read again: the snapshot says when that was, and `probeDirty` reads it anyway.\n * Concurrent reads of a worktree share one, and take no read slot: each is a caller's foreground read, which never\n * waits behind subscribed worktrees' runs. A first subscriber takes over the last read.\n */\nexport class WorktreeSummaryService implements UnifiedDisposable {\n\tprivate readonly _onDidChangeSummary = new Emitter<WorktreeSummary>();\n\t/**\n\t * Fires when the summary of any subscribed worktree changes value, and with the same summary when a dirty flag kept\n\t * from a read without a subscription is read again (see {@link WorktreeSummarySubscription.dirtyReadAt})\n\t */\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\t/** The last read of each worktree without a subscription, by repository key */\n\tprivate readonly unwatchedReads = new LruMap<string, UnwatchedRead>(maxUnwatchedReads);\n\t/** The read in flight for each worktree without a subscription, by repository key */\n\tprivate readonly unwatchedFlights = new Map<string, UnwatchedFlight>();\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 stat: WorktreeSummaryServiceOptions['stat'];\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.stat = options.stat;\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\tfor (const flight of this.unwatchedFlights.values()) {\n\t\t\tflight.disposed = true;\n\t\t\tflight.abort.abort();\n\t\t}\n\t\tthis.unwatchedFlights.clear();\n\t\tthis.unwatchedReads.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/**\n\t * Subscribes to a worktree's summary, starting to watch and read it if this is its first subscriber: from its last\n\t * read without a subscription, if any, re-reading the groups whose inputs moved since and the dirty flag — at once,\n\t * or, while its working-tree watch is still starting, as that watch goes live\n\t */\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\t// The start takes over the last unwatched read, and a read still in flight no longer stores one\n\t\t\t\tthis.unwatchedFlights.delete(key);\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.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 the last read of it,\n\t * re-reading what moved since (see {@link getSummarySnapshot}).\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) return (await this.getUnwatchedSnapshot(key, false, cancellation)).summary;\n\n\t\treturn this.getSubscribedSummary(entry, cancellation);\n\t}\n\n\t/**\n\t * Returns a worktree's summary, with when its dirty flag was read. A subscribed worktree answers as\n\t * {@link getSummary} does, with `dirtyReadAt` `undefined` once its summary follows its working tree, and until then\n\t * the saved read's (see {@link WorktreeSummarySubscription.dirtyReadAt}), which `probeDirty` reads again. Any other\n\t * answers from its last read, re-reading only the groups whose inputs moved since (no git when none did), and in\n\t * full the first time, or after a failed or stale read. Its working tree is unwatched, so the dirty flag is re-read\n\t * only when the index file moved, or with `probeDirty`; a rejection drops the last read. Its inputs are core's\n\t * cached answers, which only a `.git` watch of the worktree (or core's own writes) keeps current.\n\t */\n\tasync getSummarySnapshot(\n\t\trepoPath: string,\n\t\toptions?: { probeDirty?: boolean; cancellation?: AbortSignal },\n\t): Promise<WorktreeSummarySnapshot> {\n\t\tconst key = getRepositoryKey(repoPath);\n\t\tconst entry = this.entries.get(key);\n\t\tif (entry == null) return this.getUnwatchedSnapshot(key, options?.probeDirty ?? false, options?.cancellation);\n\n\t\treturn this.getSubscribedSnapshot(entry, options?.probeDirty ?? false, options?.cancellation);\n\t}\n\n\tprivate async getSubscribedSnapshot(\n\t\tentry: SummaryEntry,\n\t\tprobeDirty: boolean,\n\t\tcancellation: AbortSignal | undefined,\n\t): Promise<WorktreeSummarySnapshot> {\n\t\tlet summary = await this.getSubscribedSummary(entry, cancellation);\n\t\t// Asked for, a dirty flag kept from the saved read is read now rather than once the watch goes live. Looked at\n\t\t// after the wait, since the start decides to keep it only once it probed\n\t\tif (probeDirty && entry.dirtyReadAt != null) {\n\t\t\tthis.queue(entry, dirtyField);\n\t\t\tsummary = await this.getSubscribedSummary(entry, cancellation);\n\t\t}\n\t\treturn { summary: summary, dirtyReadAt: entry.dirtyReadAt };\n\t}\n\n\tprivate async getSubscribedSummary(\n\t\tentry: SummaryEntry,\n\t\tcancellation: AbortSignal | undefined,\n\t): Promise<WorktreeSummary> {\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 '${entry.key}'`);\n\t}\n\n\t/** Joins the read in flight for `key`, or starts one; the read is aborted only once no caller waits for it */\n\tprivate async getUnwatchedSnapshot(\n\t\tkey: string,\n\t\tprobeDirty: boolean,\n\t\tcancellation: AbortSignal | undefined,\n\t): Promise<WorktreeSummarySnapshot> {\n\t\tif (cancellation?.aborted) throw new CancellationError();\n\n\t\tlet flight = this.getJoinableFlight(key);\n\t\tif (probeDirty) {\n\t\t\t// A read that won't re-read the dirty flag can't answer a caller that asked for it; wait it out, then read\n\t\t\t// again\n\t\t\twhile (flight != null && !flight.probeDirty) {\n\t\t\t\tconst waited = flight;\n\t\t\t\ttry {\n\t\t\t\t\tawait (cancellation != null ? raceWithSignal(waited.promise, cancellation) : waited.promise);\n\t\t\t\t} catch (ex) {\n\t\t\t\t\tif (cancellation?.aborted) throw ex;\n\t\t\t\t}\n\t\t\t\tflight = this.getJoinableFlight(key);\n\t\t\t\t// Settled, though its callers haven't all let go of it yet\n\t\t\t\tif (flight === waited) {\n\t\t\t\t\tflight = undefined;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// A subscription that started meanwhile answers instead, its summary following the working tree\n\t\t\tconst entry = this.entries.get(key);\n\t\t\tif (entry != null) return this.getSubscribedSnapshot(entry, true, cancellation);\n\t\t}\n\n\t\tif (flight == null) {\n\t\t\tflight = new UnwatchedFlight(key, probeDirty, this._disposed, f => this.readUnwatched(f));\n\t\t\tif (!this._disposed) {\n\t\t\t\tthis.unwatchedFlights.set(key, flight);\n\t\t\t}\n\t\t}\n\n\t\tconst current = flight;\n\t\tcurrent.callers++;\n\t\ttry {\n\t\t\tconst read = await (cancellation != null ? raceWithSignal(current.promise, cancellation) : current.promise);\n\t\t\treturn { summary: read.result.summary, dirtyReadAt: read.dirtyReadAt };\n\t\t} finally {\n\t\t\tcurrent.callers--;\n\t\t\t// Settled, or every caller gave up; either way a later caller starts a read of its own. Aborted even once\n\t\t\t// another read or a subscription took its place, which no caller waits on any longer\n\t\t\tif (current.callers === 0) {\n\t\t\t\tif (this.unwatchedFlights.get(key) === current) {\n\t\t\t\t\tthis.unwatchedFlights.delete(key);\n\t\t\t\t}\n\t\t\t\tcurrent.disposed = true;\n\t\t\t\tcurrent.abort.abort();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * The read in flight for `key`, unless core wrote a merge target or base while it ran: it may have read the stored\n\t * values before the write, and a caller after an awaited write sees them, as one of a subscribed worktree does\n\t */\n\tprivate getJoinableFlight(key: string): UnwatchedFlight | undefined {\n\t\tconst flight = this.unwatchedFlights.get(key);\n\t\treturn flight?.due === 0 ? flight : undefined;\n\t}\n\n\tprivate async readUnwatched(flight: UnwatchedFlight): Promise<UnwatchedRead> {\n\t\tconst { key } = flight;\n\t\tconst signal = flight.abort.signal;\n\t\tif (flight.disposed) throw new CancellationError();\n\n\t\t// A stale read's fields can't be trusted (see `queue`), so it is read again in full\n\t\tlet last = this.unwatchedReads.get(key);\n\t\tif (last?.result.summary.stale) {\n\t\t\tlast = undefined;\n\t\t}\n\n\t\ttry {\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\t// Core drops every remote's cached `HEAD` symref on any ref change, so after the first read only those the\n\t\t\t// base depends on are read, unless the base is read again\n\t\t\tconst headRemotes = last != null ? getHeadRemotes(last.result.summary.baseDependsOn) : undefined;\n\t\t\tconst probe = await this.probeUnwatched(repo, headRemotes, true, signal);\n\t\t\tif (flight.disposed) throw new CancellationError();\n\n\t\t\tlet fields: number;\n\t\t\tlet baseMoves: Set<string> | undefined;\n\t\t\tif (last == null) {\n\t\t\t\t// The config inputs too, so a later base move can be re-measured against the key they had\n\t\t\t\tfields = allFields | baseConfigField;\n\t\t\t} else {\n\t\t\t\t({ fields, baseMoves } = await getMovedFields(repo, last, probe, flight.probeDirty, signal));\n\t\t\t\tif (flight.disposed) throw new CancellationError();\n\n\t\t\t\tif (fields === 0) {\n\t\t\t\t\tthis.unwatchedReads.touch(key);\n\t\t\t\t\treturn last;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// A base read can come to depend on any remote's `HEAD`, so the rest are read too, before it like the other\n\t\t\t// inputs\n\t\t\tif (headRemotes != null && (fields & (baseField | baseKeysField | baseConfigField | baseMoveField)) !== 0) {\n\t\t\t\tawait readRemoteHeads(repo, probe.remoteHeads, undefined, signal);\n\t\t\t\tif (flight.disposed) throw new CancellationError();\n\t\t\t}\n\n\t\t\t// No read slot: like the one-off read it replaces, this is a caller's foreground read, which never waits\n\t\t\t// behind subscribed worktrees' runs\n\t\t\tlet result = await readSummary(\n\t\t\t\trepo,\n\t\t\t\tkey,\n\t\t\t\tfields,\n\t\t\t\tlast?.result.summary,\n\t\t\t\tlast?.result.baseKeys,\n\t\t\t\tlast?.result.baseConfigKey,\n\t\t\t\tlast?.result.baseDefaultBranch,\n\t\t\t\tbaseMoves,\n\t\t\t\tsignal,\n\t\t\t\tthis.verifyBaseRemeasure,\n\t\t\t);\n\n\t\t\t// Keep the summary the caller already has when nothing in it changed\n\t\t\tconst kept = last?.result.summary;\n\t\t\tif (kept != null && summariesEqual(kept, result.summary)) {\n\t\t\t\tresult = { ...result, summary: kept };\n\t\t\t}\n\t\t\tconst read: UnwatchedRead = {\n\t\t\t\tresult: result,\n\t\t\t\t// Without a last read every group was read, dirty included\n\t\t\t\tdirtyReadAt: result.dirtyReadAt ?? last?.dirtyReadAt ?? Date.now(),\n\t\t\t\tinputs: toUnwatchedInputs(probe, result.summary),\n\t\t\t\tdue: flight.due,\n\t\t\t};\n\t\t\tif (this.unwatchedFlights.get(key) === flight && !this.entries.has(key)) {\n\t\t\t\tthis.unwatchedReads.set(key, read);\n\t\t\t}\n\t\t\treturn read;\n\t\t} catch (ex) {\n\t\t\tif (!isCancellationError(ex) && this.unwatchedFlights.get(key) === flight) {\n\t\t\t\tthis.unwatchedReads.delete(key);\n\t\t\t}\n\t\t\tthrow ex;\n\t\t}\n\t}\n\n\t/**\n\t * Reads an unwatched read's inputs: cached answers but for the index file's stat (see {@link UnwatchedInputs}), with\n\t * the `HEAD` symrefs of `remotes` (every remote's when `undefined`); without `statIndex`, the index is unknown\n\t */\n\tprivate async probeUnwatched(\n\t\trepo: RepositoryService,\n\t\tremotes: ReadonlySet<string> | undefined,\n\t\tstatIndex: boolean,\n\t\tsignal: AbortSignal,\n\t): Promise<UnwatchedProbe> {\n\t\tconst remoteHeads = new Map<string, string | null | undefined>();\n\t\tconst stat = statIndex ? this.stat : undefined;\n\t\tconst [current, tips, gitDir] = await Promise.all([\n\t\t\trepo.branches.getBranch(undefined, undefined, signal),\n\t\t\trepo.refs.getRefTips(undefined, signal),\n\t\t\tstat != null ? getGitDir(repo) : undefined,\n\t\t\treadRemoteHeads(repo, remoteHeads, remotes, signal),\n\t\t]);\n\n\t\tlet index: string | undefined;\n\t\tif (stat != null && gitDir != null) {\n\t\t\ttry {\n\t\t\t\tconst stats = await stat(joinPaths(gitDir.uri.fsPath, 'index'));\n\t\t\t\tindex = stats != null ? `${stats.size}:${stats.mtime}` : '';\n\t\t\t} catch {\n\t\t\t\tindex = undefined;\n\t\t\t}\n\t\t}\n\n\t\tconst detached = current?.detached ?? false;\n\t\treturn {\n\t\t\tbranch: detached ? undefined : current?.name || undefined,\n\t\t\tdetached: detached,\n\t\t\tsha: current?.sha,\n\t\t\tupstream: current?.upstream?.name,\n\t\t\ttips: getTipsByName(tips),\n\t\t\tremoteHeads: remoteHeads,\n\t\t\tindex: index,\n\t\t};\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\t// Taken only now: until the watch is placed, core's write of a merge target or base skips the entry but still\n\t\t// makes the stored values due on the saved read. A stale one's fields can't be trusted (see `queue`)\n\t\tlet last = this.unwatchedReads.get(entry.key);\n\t\tthis.unwatchedReads.delete(entry.key);\n\t\tif (last?.result.summary.stale) {\n\t\t\tlast = undefined;\n\t\t}\n\t\tif (last != null) {\n\t\t\tentry.seed = last.result.summary;\n\t\t\t// The values its base read consulted, or the first `gk` config or config change would read the base again\n\t\t\tentry.baseKeys = last.result.baseKeys;\n\t\t\tentry.baseConfigKey = last.result.baseConfigKey;\n\t\t\tentry.baseDefaultBranch = last.result.baseDefaultBranch;\n\t\t} else {\n\t\t\tentry.pending |= allFields | baseConfigField;\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\t// Probed once listening, so a change landing meanwhile is queued against the seed rather than missed. Whether\n\t\t// the working-tree watch the listeners placed is still starting is asked now: should it go live during the\n\t\t// probe, the rescan it queues reads the dirty flag the first run would otherwise read too\n\t\tif (last != null) {\n\t\t\tawait this.queueSeedStart(entry, last, this.watchService.isWorkingTreeStarting(entry.key));\n\t\t\tif (entry.disposed) return;\n\t\t}\n\n\t\tawait this.drain(entry);\n\t}\n\n\t/**\n\t * Queues the groups of the saved read `last` whose inputs moved since, as an unwatched read finds them, and the\n\t * dirty flag, which no input vouches for; everything when its inputs can't be read. With `deferDirty`, the dirty\n\t * flag is left to the rescan of a working-tree watch still starting, and the value keeps `last`'s until then\n\t */\n\tprivate async queueSeedStart(entry: SummaryEntry, last: UnwatchedRead, deferDirty: boolean): Promise<void> {\n\t\tconst signal = entry.abort.signal;\n\t\tlet moved: { fields: number; baseMoves: Set<string> | undefined } | undefined;\n\t\ttry {\n\t\t\tconst repo = this.getRepository(entry.key);\n\t\t\tif (repo != null) {\n\t\t\t\t// No stat of the index: the dirty flag is read whatever it says\n\t\t\t\tconst probe = await this.probeUnwatched(\n\t\t\t\t\trepo,\n\t\t\t\t\tgetHeadRemotes(last.result.summary.baseDependsOn),\n\t\t\t\t\tfalse,\n\t\t\t\t\tsignal,\n\t\t\t\t);\n\t\t\t\tif (entry.disposed) return;\n\n\t\t\t\tmoved = await getMovedFields(repo, last, probe, true, signal);\n\t\t\t}\n\t\t} catch {\n\t\t\t// Unknown inputs, read in full below\n\t\t}\n\t\tif (entry.disposed) return;\n\n\t\tif (moved == null) {\n\t\t\tdropSeed(entry);\n\t\t\tentry.pending |= allFields | baseConfigField;\n\t\t\treturn;\n\t\t}\n\n\t\tif (deferDirty) {\n\t\t\t// A working-tree change queued meanwhile still reads it\n\t\t\tentry.pending |= moved.fields & ~dirtyField;\n\t\t\tentry.dirtyReadAt = last.dirtyReadAt;\n\t\t\t// Cleared with `dirtyReadAt`, so it fires only while the saved flag is still shown\n\t\t\tentry.dirtyReadTimer = setTimeout(() => {\n\t\t\t\tentry.dirtyReadTimer = undefined;\n\t\t\t\tthis.queue(entry, dirtyField);\n\t\t\t}, maxDeferredDirtyMs);\n\t\t\t// Nothing to read before the watch goes live: the saved read is the first value as it is\n\t\t\tif (entry.pending === 0 && entry.seed != null) {\n\t\t\t\tconst seed = entry.seed;\n\t\t\t\tentry.error = undefined;\n\t\t\t\tentry.seed = undefined;\n\t\t\t\tentry.value = seed;\n\t\t\t\tthis.fireChange(entry, seed);\n\t\t\t}\n\t\t} else {\n\t\t\tentry.pending |= moved.fields;\n\t\t}\n\t\tif (moved.baseMoves != null) {\n\t\t\tentry.baseMoves ??= new Set();\n\t\t\tfor (const ref of moved.baseMoves) {\n\t\t\t\tentry.baseMoves.add(ref);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate onRepoChanged(entry: SummaryEntry, e: WatcherRepoChangeEvent): void {\n\t\tconst value = entry.value ?? entry.seed;\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 they're read again:\n\t\t\t// with everything when there's no saved read to start from, else compared with that read's\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\tif (!this.isInRepository(entry.key, e.repoPath)) continue;\n\n\t\t\tthis.queue(entry, baseKeysField);\n\t\t}\n\n\t\t// No ref moves for such a write, so a worktree without a subscription re-reads the stored values on its next read\n\t\tfor (const read of this.unwatchedReads.values()) {\n\t\t\tconst value = read.result.summary;\n\t\t\tif (value.branch == null || (e.refs != null && !e.refs.has(value.branch))) continue;\n\t\t\tif (!this.isInRepository(value.repoPath, e.repoPath)) continue;\n\n\t\t\tread.due |= baseKeysField;\n\t\t}\n\t\t// One in flight may have read them before the write, so it takes no more callers; its branch isn't known yet,\n\t\t// so any of the repository's\n\t\tfor (const flight of this.unwatchedFlights.values()) {\n\t\t\tif (!this.isInRepository(flight.key, e.repoPath)) continue;\n\n\t\t\tflight.due |= baseKeysField;\n\t\t}\n\t}\n\n\tprivate isInRepository(key: string, commonPath: string): boolean {\n\t\tconst path = this.getCommonPath?.(key);\n\t\treturn path == null || path === commonPath;\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 (or a saved read to start from) a partial read has nothing to merge into, and a stale value's\n\t\t// fields can't be trusted: a partial read would clear `stale` while vouching for groups it never re-read\n\t\tconst value = entry.value ?? entry.seed;\n\t\tentry.pending |= value == null || 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 { value, seed } = entry;\n\t\tconst previous = value ?? seed;\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.seed = 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\t// Any read of the dirty flag ends showing the saved one, even one a branch read adds on finding another branch\n\t\tconst dirtyConfirmed = result.dirtyReadAt != null && entry.dirtyReadAt != null;\n\t\tif (dirtyConfirmed) {\n\t\t\tclearDeferredDirty(entry);\n\t\t}\n\t\tif (value != null && summariesEqual(value, result.summary)) {\n\t\t\t// Unchanged, but no longer the saved read's\n\t\t\tif (dirtyConfirmed) {\n\t\t\t\tthis.fireChange(entry, value);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// The first value is published even when it reads as the seed, as the seed's own object for a host that has it\n\t\tconst summary = value == null && seed != null && summariesEqual(seed, result.summary) ? seed : result.summary;\n\t\tentry.value = summary;\n\t\tthis.fireChange(entry, 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.seed != null) {\n\t\t\t\tdropSeed(entry);\n\t\t\t\t// Changes during the run were queued against the seed; without one they read everything\n\t\t\t\tif (entry.pending !== 0) {\n\t\t\t\t\tentry.pending |= allFields | baseConfigField;\n\t\t\t\t}\n\t\t\t}\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.seed = undefined;\n\t\tclearDeferredDirty(entry);\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\n/** Drops the saved read a first run was to start from, with the values its base read consulted and its dirty flag */\nfunction dropSeed(entry: SummaryEntry): void {\n\tentry.seed = undefined;\n\tclearDeferredDirty(entry);\n\tentry.baseKeys = undefined;\n\tentry.baseConfigKey = undefined;\n\tentry.baseDefaultBranch = undefined;\n}\n\nfunction clearDeferredDirty(entry: SummaryEntry): void {\n\tentry.dirtyReadAt = undefined;\n\tclearTimeout(entry.dirtyReadTimer);\n\tentry.dirtyReadTimer = undefined;\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\tseed: undefined,\n\t\tdirtyReadAt: undefined,\n\t\tdirtyReadTimer: 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 dirtyReadAt: number | undefined;\n\tconst startDirtyRead = (): Promise<boolean> => {\n\t\tdirtyReadAt = Date.now();\n\t\treturn readDirty(repo, signal);\n\t};\n\tlet dirtyRead = fields & dirtyField ? startDirtyRead() : 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 ??= startDirtyRead();\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\tdirtyReadAt: dirtyReadAt,\n\t};\n}\n\nasync function getGitDir(repo: RepositoryService): Promise<GitDir | undefined> {\n\ttry {\n\t\treturn await repo.config.getGitDir?.();\n\t} catch (ex) {\n\t\tif (isCancellationError(ex)) throw ex;\n\n\t\treturn undefined;\n\t}\n}\n\n/** Each ref list's tips by full name, built once per list, which core's cache shares across a repository's worktrees */\nconst tipsByNameCache = new WeakMap<readonly GitRefTip[], ReadonlyMap<string, string>>();\n\nfunction getTipsByName(tips: readonly GitRefTip[]): ReadonlyMap<string, string> {\n\tlet byName = tipsByNameCache.get(tips);\n\tif (byName == null) {\n\t\tconst map = new Map<string, string>();\n\t\tfor (const tip of tips) {\n\t\t\tmap.set(tip.fullName, tip.sha);\n\t\t}\n\t\tbyName = map;\n\t\ttipsByNameCache.set(tips, byName);\n\t}\n\treturn byName;\n}\n\n/**\n * The read groups due on a read from `last`, given what `probe` found of its inputs since (with the refs the base\n * depends on that moved): those `last` made due, and those whose inputs moved\n */\nasync function getMovedFields(\n\trepo: RepositoryService,\n\tlast: UnwatchedRead,\n\tprobe: UnwatchedProbe,\n\tprobeDirty: boolean,\n\tsignal: AbortSignal,\n): Promise<{ fields: number; baseMoves: Set<string> | undefined }> {\n\tlet fields = last.due;\n\tlet baseMoves: Set<string> | undefined;\n\tconst { inputs } = last;\n\tconst previous = last.result.summary;\n\tif (probe.branch !== inputs.branch || probe.detached !== inputs.detached || probe.sha !== inputs.sha) {\n\t\t// The branch read only widens to the rest for a different branch, but a commit moves the base count and can\n\t\t// leave the working tree clean\n\t\tfields |= allFields;\n\t} else {\n\t\tif (probe.upstream !== inputs.upstream) {\n\t\t\t// The config inputs too, which read the base again when the upstream's identity changed\n\t\t\tfields |= branchField | baseConfigField;\n\t\t} else if (getUpstreamTips(probe.tips, probe.upstream) !== inputs.upstreamTips) {\n\t\t\tfields |= branchField;\n\t\t}\n\t\tfor (const ref of previous.baseDependsOn) {\n\t\t\t// An unreadable value is unknown, so it moved\n\t\t\tconst value = getBaseInput(probe, ref);\n\t\t\tif (value !== null && value === inputs.baseTips.get(ref)) continue;\n\n\t\t\tbaseMoves ??= new Set();\n\t\t\tbaseMoves.add(ref);\n\t\t}\n\t\tif (baseMoves != null) {\n\t\t\tfields |= baseMoveField;\n\t\t}\n\t\t// A config write the base read consulted (another branch's tracking, a remote, the default branch) moves no\n\t\t// ref; one cached read, as a subscribed worktree's config change reads\n\t\tif (\n\t\t\t(fields & baseConfigField) === 0 &&\n\t\t\tlast.result.baseConfigKey != null &&\n\t\t\trepo.branches.getAheadOfBase != null &&\n\t\t\t(probe.detached || probe.branch != null)\n\t\t) {\n\t\t\tconst configKey = getBaseConfigKey(await readBaseConfig(repo, signal), previous);\n\t\t\t// An unreadable config is unknown, not changed\n\t\t\tif (configKey != null && configKey !== last.result.baseConfigKey) {\n\t\t\t\tfields |= branchField | baseConfigField;\n\t\t\t}\n\t\t}\n\t}\n\tif (probeDirty || probe.index == null || probe.index !== inputs.index) {\n\t\tfields |= dirtyField;\n\t}\n\treturn { fields: fields, baseMoves: baseMoves };\n}\n\n/** The upstream's tips as a remote-tracking and as a local branch, since its short name doesn't say which */\nfunction getUpstreamTips(tips: ReadonlyMap<string, string>, upstream: string | undefined): string | undefined {\n\tif (upstream == null) return undefined;\n\n\treturn `${tips.get(`refs/remotes/${upstream}`) ?? ''}\\0${tips.get(`refs/heads/${upstream}`) ?? ''}`;\n}\n\n/**\n * Reads where the `HEAD` symref of each of `remotes` (every remote's when `undefined`) points (`origin/main`) into\n * `heads`, as core's cached local reads answer it, skipping those already there: `undefined` when it has none (a\n * remote since removed included), `null` when the read failed\n */\nasync function readRemoteHeads(\n\trepo: RepositoryService,\n\theads: Map<string, string | null | undefined>,\n\tremotes: ReadonlySet<string> | undefined,\n\tsignal: AbortSignal,\n): Promise<void> {\n\tif (remotes?.size === 0) return;\n\n\tconst names = remotes ?? (await repo.remotes.getRemotes(undefined, signal)).map(r => r.name);\n\tawait Promise.all(\n\t\tArray.from(names, async name => {\n\t\t\tif (heads.has(name)) return;\n\n\t\t\tlet target: string | null | undefined;\n\t\t\ttry {\n\t\t\t\ttarget = await repo.branches.getDefaultBranchName(name, { local: true }, signal);\n\t\t\t} catch (ex) {\n\t\t\t\tif (isCancellationError(ex)) throw ex;\n\n\t\t\t\ttarget = null;\n\t\t\t}\n\t\t\theads.set(name, target);\n\t\t}),\n\t);\n}\n\n/** The remote whose `HEAD` symref `ref` is; `undefined` for any other ref */\nfunction getHeadRemote(ref: string): string | undefined {\n\tif (!ref.startsWith('refs/remotes/') || !ref.endsWith('/HEAD')) return undefined;\n\n\t// A remote name can hold a slash, so the remote is everything between\n\treturn ref.slice('refs/remotes/'.length, -'/HEAD'.length);\n}\n\n/** The remotes whose `HEAD` symref is among `refs` */\nfunction getHeadRemotes(refs: readonly string[]): Set<string> {\n\tconst remotes = new Set<string>();\n\tfor (const ref of refs) {\n\t\tconst remote = getHeadRemote(ref);\n\t\tif (remote != null) {\n\t\t\tremotes.add(remote);\n\t\t}\n\t}\n\treturn remotes;\n}\n\n/**\n * What `probe` found of `ref`, a ref the base depends on: for a remote's `HEAD` symref, which the ref tips leave out,\n * the ref it points at, since its tip follows that ref's, itself a dependency; else its tip. `null` for a symref of a\n * remote it didn't read: only when the read found HEAD elsewhere than the probe did and read the base for that, which\n * the next probe sees as HEAD moving anyway\n */\nfunction getBaseInput(probe: UnwatchedProbe, ref: string): string | null | undefined {\n\tconst remote = getHeadRemote(ref);\n\tif (remote == null) return probe.tips.get(ref);\n\n\treturn probe.remoteHeads.has(remote) ? probe.remoteHeads.get(remote) : null;\n}\n\n/** The inputs `summary` was read from, as the probe before its read found them */\nfunction toUnwatchedInputs(probe: UnwatchedProbe, summary: WorktreeSummary): UnwatchedInputs {\n\tconst baseTips = new Map<string, string | null | undefined>();\n\tfor (const ref of summary.baseDependsOn) {\n\t\tbaseTips.set(ref, getBaseInput(probe, ref));\n\t}\n\treturn {\n\t\tbranch: probe.branch,\n\t\tdetached: probe.detached,\n\t\tsha: probe.sha,\n\t\tupstream: probe.upstream,\n\t\tupstreamTips: getUpstreamTips(probe.tips, probe.upstream),\n\t\tbaseTips: baseTips,\n\t\tindex: probe.index,\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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"}
@@ -504,10 +504,10 @@ var CliGitProvider = class {
504
504
  repoPath,
505
505
  gitDirPath,
506
506
  fs: this.context.fs,
507
- getGlobalExcludesPath: this.config.getConfig != null ? async () => {
508
- const configured = await this.config.getConfig(repoPath, "core.excludesFile");
507
+ getGlobalExcludesPath: async () => {
508
+ const { excludesFile: configured } = await this.config.getIgnoreConfig(repoPath);
509
509
  return configured != null ? resolveGitPathConfig(configured, repoPath) : getDefaultGlobalExcludesPath();
510
- } : void 0,
510
+ },
511
511
  getInfoExcludePath: async () => {
512
512
  const gitDir = await this.config.getGitDir?.(repoPath);
513
513
  if (gitDir == null) return void 0;
@@ -515,7 +515,7 @@ var CliGitProvider = class {
515
515
  },
516
516
  getGitIgnorePaths: () => this.getGitIgnorePaths(repoPath),
517
517
  getIgnoreCase: async () => {
518
- const value = await this.config.getConfig?.(repoPath, "core.ignorecase");
518
+ const { ignoreCase: value } = await this.config.getIgnoreConfig(repoPath);
519
519
  if (value == null) return void 0;
520
520
  if (parseGitBoolean(value)) return true;
521
521
  return isGitBooleanFalse(value) ? false : void 0;