@gitkraken/core-gitlens 0.24.0 → 0.26.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.
- package/CHANGELOG.md +40 -1
- package/README.md +23 -15
- package/dist/git/errors.d.ts +6 -5
- package/dist/git/errors.js +7 -6
- package/dist/git/errors.js.map +1 -1
- package/dist/git/features.d.ts +1 -1
- package/dist/git/features.js +1 -1
- package/dist/git/features.js.map +1 -1
- package/dist/git/models/remoteProvider.d.ts +4 -1
- package/dist/git/models/remoteProvider.js.map +1 -1
- package/dist/git/providers/operations.d.ts +15 -0
- package/dist/git/providers/provider.d.ts +4 -2
- package/dist/git/utils/branch.utils.d.ts +4 -1
- package/dist/git/utils/branch.utils.js +5 -2
- package/dist/git/utils/branch.utils.js.map +1 -1
- package/dist/git/utils/mergeConflicts.utils.js +2 -2
- package/dist/git/utils/mergeConflicts.utils.js.map +1 -1
- package/dist/git/watching/worktreeSummary.d.ts +15 -3
- package/dist/git/watching/worktreeSummary.js +179 -31
- package/dist/git/watching/worktreeSummary.js.map +1 -1
- package/dist/git-cli/cliGitProvider.d.ts +30 -3
- package/dist/git-cli/cliGitProvider.js +102 -40
- package/dist/git-cli/cliGitProvider.js.map +1 -1
- package/dist/git-cli/exec/git.d.ts +9 -1
- package/dist/git-cli/exec/git.js +23 -4
- package/dist/git-cli/exec/git.js.map +1 -1
- package/dist/git-cli/exec/gitDirResolver.d.ts +26 -0
- package/dist/git-cli/exec/gitDirResolver.js +181 -0
- package/dist/git-cli/exec/gitDirResolver.js.map +1 -0
- package/dist/git-cli/exec/headState.js +3 -3
- package/dist/git-cli/exec/headState.js.map +1 -1
- package/dist/git-cli/exec/indexRefresh.d.ts +78 -0
- package/dist/git-cli/exec/indexRefresh.js +159 -0
- package/dist/git-cli/exec/indexRefresh.js.map +1 -0
- package/dist/git-cli/providers/branchRemote.js +2 -5
- package/dist/git-cli/providers/branchRemote.js.map +1 -1
- package/dist/git-cli/providers/branches.js +4 -4
- package/dist/git-cli/providers/branches.js.map +1 -1
- package/dist/git-cli/providers/config.d.ts +2 -0
- package/dist/git-cli/providers/config.js +26 -4
- package/dist/git-cli/providers/config.js.map +1 -1
- package/dist/git-cli/providers/maintenance.js +1 -1
- package/dist/git-cli/providers/operations.d.ts +4 -1
- package/dist/git-cli/providers/operations.js +33 -25
- package/dist/git-cli/providers/operations.js.map +1 -1
- package/dist/git-cli/providers/pausedOperations.d.ts +3 -1
- package/dist/git-cli/providers/pausedOperations.js +10 -7
- package/dist/git-cli/providers/pausedOperations.js.map +1 -1
- package/dist/git-cli/providers/refs.js +25 -1
- package/dist/git-cli/providers/refs.js.map +1 -1
- package/dist/git-cli/providers/staging.js +1 -1
- package/dist/git-cli/providers/stash.d.ts +3 -1
- package/dist/git-cli/providers/stash.js +8 -5
- package/dist/git-cli/providers/stash.js.map +1 -1
- package/dist/git-cli/providers/worktrees.d.ts +6 -1
- package/dist/git-cli/providers/worktrees.js +6 -2
- package/dist/git-cli/providers/worktrees.js.map +1 -1
- package/dist/git-cli/service.d.ts +2 -0
- package/dist/git-cli/service.js +2 -1
- package/dist/git-cli/service.js.map +1 -1
- package/dist/ipc/discovery.js +1 -1
- package/dist/plus/agents/providers/claudeCodeTranscript.js +6 -6
- package/dist/plus/agents/providers/claudeCodeTranscript.js.map +1 -1
- package/dist/plus/ai/errors.d.ts +4 -1
- package/dist/plus/ai/errors.js +4 -0
- package/dist/plus/ai/errors.js.map +1 -1
- package/dist/plus/ai/providers/mistralProvider.js +1 -1
- package/dist/plus/ai/providers/mistralProvider.js.map +1 -1
- package/dist/plus/ai/providers/openAICompatibleProviderBase.js +2 -1
- package/dist/plus/ai/providers/openAICompatibleProviderBase.js.map +1 -1
- package/dist/plus/git-github/api/github.js +12 -13
- package/dist/plus/git-github/api/github.js.map +1 -1
- package/dist/plus/git-github/api/token.d.ts +2 -0
- package/dist/plus/integrations/authentication/cloudIntegrationService.d.ts +1 -1
- package/dist/plus/integrations/authentication/cloudIntegrationService.js +6 -1
- package/dist/plus/integrations/authentication/cloudIntegrationService.js.map +1 -1
- package/dist/plus/integrations/authentication/configuredIntegrationService.js +2 -2
- package/dist/plus/integrations/authentication/integrationAuthenticationProvider.js +18 -5
- package/dist/plus/integrations/authentication/integrationAuthenticationProvider.js.map +1 -1
- package/dist/plus/integrations/authentication/integrationAuthenticationService.d.ts +3 -1
- package/dist/plus/integrations/authentication/integrationAuthenticationService.js +4 -0
- package/dist/plus/integrations/authentication/integrationAuthenticationService.js.map +1 -1
- package/dist/plus/integrations/authentication/models.d.ts +2 -0
- package/dist/plus/integrations/authentication/models.js +2 -1
- package/dist/plus/integrations/authentication/models.js.map +1 -1
- package/dist/plus/integrations/authentication/observedAuthenticationProvider.js +1 -1
- package/dist/plus/integrations/authentication/rejectedTokenTracker.d.ts +5 -4
- package/dist/plus/integrations/authentication/rejectedTokenTracker.js +5 -4
- package/dist/plus/integrations/authentication/rejectedTokenTracker.js.map +1 -1
- package/dist/plus/integrations/index.d.ts +2 -2
- package/dist/plus/integrations/index.js +1 -1
- package/dist/plus/integrations/index.js.map +1 -1
- package/dist/plus/integrations/integrationService.d.ts +6 -0
- package/dist/plus/integrations/integrationService.js +3 -3
- package/dist/plus/integrations/integrationService.js.map +1 -1
- package/dist/plus/integrations/lite.js +1 -1
- package/dist/plus/integrations/manager.d.ts +51 -3
- package/dist/plus/integrations/models/gitHostIntegration.d.ts +14 -0
- package/dist/plus/integrations/models/gitHostIntegration.js +50 -41
- package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
- package/dist/plus/integrations/models/integration.d.ts +27 -5
- package/dist/plus/integrations/models/integration.js +57 -15
- package/dist/plus/integrations/models/integration.js.map +1 -1
- package/dist/plus/integrations/models/issueReads.d.ts +6 -0
- package/dist/plus/integrations/models/issuesIntegration.js +11 -11
- package/dist/plus/integrations/models/issuesIntegration.js.map +1 -1
- package/dist/plus/integrations/providers/azure/azure.js +2 -2
- package/dist/plus/integrations/providers/azureDevOps.js +1 -1
- package/dist/plus/integrations/providers/azureDevOpsServer.js +1 -1
- package/dist/plus/integrations/providers/bitbucket/bitbucket.js +1 -1
- package/dist/plus/integrations/providers/bitbucket/bitbucket.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket-server.js +1 -1
- package/dist/plus/integrations/providers/bitbucket.js +1 -1
- package/dist/plus/integrations/providers/github.js +1 -1
- package/dist/plus/integrations/providers/gitlab/gitlab.js +2 -2
- package/dist/plus/integrations/providers/gitlab/gitlab.js.map +1 -1
- package/dist/plus/integrations/providers/gitlab.js +1 -1
- package/dist/plus/integrations/providers/jira-server.js +2 -2
- package/dist/plus/integrations/providers/jira.js +1 -1
- package/dist/plus/integrations/providers/linear.js +2 -2
- package/dist/plus/integrations/providers/linear.js.map +1 -1
- package/dist/plus/integrations/providers/models.js +2 -1
- package/dist/plus/integrations/providers/models.js.map +1 -1
- package/dist/plus/integrations/providers/providerErrors.js +9 -0
- package/dist/plus/integrations/providers/providerErrors.js.map +1 -1
- package/dist/plus/integrations/providers/providersApi.js +1 -1
- package/dist/plus/integrations/providers/trello.js +1 -1
- package/dist/plus/integrations/providers/utils.js +1 -1
- package/dist/plus/integrations/reads/counts.js +1 -1
- package/dist/plus/integrations/reads/cursors.js +1 -1
- package/dist/plus/integrations/reads/drains.d.ts +5 -4
- package/dist/plus/integrations/reads/drains.js +28 -8
- package/dist/plus/integrations/reads/drains.js.map +1 -1
- package/dist/plus/integrations/reads/hierarchy.js +1 -1
- package/dist/plus/integrations/reads/issueBatch.d.ts +1 -1
- package/dist/plus/integrations/reads/issueBatch.js.map +1 -1
- package/dist/plus/integrations/reads/issueTracker.js +1 -1
- package/dist/plus/integrations/reads/issues.d.ts +2 -0
- package/dist/plus/integrations/reads/issues.js +5 -3
- package/dist/plus/integrations/reads/issues.js.map +1 -1
- package/dist/plus/integrations/reads/paging.d.ts +5 -6
- package/dist/plus/integrations/reads/paging.js +5 -6
- package/dist/plus/integrations/reads/paging.js.map +1 -1
- package/dist/plus/integrations/reads/pullRequests.d.ts +4 -0
- package/dist/plus/integrations/reads/pullRequests.js +4 -2
- package/dist/plus/integrations/reads/pullRequests.js.map +1 -1
- package/dist/plus/integrations/reads/resolveRepository.js +1 -1
- package/dist/plus/integrations/reads/sweeps.js +42 -10
- package/dist/plus/integrations/reads/sweeps.js.map +1 -1
- package/dist/plus/integrations/results.d.ts +23 -3
- package/dist/plus/integrations/results.js.map +1 -1
- package/dist/plus/notifications/api.d.ts +20 -0
- package/dist/plus/notifications/api.js +89 -0
- package/dist/plus/notifications/api.js.map +1 -0
- package/dist/plus/notifications/context.d.ts +28 -0
- package/dist/plus/notifications/context.js +0 -0
- package/dist/plus/notifications/errors.d.ts +13 -0
- package/dist/plus/notifications/errors.js +22 -0
- package/dist/plus/notifications/errors.js.map +1 -0
- package/dist/plus/notifications/models.d.ts +94 -0
- package/dist/plus/notifications/models.js +0 -0
- package/dist/plus/notifications/notificationsService.d.ts +115 -0
- package/dist/plus/notifications/notificationsService.js +381 -0
- package/dist/plus/notifications/notificationsService.js.map +1 -0
- package/dist/plus/notifications/parse.d.ts +12 -0
- package/dist/plus/notifications/parse.js +152 -0
- package/dist/plus/notifications/parse.js.map +1 -0
- package/dist/plus/notifications/presentation.d.ts +28 -0
- package/dist/plus/notifications/presentation.js +55 -0
- package/dist/plus/notifications/presentation.js.map +1 -0
- package/dist/utils/env/node/exec.d.ts +10 -1
- package/dist/utils/env/node/exec.js +41 -4
- package/dist/utils/env/node/exec.js.map +1 -1
- package/docs/integrations.md +21 -2
- package/docs/notifications.md +239 -0
- package/package.json +21 -1
|
@@ -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, 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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"}
|
|
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 { GitBranch, 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/**\n * Checks the summary against what a probe finds now, for a change that may have moved one of its refs without naming it\n * (a packed-refs rewrite, a ref directory, an overflow or a poll): HEAD, the upstream and the counts against it as\n * `getBranch` answers them, and the refs the base depends on against the tips it was read from (see {@link ReadTips});\n * reads the groups that moved, as an unwatched read would — everything when HEAD's branch or commit did — and nothing\n * when none did\n */\nconst tipCheckField = 64;\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([]);\nconst noRemotes: ReadonlySet<string> = new Set();\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\t/** The read groups it read, as widened along the way */\n\treadonly fields: number;\n}\n\n/**\n * Probes a subscribed read's inputs once its dirty read started, and before its branch and base reads, given the groups\n * due and the refs the base depends on that moved; returns them as the probe widened them, with HEAD as it read it\n * (absent when it didn't), which the branch read then takes\n */\ntype ReadProbe = (\n\tfields: number,\n\tbaseMoves: ReadonlySet<string> | undefined,\n) => Promise<{\n\treadonly fields: number;\n\treadonly baseMoves: ReadonlySet<string> | undefined;\n\treadonly head?: { readonly branch: GitBranch | undefined };\n}>;\n\n/**\n * The tips a subscribed worktree's summary was read from, taken by a probe just before its base was last read, so a\n * change landing during a read leaves them looking older than the disk and the next tip check reads what it moved. HEAD,\n * the upstream and the counts against it aren't kept: the summary itself, read from `getBranch`, has them for a tip\n * check to compare.\n */\ninterface ReadTips {\n\t/**\n\t * What each ref the base depends on was as of the last base read (see {@link getBaseInput}); `undefined` when\n\t * unknown (a base read no probe came before)\n\t */\n\treadonly base: ReadonlyMap<string, string | null | undefined> | 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 a probe finds of the refs (see {@link probeRefs}) */\ninterface ProbedRefs {\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}\n\n/** What an unwatched read finds of its inputs before it reads */\ninterface UnwatchedProbe extends ProbedRefs {\n\t/** HEAD as `getBranch` answered it */\n\treadonly current: GitBranch | undefined;\n\treadonly branch: string | undefined;\n\treadonly detached: boolean;\n\treadonly sha: string | undefined;\n\treadonly upstream: string | 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/** The tips the value (or the saved read) was read from, for a tip check; `undefined` before any were taken */\n\ttips: ReadTips | 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. A change that may have moved one\n * of those refs without naming it (a packed-refs rewrite, as deleting a packed branch makes, a ref directory, an\n * overflow or a poll) first checks HEAD, the upstream and the counts against it as core's cached `getBranch` answers\n * them, and the tips the base was read from against core's cached ref list, both shared by the repository's\n * checkouts, and reads only the groups that moved, by the same rules — nothing when none did.\n * Stash, unrelated tags and branches, and the like read nothing. One run is in flight per worktree at a time, at most\n * four per repository (the 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 stat = statIndex ? this.stat : undefined;\n\t\tconst [current, refs, gitDir] = await Promise.all([\n\t\t\trepo.branches.getBranch(undefined, undefined, signal),\n\t\t\tprobeRefs(repo, remotes, signal),\n\t\t\tstat != null ? getGitDir(repo) : undefined,\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\tcurrent: current,\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: refs.tips,\n\t\t\tremoteHeads: refs.remoteHeads,\n\t\t\tindex: index,\n\t\t};\n\t}\n\n\t/**\n\t * A subscribed run's {@link ReadProbe}, from cached answers: HEAD when the branch is due or a tip check is, the ref\n\t * tips (kept in `probed`), and the `HEAD` symrefs of the remotes the base depends on when the base may be read or a\n\t * tip check is due — every remote's for a first read, which can come to depend on any. A tip check widens `fields` as\n\t * {@link getTipCheckFields} finds, and is read in full when the probe fails; any other probe that fails leaves\n\t * the tips its groups read unknown.\n\t */\n\tprivate async probeRead(\n\t\trepo: RepositoryService,\n\t\tprevious: WorktreeSummary | undefined,\n\t\ttips: ReadTips | undefined,\n\t\tfields: number,\n\t\tbaseMoves: ReadonlySet<string> | undefined,\n\t\tprobed: { refs?: ProbedRefs },\n\t\tsignal: AbortSignal,\n\t): Promise<Awaited<ReturnType<ReadProbe>>> {\n\t\t// Nothing to check against without a value, nor anything left to widen to with every group due\n\t\tconst check = (fields & tipCheckField) !== 0 && previous != null && (fields & allFields) !== allFields;\n\t\tfields &= ~tipCheckField;\n\n\t\tconst remotes =\n\t\t\tprevious == null\n\t\t\t\t? undefined\n\t\t\t\t: check || (fields & (baseField | baseMoveField | baseKeysField | baseConfigField)) !== 0\n\t\t\t\t\t? getHeadRemotes(previous.baseDependsOn)\n\t\t\t\t\t: noRemotes;\n\t\ttry {\n\t\t\tif (!check && (fields & branchField) === 0) {\n\t\t\t\tprobed.refs = await probeRefs(repo, remotes, signal);\n\t\t\t\treturn { fields: fields, baseMoves: baseMoves };\n\t\t\t}\n\n\t\t\tconst probe = await this.probeUnwatched(repo, remotes, false, signal);\n\t\t\tprobed.refs = probe;\n\t\t\tconst head = { branch: probe.current };\n\t\t\tif (!check) return { fields: fields, baseMoves: baseMoves, head: head };\n\n\t\t\tconst moved = getTipCheckFields(probe, previous, tips);\n\t\t\tif (moved.baseMoves != null && baseMoves != null) {\n\t\t\t\tfor (const ref of baseMoves) {\n\t\t\t\t\tmoved.baseMoves.add(ref);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn { fields: fields | moved.fields, baseMoves: moved.baseMoves ?? baseMoves, head: head };\n\t\t} catch (ex) {\n\t\t\tif (isCancellationError(ex)) throw ex;\n\n\t\t\tprobed.refs = undefined;\n\t\t\treturn { fields: check ? fields | allFields : fields, baseMoves: baseMoves };\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\t// The tips the saved read was read from: the newer ones the probe below finds are of groups it queues unread\n\t\t\tentry.tips = { base: last.inputs.baseTips };\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\t// A ref that only may have moved — its kind changed without names (a packed-refs rewrite, an overflow, a poll), or\n\t\t// a directory above it changed — is checked against the tips it was read from, when the run starts\n\t\tif (value.branch != null) {\n\t\t\tconst ref = `refs/heads/${value.branch}`;\n\t\t\tif (e.mayHaveChangedRef(ref)) {\n\t\t\t\tfields |= isNamedRef(e, ref) ? allFields : tipCheckField;\n\t\t\t}\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 (value.upstream != null) {\n\t\t\tconst remoteRef = `refs/remotes/${value.upstream.name}`;\n\t\t\tif (e.mayHaveChangedRef(remoteRef)) {\n\t\t\t\tfields |= isNamedRef(e, remoteRef) ? branchField : tipCheckField;\n\t\t\t}\n\t\t\tconst localRef = `refs/heads/${value.upstream.name}`;\n\t\t\tif (e.mayHaveChangedRef(localRef)) {\n\t\t\t\tfields |= isNamedRef(e, localRef) ? branchField : tipCheckField;\n\t\t\t}\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\tif (!isNamedRef(e, ref)) {\n\t\t\t\t\tfields |= tipCheckField;\n\t\t\t\t\tcontinue;\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, tips } = entry;\n\t\tconst previous = value ?? seed;\n\t\t// Fields queued during the run that left the value stale were queued against one whose groups could be trusted;\n\t\t// read partially now, they'd clear `stale` while vouching for groups never re-read (see `queue`)\n\t\tif (previous?.stale) {\n\t\t\tfields |= allFields | baseConfigField;\n\t\t}\n\n\t\tconst probed: { refs?: ProbedRefs } = {};\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\tconst signal = entry.abort.signal;\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\tsignal,\n\t\t\t\tthis.verifyBaseRemeasure,\n\t\t\t\t(due, moves) => this.probeRead(repo, previous, tips, due, moves, probed, signal),\n\t\t\t);\n\t\t} catch (ex) {\n\t\t\tif (entry.disposed || isCancellationError(ex)) return;\n\n\t\t\tthis.fail(entry, ex);\n\t\t\treturn;\n\t\t}\n\t\tif (entry.disposed) return;\n\n\t\tif (result.summary.stale && (previous == null || !previous.stale)) {\n\t\t\tLogger.warn(\n\t\t\t\t`WorktreeSummaryService: reading the base of '${entry.key}' failed: ${String(result.baseError)}`,\n\t\t\t);\n\t\t}\n\n\t\tentry.error = undefined;\n\t\tentry.seed = undefined;\n\t\tentry.tips = getReadTips(tips, probed.refs, result);\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.tips = 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\tentry.tips = 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\ttips: 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\tprobe?: ReadProbe,\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 head: { readonly branch: GitBranch | undefined } | undefined;\n\tif (probe != null && fields & (branchField | baseField | baseMoveField | tipCheckField)) {\n\t\tconst probed = await probe(fields, baseMoves);\n\t\t({ fields, baseMoves, head } = probed);\n\t\tif (fields & dirtyField) {\n\t\t\tdirtyRead ??= startDirtyRead();\n\t\t}\n\t}\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 = head != null ? head.branch : 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\tfields: fields,\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/**\n * Reads the ref tips and the `HEAD` symrefs of `remotes` (every remote's when `undefined`), as core's caches answer\n * them: one ref list shared by the repository's worktrees\n */\nasync function probeRefs(\n\trepo: RepositoryService,\n\tremotes: ReadonlySet<string> | undefined,\n\tsignal: AbortSignal,\n): Promise<ProbedRefs> {\n\tconst remoteHeads = new Map<string, string | null | undefined>();\n\tconst [tips] = await Promise.all([\n\t\trepo.refs.getRefTips(undefined, signal),\n\t\treadRemoteHeads(repo, remoteHeads, remotes, signal),\n\t]);\n\treturn { tips: getTipsByName(tips), remoteHeads: remoteHeads };\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\tfields |= getUpstreamFields(probe.current, previous);\n\t\tif (probe.upstream !== inputs.upstream) {\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\tbaseMoves = getMovedBaseRefs(probe, previous.baseDependsOn, inputs.baseTips);\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/**\n * The read groups a tip check (see {@link tipCheckField}) finds moved since `previous` was read, with the refs the base\n * depends on as `tips` has them: everything when HEAD's branch or commit isn't the one `previous` has, else those\n * {@link getUpstreamFields} finds, and the base's refs that moved\n */\nfunction getTipCheckFields(\n\tprobe: UnwatchedProbe,\n\tprevious: WorktreeSummary,\n\ttips: ReadTips | undefined,\n): { fields: number; baseMoves: Set<string> | undefined } {\n\tif (probe.branch !== previous.branch || probe.detached !== previous.detached || probe.sha !== previous.sha) {\n\t\treturn { fields: allFields, baseMoves: undefined };\n\t}\n\n\tlet fields = getUpstreamFields(probe.current, previous);\n\tconst baseMoves = getMovedBaseRefs(probe, previous.baseDependsOn, tips?.base);\n\tif (baseMoves != null) {\n\t\tfields |= baseMoveField;\n\t}\n\treturn { fields: fields, baseMoves: baseMoves };\n}\n\n/**\n * The read groups `current`, HEAD as `getBranch` answers it, finds moved in what `previous` has of the upstream: another\n * upstream reads the branch and the config inputs, which read the base again when the upstream's identity changed;\n * one gone or back, or other counts against it, the branch. Core drops its cached branches, counts and all, with its\n * ref list on any change to branches or remote-tracking refs, the changes a tip check follows, so a probe after one\n * answers them as of that change.\n */\nfunction getUpstreamFields(current: GitBranch | undefined, previous: WorktreeSummary): number {\n\tconst upstream = current?.upstream;\n\tif (upstream?.name !== previous.upstream?.name) return branchField | baseConfigField;\n\n\tif (\n\t\tupstream?.missing !== previous.upstream?.missing ||\n\t\t(upstream?.state.ahead ?? 0) !== previous.ahead ||\n\t\t(upstream?.state.behind ?? 0) !== previous.behind\n\t) {\n\t\treturn branchField;\n\t}\n\treturn 0;\n}\n\n/**\n * The refs of `baseDependsOn` that `probe` finds moved since `baseTips`; `undefined` when none did. A tip that's unknown\n * (`null`, or not kept) moved.\n */\nfunction getMovedBaseRefs(\n\tprobe: ProbedRefs,\n\tbaseDependsOn: readonly string[],\n\tbaseTips: ReadonlyMap<string, string | null | undefined> | undefined,\n): Set<string> | undefined {\n\tlet baseMoves: Set<string> | undefined;\n\tfor (const ref of baseDependsOn) {\n\t\t// An unreadable value is unknown, so it moved\n\t\tconst value = getBaseInput(probe, ref);\n\t\tif (value !== null && baseTips?.has(ref) && value === baseTips.get(ref)) continue;\n\n\t\tbaseMoves ??= new Set();\n\t\tbaseMoves.add(ref);\n\t}\n\treturn baseMoves;\n}\n\n/**\n * The tips a subscribed run leaves its summary read from: from the refs its probe found (`refs`) when it read the base,\n * unknown when it read it without a probe, and else `last`'s\n */\nfunction getReadTips(last: ReadTips | undefined, refs: ProbedRefs | undefined, result: ReadResult): ReadTips {\n\tconst { summary, fields } = result;\n\n\tlet base = last?.base;\n\t// A base that failed to read is stale, which reads everything next time\n\tif (fields & (baseField | baseMoveField)) {\n\t\tbase = refs != null && !summary.stale ? getBaseTips(refs, summary.baseDependsOn) : undefined;\n\t}\n\treturn { base: base };\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: ProbedRefs, 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\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: getBaseTips(probe, summary.baseDependsOn),\n\t\tindex: probe.index,\n\t};\n}\n\n/** What `refs` found of each of `baseDependsOn` (see {@link getBaseInput}) */\nfunction getBaseTips(\n\trefs: ProbedRefs,\n\tbaseDependsOn: readonly string[],\n): ReadonlyMap<string, string | null | undefined> {\n\tconst baseTips = new Map<string, string | null | undefined>();\n\tfor (const ref of baseDependsOn) {\n\t\tbaseTips.set(ref, getBaseInput(refs, ref));\n\t}\n\treturn baseTips;\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\n/** Whether `e` names `ref` exactly, so it's known to be a ref that moved rather than one that may have */\nfunction isNamedRef(e: WatcherRepoChangeEvent, ref: string): boolean {\n\tconst kind = getRefChangeKind(ref);\n\treturn kind != null && e.refs.has(ref) && !e.unnamedRefKinds.has(kind);\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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"}
|
|
@@ -11,6 +11,7 @@ import { AnnouncedRepositoryChanges, GitProvider } from "../git/providers/provid
|
|
|
11
11
|
import { FilteredGitFeatures, GitFeatureOrPrefix, GitFeatures } from "../git/features.js";
|
|
12
12
|
import { GitLocation } from "./exec/locator.js";
|
|
13
13
|
import { Git, GitFeatureUnsupportedMessage, GitOptions } from "./exec/git.js";
|
|
14
|
+
import { IndexRefresher, IndexRefresherOptions } from "./exec/indexRefresh.js";
|
|
14
15
|
import { BlameGitSubProvider } from "./providers/blame.js";
|
|
15
16
|
import { BranchesGitSubProvider } from "./providers/branches.js";
|
|
16
17
|
import { CommitsGitSubProvider } from "./providers/commits.js";
|
|
@@ -58,6 +59,17 @@ export interface CliGitProviderOptions {
|
|
|
58
59
|
* a literal path strictly inside the common git dir, or that lies under `worktrees`, is dropped.
|
|
59
60
|
*/
|
|
60
61
|
ignoredWorktreeFolders?: readonly string[];
|
|
62
|
+
/**
|
|
63
|
+
* Refreshes a checkout's index in the background after core's own clone, worktree add, checkout, restore, merge, pull,
|
|
64
|
+
* reset, cherry-pick, revert, rebase, stash apply, pop and push, and abort or continue of a paused operation rewrote
|
|
65
|
+
* it, so later status and diff reads stop re-hashing the files written in the index's second. A write that stops on
|
|
66
|
+
* conflicts refreshes too, since the files it rewrote first are read the most while the conflicts are resolved. Off
|
|
67
|
+
* by default: each costs a status of the whole checkout, worth it only where that checkout will be read again.
|
|
68
|
+
* `scheduleIndexRefresh` runs either way.
|
|
69
|
+
*/
|
|
70
|
+
refreshIndexAfterWrites?: boolean;
|
|
71
|
+
/** The clock and timer behind the background index refresh, for tests; the real ones by default */
|
|
72
|
+
indexRefresh?: Pick<IndexRefresherOptions, 'now' | 'setTimer'>;
|
|
61
73
|
}
|
|
62
74
|
/**
|
|
63
75
|
* Exposes `isTrackedWithDetails` as a callable method for sub-providers.
|
|
@@ -97,9 +109,13 @@ export declare class CliGitProvider implements GitProvider {
|
|
|
97
109
|
private readonly _ignoredWorktreeFolders;
|
|
98
110
|
/** By common git dir, the folders whose worktrees are ignored there: a common git dir never moves while it is open */
|
|
99
111
|
private readonly _ignoredWorktreeRoots;
|
|
112
|
+
private readonly _indexRefresher;
|
|
100
113
|
constructor(options: CliGitProviderOptions);
|
|
101
114
|
/** The underlying cache instance (for repo path registration, etc.) */
|
|
102
115
|
get cache(): Cache;
|
|
116
|
+
/** The per-checkout queue that refreshes an index a write left with untrusted entries */
|
|
117
|
+
get indexRefresher(): IndexRefresher;
|
|
118
|
+
private statIndexMtimeMs;
|
|
103
119
|
get onDidChangeMergeTargets(): Event<MergeTargetsChangeEvent>;
|
|
104
120
|
getIgnoredWorktreeFolders(_repoPath: string): readonly string[];
|
|
105
121
|
/**
|
|
@@ -247,14 +263,25 @@ export declare class CliGitProvider implements GitProvider {
|
|
|
247
263
|
priority?: GitCommandPriority;
|
|
248
264
|
}, cancellation?: AbortSignal): Promise<string[]>;
|
|
249
265
|
/**
|
|
250
|
-
* Which of `scopes` are ignored.
|
|
251
|
-
*
|
|
252
|
-
*
|
|
266
|
+
* Which of `scopes` are ignored. A scope git refuses (beyond a symlink, inside a submodule) is not ignored, as the
|
|
267
|
+
* listing answers it with nothing. Any other failure answers none; when git itself is failing, the listing that
|
|
268
|
+
* follows fails too.
|
|
253
269
|
*/
|
|
254
270
|
private getIgnoredScopes;
|
|
271
|
+
/**
|
|
272
|
+
* `check-ignore` dies on the first path it can't answer (inside a submodule, beyond a symlink, outside the repository,
|
|
273
|
+
* or empty), where this repository ignores nothing, having answered every path before it, so the paths after it are
|
|
274
|
+
* asked again, less those in the folder of a path refused for a symlink or submodule, which share its fate. Each path
|
|
275
|
+
* is answered once, in one run plus one for each refusal. Any other failure is thrown.
|
|
276
|
+
*/
|
|
255
277
|
getIgnoredPaths(repoPath: string, paths: readonly string[], options?: {
|
|
256
278
|
priority?: GitCommandPriority;
|
|
257
279
|
}, cancellation?: AbortSignal): Promise<Set<string>>;
|
|
280
|
+
/**
|
|
281
|
+
* One `check-ignore` run over `paths`, adding the ignored ones to `ignored`. Returns the path git died on, which
|
|
282
|
+
* every path before it was answered ahead of, or `undefined` when all were answered.
|
|
283
|
+
*/
|
|
284
|
+
private checkIgnore;
|
|
258
285
|
/** Every `.gitignore` git reads in the working tree (tracked, or untracked and not itself ignored), root included */
|
|
259
286
|
private getGitIgnorePaths;
|
|
260
287
|
private isTrackedWithDetails;
|