@gitkraken/core-gitlens 0.5.110 → 0.5.112
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 +19 -1
- package/dist/git/cache.d.ts +111 -6
- package/dist/git/cache.d.ts.map +1 -1
- package/dist/git/cache.js +312 -43
- package/dist/git/cache.js.map +1 -1
- package/dist/git/context.d.ts +11 -0
- package/dist/git/context.d.ts.map +1 -1
- package/dist/git/context.js.map +1 -1
- package/dist/git/models/fileStatus.d.ts +1 -0
- package/dist/git/models/fileStatus.d.ts.map +1 -1
- package/dist/git/models/fileStatus.js +1 -0
- package/dist/git/models/fileStatus.js.map +1 -1
- package/dist/git/models/issue.d.ts +4 -0
- package/dist/git/models/issue.d.ts.map +1 -1
- package/dist/git/models/mergeConflicts.d.ts +2 -0
- package/dist/git/models/mergeConflicts.d.ts.map +1 -1
- package/dist/git/models/pullRequest.d.ts +38 -2
- package/dist/git/models/pullRequest.d.ts.map +1 -1
- package/dist/git/models/pullRequest.js +12 -1
- package/dist/git/models/pullRequest.js.map +1 -1
- package/dist/git/models/repository.d.ts +32 -5
- package/dist/git/models/repository.d.ts.map +1 -1
- package/dist/git/models/repository.js +58 -12
- package/dist/git/models/repository.js.map +1 -1
- package/dist/git/models/statusFile.d.ts.map +1 -1
- package/dist/git/models/statusFile.js +3 -0
- package/dist/git/models/statusFile.js.map +1 -1
- package/dist/git/providers/branches.d.ts +2 -0
- package/dist/git/providers/branches.d.ts.map +1 -1
- package/dist/git/providers/commits.d.ts +8 -0
- package/dist/git/providers/commits.d.ts.map +1 -1
- package/dist/git/providers/config.d.ts +19 -1
- package/dist/git/providers/config.d.ts.map +1 -1
- package/dist/git/providers/operations.d.ts +1 -0
- package/dist/git/providers/operations.d.ts.map +1 -1
- package/dist/git/providers/pausedOperations.d.ts +2 -0
- package/dist/git/providers/pausedOperations.d.ts.map +1 -1
- package/dist/git/providers/status.d.ts +1 -0
- package/dist/git/providers/status.d.ts.map +1 -1
- package/dist/git/utils/config.utils.d.ts +3 -0
- package/dist/git/utils/config.utils.d.ts.map +1 -0
- package/dist/git/utils/config.utils.js +8 -0
- package/dist/git/utils/config.utils.js.map +1 -0
- package/dist/git/utils/issue.utils.d.ts.map +1 -1
- package/dist/git/utils/issue.utils.js +2 -0
- package/dist/git/utils/issue.utils.js.map +1 -1
- package/dist/git/utils/pausedOperationStatus.utils.d.ts +14 -0
- package/dist/git/utils/pausedOperationStatus.utils.d.ts.map +1 -1
- package/dist/git/utils/pausedOperationStatus.utils.js +23 -0
- package/dist/git/utils/pausedOperationStatus.utils.js.map +1 -1
- package/dist/git/utils/pullRequest.utils.d.ts +14 -1
- package/dist/git/utils/pullRequest.utils.d.ts.map +1 -1
- package/dist/git/utils/pullRequest.utils.js +31 -0
- package/dist/git/utils/pullRequest.utils.js.map +1 -1
- package/dist/git/watching/changeEvent.d.ts +6 -1
- package/dist/git/watching/changeEvent.d.ts.map +1 -1
- package/dist/git/watching/classifyChange.d.ts.map +1 -1
- package/dist/git/watching/classifyChange.js +14 -1
- package/dist/git/watching/classifyChange.js.map +1 -1
- package/dist/git/watching/watchService.d.ts.map +1 -1
- package/dist/git/watching/watchService.js +18 -3
- package/dist/git/watching/watchService.js.map +1 -1
- package/dist/git/watching/watchSession.d.ts +8 -1
- package/dist/git/watching/watchSession.d.ts.map +1 -1
- package/dist/git/watching/watchSession.js +38 -6
- package/dist/git/watching/watchSession.js.map +1 -1
- package/dist/git/watching/watcherPatterns.d.ts +2 -2
- package/dist/git/watching/watcherPatterns.d.ts.map +1 -1
- package/dist/git/watching/watcherPatterns.js +1 -1
- package/dist/git/watching/watcherPatterns.js.map +1 -1
- package/dist/git-cli/exec/git.d.ts +1 -1
- package/dist/git-cli/exec/git.d.ts.map +1 -1
- package/dist/git-cli/exec/git.js +13 -3
- package/dist/git-cli/exec/git.js.map +1 -1
- package/dist/git-cli/providers/branches.d.ts +19 -0
- package/dist/git-cli/providers/branches.d.ts.map +1 -1
- package/dist/git-cli/providers/branches.js +282 -78
- package/dist/git-cli/providers/branches.js.map +1 -1
- package/dist/git-cli/providers/commits.d.ts +4 -0
- package/dist/git-cli/providers/commits.d.ts.map +1 -1
- package/dist/git-cli/providers/commits.js +84 -11
- package/dist/git-cli/providers/commits.js.map +1 -1
- package/dist/git-cli/providers/config.d.ts +42 -0
- package/dist/git-cli/providers/config.d.ts.map +1 -1
- package/dist/git-cli/providers/config.js +186 -5
- package/dist/git-cli/providers/config.js.map +1 -1
- package/dist/git-cli/providers/contributors.d.ts.map +1 -1
- package/dist/git-cli/providers/contributors.js +1 -1
- package/dist/git-cli/providers/contributors.js.map +1 -1
- package/dist/git-cli/providers/graph.d.ts +2 -2
- package/dist/git-cli/providers/graph.d.ts.map +1 -1
- package/dist/git-cli/providers/graph.js +27 -9
- package/dist/git-cli/providers/graph.js.map +1 -1
- package/dist/git-cli/providers/operations.d.ts.map +1 -1
- package/dist/git-cli/providers/operations.js +40 -12
- package/dist/git-cli/providers/operations.js.map +1 -1
- package/dist/git-cli/providers/pausedOperations.d.ts +5 -0
- package/dist/git-cli/providers/pausedOperations.d.ts.map +1 -1
- package/dist/git-cli/providers/pausedOperations.js +87 -16
- package/dist/git-cli/providers/pausedOperations.js.map +1 -1
- package/dist/git-cli/providers/refs.d.ts +5 -3
- package/dist/git-cli/providers/refs.d.ts.map +1 -1
- package/dist/git-cli/providers/refs.js +33 -4
- package/dist/git-cli/providers/refs.js.map +1 -1
- package/dist/git-cli/providers/status.d.ts +1 -0
- package/dist/git-cli/providers/status.d.ts.map +1 -1
- package/dist/git-cli/providers/status.js +18 -3
- package/dist/git-cli/providers/status.js.map +1 -1
- package/dist/git-cli/providers/worktrees.d.ts.map +1 -1
- package/dist/git-cli/providers/worktrees.js +4 -0
- package/dist/git-cli/providers/worktrees.js.map +1 -1
- package/dist/git-cli/service.d.ts.map +1 -1
- package/dist/git-cli/service.js.map +1 -1
- package/dist/plus/agents/providers/claudeCodeProvider.d.ts +39 -1
- package/dist/plus/agents/providers/claudeCodeProvider.d.ts.map +1 -1
- package/dist/plus/agents/providers/claudeCodeProvider.js +978 -71
- package/dist/plus/agents/providers/claudeCodeProvider.js.map +1 -1
- package/dist/plus/agents/providers/claudeCodeTranscript.d.ts +24 -2
- package/dist/plus/agents/providers/claudeCodeTranscript.d.ts.map +1 -1
- package/dist/plus/agents/providers/claudeCodeTranscript.js +84 -9
- package/dist/plus/agents/providers/claudeCodeTranscript.js.map +1 -1
- package/dist/plus/agents/types.d.ts +37 -2
- package/dist/plus/agents/types.d.ts.map +1 -1
- package/dist/plus/agents/types.js +2 -0
- package/dist/plus/agents/types.js.map +1 -1
- package/dist/plus/ai/errors.d.ts +10 -0
- package/dist/plus/ai/errors.d.ts.map +1 -1
- package/dist/plus/ai/errors.js +29 -0
- package/dist/plus/ai/errors.js.map +1 -1
- package/dist/plus/ai/models/model.d.ts +4 -0
- package/dist/plus/ai/models/model.d.ts.map +1 -1
- package/dist/plus/ai/models/model.js +51 -6
- package/dist/plus/ai/models/model.js.map +1 -1
- package/dist/plus/ai/models/promptTemplates.d.ts +1 -1
- package/dist/plus/ai/models/promptTemplates.d.ts.map +1 -1
- package/dist/plus/ai/models/provider.d.ts +60 -2
- package/dist/plus/ai/models/provider.d.ts.map +1 -1
- package/dist/plus/ai/prompts.d.ts +12 -0
- package/dist/plus/ai/prompts.d.ts.map +1 -1
- package/dist/plus/ai/prompts.js +177 -61
- package/dist/plus/ai/prompts.js.map +1 -1
- package/dist/plus/ai/providers/anthropicProvider.d.ts +10 -2
- package/dist/plus/ai/providers/anthropicProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/anthropicProvider.js +139 -46
- package/dist/plus/ai/providers/anthropicProvider.js.map +1 -1
- package/dist/plus/ai/providers/deepSeekProvider.d.ts +2 -0
- package/dist/plus/ai/providers/deepSeekProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/deepSeekProvider.js +10 -21
- package/dist/plus/ai/providers/deepSeekProvider.js.map +1 -1
- package/dist/plus/ai/providers/geminiProvider.d.ts +1 -0
- package/dist/plus/ai/providers/geminiProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/geminiProvider.js +19 -0
- package/dist/plus/ai/providers/geminiProvider.js.map +1 -1
- package/dist/plus/ai/providers/gitkrakenProvider.d.ts +5 -1
- package/dist/plus/ai/providers/gitkrakenProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/gitkrakenProvider.js +118 -3
- package/dist/plus/ai/providers/gitkrakenProvider.js.map +1 -1
- package/dist/plus/ai/providers/huggingFaceProvider.d.ts +1 -0
- package/dist/plus/ai/providers/huggingFaceProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/huggingFaceProvider.js +5 -0
- package/dist/plus/ai/providers/huggingFaceProvider.js.map +1 -1
- package/dist/plus/ai/providers/mistralProvider.d.ts +3 -1
- package/dist/plus/ai/providers/mistralProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/mistralProvider.js +99 -19
- package/dist/plus/ai/providers/mistralProvider.js.map +1 -1
- package/dist/plus/ai/providers/ollamaProvider.d.ts +4 -3
- package/dist/plus/ai/providers/ollamaProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/ollamaProvider.js +38 -3
- package/dist/plus/ai/providers/ollamaProvider.js.map +1 -1
- package/dist/plus/ai/providers/openAICompatibleProvider.d.ts +1 -0
- package/dist/plus/ai/providers/openAICompatibleProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/openAICompatibleProvider.js +4 -0
- package/dist/plus/ai/providers/openAICompatibleProvider.js.map +1 -1
- package/dist/plus/ai/providers/openAICompatibleProviderBase.d.ts +154 -5
- package/dist/plus/ai/providers/openAICompatibleProviderBase.d.ts.map +1 -1
- package/dist/plus/ai/providers/openAICompatibleProviderBase.js +259 -10
- package/dist/plus/ai/providers/openAICompatibleProviderBase.js.map +1 -1
- package/dist/plus/ai/providers/openRouterProvider.d.ts +4 -0
- package/dist/plus/ai/providers/openRouterProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/openRouterProvider.js +9 -0
- package/dist/plus/ai/providers/openRouterProvider.js.map +1 -1
- package/dist/plus/ai/providers/openaiProvider.d.ts +1 -0
- package/dist/plus/ai/providers/openaiProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/openaiProvider.js +1 -0
- package/dist/plus/ai/providers/openaiProvider.js.map +1 -1
- package/dist/plus/ai/providers/responseFormatCache.d.ts +8 -0
- package/dist/plus/ai/providers/responseFormatCache.d.ts.map +1 -0
- package/dist/plus/ai/providers/responseFormatCache.js +25 -0
- package/dist/plus/ai/providers/responseFormatCache.js.map +1 -0
- package/dist/plus/ai/providers/xaiProvider.d.ts +1 -0
- package/dist/plus/ai/providers/xaiProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/xaiProvider.js +10 -1
- package/dist/plus/ai/providers/xaiProvider.js.map +1 -1
- package/dist/plus/ai/utils/ai.utils.d.ts +3 -0
- package/dist/plus/ai/utils/ai.utils.d.ts.map +1 -1
- package/dist/plus/ai/utils/ai.utils.js +13 -0
- package/dist/plus/ai/utils/ai.utils.js.map +1 -1
- package/dist/plus/ai/utils/results.utils.d.ts +16 -2
- package/dist/plus/ai/utils/results.utils.d.ts.map +1 -1
- package/dist/plus/ai/utils/results.utils.js +204 -28
- package/dist/plus/ai/utils/results.utils.js.map +1 -1
- package/dist/plus/git-github/api/github.d.ts +55 -0
- package/dist/plus/git-github/api/github.d.ts.map +1 -1
- package/dist/plus/git-github/api/github.js +177 -4
- package/dist/plus/git-github/api/github.js.map +1 -1
- package/dist/plus/git-github/models.d.ts +16 -0
- package/dist/plus/git-github/models.d.ts.map +1 -1
- package/dist/plus/git-github/models.js +29 -3
- package/dist/plus/git-github/models.js.map +1 -1
- package/dist/plus/git-github/providers/github/status.d.ts +1 -0
- package/dist/plus/git-github/providers/github/status.d.ts.map +1 -1
- package/dist/plus/git-github/providers/github/status.js.map +1 -1
- package/dist/plus/integrations/context.d.ts +4 -0
- package/dist/plus/integrations/context.d.ts.map +1 -1
- package/dist/plus/integrations/index.d.ts.map +1 -1
- package/dist/plus/integrations/index.js +2 -0
- package/dist/plus/integrations/index.js.map +1 -1
- package/dist/plus/integrations/models/gitHostIntegration.d.ts +6 -3
- package/dist/plus/integrations/models/gitHostIntegration.d.ts.map +1 -1
- package/dist/plus/integrations/models/gitHostIntegration.js +12 -2
- package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
- package/dist/plus/integrations/models/integration.d.ts +3 -1
- package/dist/plus/integrations/models/integration.d.ts.map +1 -1
- package/dist/plus/integrations/models/integration.js +2 -2
- package/dist/plus/integrations/models/integration.js.map +1 -1
- package/dist/plus/integrations/providers/accounts.d.ts.map +1 -1
- package/dist/plus/integrations/providers/accounts.js +4 -0
- package/dist/plus/integrations/providers/accounts.js.map +1 -1
- package/dist/plus/integrations/providers/azure/models.d.ts.map +1 -1
- package/dist/plus/integrations/providers/azure/models.js +3 -0
- package/dist/plus/integrations/providers/azure/models.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket/models.d.ts.map +1 -1
- package/dist/plus/integrations/providers/bitbucket/models.js +1 -0
- package/dist/plus/integrations/providers/bitbucket/models.js.map +1 -1
- package/dist/plus/integrations/providers/github.d.ts +14 -2
- package/dist/plus/integrations/providers/github.d.ts.map +1 -1
- package/dist/plus/integrations/providers/github.js +55 -3
- package/dist/plus/integrations/providers/github.js.map +1 -1
- package/dist/plus/integrations/providers/gitlab.d.ts.map +1 -1
- package/dist/plus/integrations/providers/gitlab.js.map +1 -1
- package/dist/plus/integrations/providers/models.d.ts.map +1 -1
- package/dist/plus/integrations/providers/models.js +30 -4
- package/dist/plus/integrations/providers/models.js.map +1 -1
- package/dist/plus/integrations/reads/broaden.d.ts.map +1 -1
- package/dist/plus/integrations/reads/broaden.js +6 -1
- package/dist/plus/integrations/reads/broaden.js.map +1 -1
- package/dist/plus/integrations/reads/drains.d.ts.map +1 -1
- package/dist/plus/integrations/reads/drains.js +7 -4
- package/dist/plus/integrations/reads/drains.js.map +1 -1
- package/dist/plus/integrations/reads/hierarchy.d.ts.map +1 -1
- package/dist/plus/integrations/reads/hierarchy.js +3 -1
- package/dist/plus/integrations/reads/hierarchy.js.map +1 -1
- package/dist/plus/integrations/reads/issueTracker.d.ts.map +1 -1
- package/dist/plus/integrations/reads/issueTracker.js +8 -3
- package/dist/plus/integrations/reads/issueTracker.js.map +1 -1
- package/dist/plus/integrations/reads/issues.d.ts.map +1 -1
- package/dist/plus/integrations/reads/issues.js +9 -4
- package/dist/plus/integrations/reads/issues.js.map +1 -1
- package/dist/plus/integrations/reads/pullRequests.d.ts.map +1 -1
- package/dist/plus/integrations/reads/pullRequests.js +9 -4
- package/dist/plus/integrations/reads/pullRequests.js.map +1 -1
- package/dist/utils/env/browser/base64.d.ts +1 -1
- package/dist/utils/env/browser/base64.d.ts.map +1 -1
- package/dist/utils/env/node/base64.d.ts +1 -1
- package/dist/utils/env/node/base64.d.ts.map +1 -1
- package/dist/utils/env/node/base64.js +2 -0
- package/dist/utils/env/node/base64.js.map +1 -1
- package/dist/utils/keys/chord.d.ts +52 -0
- package/dist/utils/keys/chord.d.ts.map +1 -0
- package/dist/utils/keys/chord.js +135 -0
- package/dist/utils/keys/chord.js.map +1 -0
- package/dist/utils/keys/keybinding.d.ts +53 -0
- package/dist/utils/keys/keybinding.d.ts.map +1 -0
- package/dist/utils/keys/keybinding.js +58 -0
- package/dist/utils/keys/keybinding.js.map +1 -0
- package/dist/utils/path.d.ts +11 -0
- package/dist/utils/path.d.ts.map +1 -1
- package/dist/utils/path.js +13 -0
- package/dist/utils/path.js.map +1 -1
- package/package.json +13 -5
- package/src/git/cache.ts +383 -47
- package/src/git/context.ts +11 -0
- package/src/git/models/fileStatus.ts +1 -0
- package/src/git/models/issue.ts +4 -0
- package/src/git/models/mergeConflicts.ts +3 -2
- package/src/git/models/pullRequest.ts +33 -1
- package/src/git/models/repository.ts +58 -17
- package/src/git/models/statusFile.ts +3 -0
- package/src/git/providers/branches.ts +6 -0
- package/src/git/providers/commits.ts +11 -0
- package/src/git/providers/config.ts +18 -0
- package/src/git/providers/operations.ts +1 -0
- package/src/git/providers/pausedOperations.ts +2 -0
- package/src/git/providers/status.ts +1 -0
- package/src/git/utils/config.utils.ts +8 -0
- package/src/git/utils/issue.utils.ts +2 -0
- package/src/git/utils/pausedOperationStatus.utils.ts +28 -0
- package/src/git/utils/pullRequest.utils.ts +36 -0
- package/src/git/watching/changeEvent.ts +6 -1
- package/src/git/watching/classifyChange.ts +15 -1
- package/src/git/watching/watchService.ts +20 -3
- package/src/git/watching/watchSession.ts +41 -6
- package/src/git/watching/watcherPatterns.ts +1 -1
- package/src/git-cli/exec/git.ts +13 -3
- package/src/git-cli/providers/branches.ts +384 -132
- package/src/git-cli/providers/commits.ts +106 -15
- package/src/git-cli/providers/config.ts +229 -8
- package/src/git-cli/providers/contributors.ts +5 -1
- package/src/git-cli/providers/graph.ts +26 -13
- package/src/git-cli/providers/operations.ts +45 -20
- package/src/git-cli/providers/pausedOperations.ts +109 -17
- package/src/git-cli/providers/refs.ts +33 -3
- package/src/git-cli/providers/status.ts +25 -4
- package/src/git-cli/providers/worktrees.ts +5 -0
- package/src/git-cli/service.ts +0 -1
- package/src/plus/agents/providers/claudeCodeProvider.ts +1130 -87
- package/src/plus/agents/providers/claudeCodeTranscript.ts +95 -9
- package/src/plus/agents/types.ts +46 -2
- package/src/plus/ai/errors.ts +30 -0
- package/src/plus/ai/models/model.ts +56 -6
- package/src/plus/ai/models/promptTemplates.ts +1 -1
- package/src/plus/ai/models/provider.ts +69 -2
- package/src/plus/ai/prompts.ts +186 -61
- package/src/plus/ai/providers/anthropicProvider.ts +155 -47
- package/src/plus/ai/providers/deepSeekProvider.ts +11 -21
- package/src/plus/ai/providers/geminiProvider.ts +19 -0
- package/src/plus/ai/providers/gitkrakenProvider.ts +126 -3
- package/src/plus/ai/providers/huggingFaceProvider.ts +6 -0
- package/src/plus/ai/providers/mistralProvider.ts +102 -19
- package/src/plus/ai/providers/ollamaProvider.ts +55 -4
- package/src/plus/ai/providers/openAICompatibleProvider.ts +5 -0
- package/src/plus/ai/providers/openAICompatibleProviderBase.ts +360 -17
- package/src/plus/ai/providers/openRouterProvider.ts +17 -0
- package/src/plus/ai/providers/openaiProvider.ts +1 -0
- package/src/plus/ai/providers/responseFormatCache.ts +39 -0
- package/src/plus/ai/providers/xaiProvider.ts +10 -1
- package/src/plus/ai/utils/ai.utils.ts +14 -0
- package/src/plus/ai/utils/results.utils.ts +255 -31
- package/src/plus/git-github/api/github.ts +291 -7
- package/src/plus/git-github/models.ts +48 -2
- package/src/plus/git-github/providers/github/status.ts +1 -0
- package/src/plus/integrations/context.ts +4 -0
- package/src/plus/integrations/index.ts +2 -0
- package/src/plus/integrations/models/gitHostIntegration.ts +25 -2
- package/src/plus/integrations/models/integration.ts +23 -13
- package/src/plus/integrations/providers/accounts.ts +4 -0
- package/src/plus/integrations/providers/azure/models.ts +3 -0
- package/src/plus/integrations/providers/bitbucket/models.ts +1 -0
- package/src/plus/integrations/providers/github.ts +85 -1
- package/src/plus/integrations/providers/gitlab.ts +2 -10
- package/src/plus/integrations/providers/models.ts +36 -4
- package/src/plus/integrations/reads/broaden.ts +6 -1
- package/src/plus/integrations/reads/drains.ts +7 -4
- package/src/plus/integrations/reads/hierarchy.ts +3 -1
- package/src/plus/integrations/reads/issueTracker.ts +9 -3
- package/src/plus/integrations/reads/issues.ts +9 -4
- package/src/plus/integrations/reads/pullRequests.ts +9 -4
- package/src/utils/env/browser/base64.ts +1 -1
- package/src/utils/env/node/base64.ts +3 -1
- package/src/utils/keys/chord.ts +184 -0
- package/src/utils/keys/keybinding.ts +116 -0
- package/src/utils/path.ts +14 -0
package/dist/git/cache.js
CHANGED
|
@@ -17,6 +17,12 @@ const uriScopedCachedGitTypes = ['blame', 'diff', 'fileLog'];
|
|
|
17
17
|
export function areUriScopedCachedGitTypes(types) {
|
|
18
18
|
return types.every(t => uriScopedCachedGitTypes.includes(t));
|
|
19
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* Ceiling on how long a derived branch base is trusted. Long enough that repeated reads during normal use
|
|
22
|
+
* are served from cache, short enough that a base that changed by a route with no eviction signal (an
|
|
23
|
+
* external delete-and-recreate of a branch that is never checked out) self-heals without a reload.
|
|
24
|
+
*/
|
|
25
|
+
const baseBranchNameTTL = 5 * 60 * 1000; // 5 minutes
|
|
20
26
|
/**
|
|
21
27
|
* gkConfig keys that participate in the `branchOverviews` cache's mergeTarget/mergeBase lineage.
|
|
22
28
|
* Capture group 1 is the ref name (which may itself contain `.`/`/`).
|
|
@@ -102,6 +108,22 @@ export class Cache {
|
|
|
102
108
|
_worktreesByCommonPath = new Map();
|
|
103
109
|
/** Monotonic per-worktree "status clock" — see {@link getStatusGeneration}. */
|
|
104
110
|
_statusGenerations = new Map();
|
|
111
|
+
/** Monotonic per-path "close clock" — see {@link getCloseGeneration}. */
|
|
112
|
+
_closeGenerations = new Map();
|
|
113
|
+
/**
|
|
114
|
+
* Per-commonPath snapshot of the merge-relevant subset of `.git/gk/config` (keys matching
|
|
115
|
+
* {@link branchOverviewGkConfigKeysRegex}), used by {@link reconcileGkConfigMap} to diff a watcher
|
|
116
|
+
* `'gkConfig'` event down to only the keys that actually changed, instead of coarsely re-deriving
|
|
117
|
+
* `baseBranchName`/`branchOverviews` on every gk write. Absent means "never observed".
|
|
118
|
+
*/
|
|
119
|
+
_gkConfigMergeSnapshots = new Map();
|
|
120
|
+
/**
|
|
121
|
+
* Reconciler registered by the CLI config sub-provider (see {@link setGkConfigReconciler}),
|
|
122
|
+
* invoked on a watcher-observed `'gkConfig'` change instead of the coarse `clearCaches(repoPath,
|
|
123
|
+
* 'gkConfig')` cascade. `undefined` (e.g. the GitHub provider, which has no `.git/gk/config`)
|
|
124
|
+
* falls back to the coarse clear.
|
|
125
|
+
*/
|
|
126
|
+
_gkConfigReconciler;
|
|
105
127
|
[Symbol.dispose]() {
|
|
106
128
|
this.dispose();
|
|
107
129
|
}
|
|
@@ -348,9 +370,24 @@ export class Cache {
|
|
|
348
370
|
keysToClear.add('reachability');
|
|
349
371
|
keysToClear.add('resolvedRevisions');
|
|
350
372
|
}
|
|
351
|
-
// Shared branch caches (branch list, metadata)
|
|
352
|
-
|
|
373
|
+
// Shared branch caches (branch list, metadata). `baseBranchName` is deliberately NOT cleared
|
|
374
|
+
// here — a branch's base is set at creation and only changes when its stored key changes
|
|
375
|
+
// (`gkConfig`/`config` below) or the branch itself is created/renamed/deleted. Every op that
|
|
376
|
+
// does one of those calls `deleteBaseBranchName` and moves or drops the branch's persisted
|
|
377
|
+
// `branch.<ref>.gk-*` keys: `createBranch`/`deleteLocalBranch`/`renameBranch`, plus the two
|
|
378
|
+
// paths that create a branch as a side effect (`checkout -b`, `worktree add -b`). Tip movement
|
|
379
|
+
// can't change a base, so clearing on every commit only forced a `git reflog` re-derivation.
|
|
380
|
+
if (types.includes('branch')) {
|
|
381
|
+
// `'branch'` comes from a HEAD change — a checkout — which appends `checkout: moving from X
|
|
382
|
+
// to Y` to the reflog, exactly the entry `getBaseBranchName` greps for when nothing is
|
|
383
|
+
// stored. A base derived as "none" BEFORE that entry existed is cached with no TTL, so
|
|
384
|
+
// without this it stays "none" for the session even though the answer now exists.
|
|
385
|
+
//
|
|
386
|
+
// Deliberately not under `'branches'`: a tip move can't change a branch's base, so re-deriving
|
|
387
|
+
// on every commit would be pure cost. Checkouts are user-driven and rare by comparison.
|
|
353
388
|
keysToClear.add('baseBranchName');
|
|
389
|
+
}
|
|
390
|
+
if (types.includes('branches')) {
|
|
354
391
|
keysToClear.add('branchMetadataMap');
|
|
355
392
|
keysToClear.add('branches');
|
|
356
393
|
keysToClear.add('sharedBranches');
|
|
@@ -361,6 +398,10 @@ export class Cache {
|
|
|
361
398
|
keysToClear.add('refTips');
|
|
362
399
|
}
|
|
363
400
|
if (types.includes('config')) {
|
|
401
|
+
// `getBaseBranchName` falls back to `branch.<ref>.vscode-merge-base` (written by VS Code's
|
|
402
|
+
// built-in Git), which lives in `.git/config` — so a config change is the only signal that
|
|
403
|
+
// source changed. Cheap: config events are rare.
|
|
404
|
+
keysToClear.add('baseBranchName');
|
|
364
405
|
keysToClear.add('configKeys');
|
|
365
406
|
keysToClear.add('configPatterns');
|
|
366
407
|
keysToClear.add('currentBranchReference');
|
|
@@ -415,6 +456,11 @@ export class Cache {
|
|
|
415
456
|
keysToClear.add('tags');
|
|
416
457
|
keysToClear.add('refs');
|
|
417
458
|
keysToClear.add('refTips');
|
|
459
|
+
// `commit`/`commitCount` can be keyed by a tag name (e.g. the tag node's load-more count),
|
|
460
|
+
// which re-points on a force-moved or deleted-and-recreated tag — same drift the
|
|
461
|
+
// `branch`/`branches` cascade above clears for.
|
|
462
|
+
keysToClear.add('commit');
|
|
463
|
+
keysToClear.add('commitCount');
|
|
418
464
|
}
|
|
419
465
|
if (types.includes('tracking')) {
|
|
420
466
|
keysToClear.add('fileExistence');
|
|
@@ -436,36 +482,44 @@ export class Cache {
|
|
|
436
482
|
cache.clear();
|
|
437
483
|
}
|
|
438
484
|
else if (sharedCacheKeys.has(key)) {
|
|
439
|
-
|
|
440
|
-
// For shared caches, prefer `invalidate` where supported so in-flight work is
|
|
441
|
-
// shared across new callers and self-evicts on settle rather than spawning a
|
|
442
|
-
// duplicate factory. `invalidate` does the right thing per-entry: entries with
|
|
443
|
-
// a `CacheController` (created via `getOrCreate`) are marked invalidated; entries
|
|
444
|
-
// without one (created via plain `.set()`, e.g. per-worktree mapper results) are
|
|
445
|
-
// hard-deleted. Caches that don't support `invalidate` fall back to `delete`.
|
|
446
|
-
const invalidate = cache.invalidate;
|
|
447
|
-
if (typeof invalidate === 'function') {
|
|
448
|
-
invalidate.call(cache, commonPath);
|
|
449
|
-
for (const worktreePath of this.getWorktreePaths(commonPath)) {
|
|
450
|
-
if (worktreePath === commonPath)
|
|
451
|
-
continue;
|
|
452
|
-
invalidate.call(cache, worktreePath);
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
else {
|
|
456
|
-
cache.delete(commonPath);
|
|
457
|
-
for (const worktreePath of this.getWorktreePaths(commonPath)) {
|
|
458
|
-
if (worktreePath === commonPath)
|
|
459
|
-
continue;
|
|
460
|
-
cache.delete(worktreePath);
|
|
461
|
-
}
|
|
462
|
-
}
|
|
485
|
+
this.evictShared(key, repoPath);
|
|
463
486
|
}
|
|
464
487
|
else {
|
|
465
488
|
cache.delete(repoPath);
|
|
466
489
|
}
|
|
467
490
|
}
|
|
468
491
|
}
|
|
492
|
+
/**
|
|
493
|
+
* Evicts a single shared (commonPath-keyed) cache entry for `repoPath` and its sibling worktrees.
|
|
494
|
+
* Prefers `invalidate` where supported so in-flight work is shared across new callers and
|
|
495
|
+
* self-evicts on settle rather than spawning a duplicate factory. `invalidate` does the right
|
|
496
|
+
* thing per-entry: entries with a `CacheController` (created via `getOrCreate`) are marked
|
|
497
|
+
* invalidated; entries without one (created via plain `.set()`, e.g. per-worktree mapper results)
|
|
498
|
+
* are hard-deleted. Caches that don't support `invalidate` fall back to `delete`.
|
|
499
|
+
*/
|
|
500
|
+
evictShared(key, repoPath) {
|
|
501
|
+
const cache = this._caches[key];
|
|
502
|
+
if (cache == null)
|
|
503
|
+
return;
|
|
504
|
+
const commonPath = this.getCommonPath(repoPath);
|
|
505
|
+
const invalidate = cache.invalidate;
|
|
506
|
+
if (typeof invalidate === 'function') {
|
|
507
|
+
invalidate.call(cache, commonPath);
|
|
508
|
+
for (const worktreePath of this.getWorktreePaths(commonPath)) {
|
|
509
|
+
if (worktreePath === commonPath)
|
|
510
|
+
continue;
|
|
511
|
+
invalidate.call(cache, worktreePath);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
else {
|
|
515
|
+
cache.delete(commonPath);
|
|
516
|
+
for (const worktreePath of this.getWorktreePaths(commonPath)) {
|
|
517
|
+
if (worktreePath === commonPath)
|
|
518
|
+
continue;
|
|
519
|
+
cache.delete(worktreePath);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
}
|
|
469
523
|
/**
|
|
470
524
|
* Monotonic per-worktree counter, advanced whenever anything that can change `git status` output is
|
|
471
525
|
* observed. `git status` and its siblings are point-in-time reads of mutable state, so deduplicating them
|
|
@@ -518,6 +572,20 @@ export class Cache {
|
|
|
518
572
|
const commonPath = this._commonPathRegistry.get(repoPath);
|
|
519
573
|
return commonPath != null && commonPath !== repoPath;
|
|
520
574
|
}
|
|
575
|
+
/** Whether `repoPath` is currently registered (via {@link registerRepoPath}, not yet unregistered). */
|
|
576
|
+
isRegistered(repoPath) {
|
|
577
|
+
return this._commonPathRegistry.has(repoPath);
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* Monotonic per-path counter advanced whenever `repoPath` is unregistered (repo closed, worktree
|
|
581
|
+
* removed). Lets an async post-read step — e.g. the gk-config reconcile — detect that its target was
|
|
582
|
+
* closed (and possibly reopened) mid-flight and bail. Unlike an `isRegistered` check it doesn't
|
|
583
|
+
* require the caller to have registered in the first place, so it stays correct for consumers of
|
|
584
|
+
* this package that don't wire up the host's repo lifecycle.
|
|
585
|
+
*/
|
|
586
|
+
getCloseGeneration(repoPath) {
|
|
587
|
+
return this._closeGenerations.get(repoPath) ?? 0;
|
|
588
|
+
}
|
|
521
589
|
/** Clears file-scoped caches (blame, diff, fileLog) for a specific path within a repo */
|
|
522
590
|
clearForPath(repoPath, path, ...types) {
|
|
523
591
|
const prefix = `${normalizePath(path)}:`;
|
|
@@ -565,6 +633,9 @@ export class Cache {
|
|
|
565
633
|
// Advance the status clock on close so a status read still in flight from this registration can't be
|
|
566
634
|
// joined by a read issued after the path is reopened (which would otherwise reuse the same generation).
|
|
567
635
|
this.incrementStatusGeneration(repoPath);
|
|
636
|
+
// Advance the close clock so an async step that captured it before its read (see `getCloseGeneration`)
|
|
637
|
+
// can tell its target went away mid-flight.
|
|
638
|
+
this._closeGenerations.set(repoPath, this.getCloseGeneration(repoPath) + 1);
|
|
568
639
|
const commonPath = this._commonPathRegistry.get(repoPath) ?? repoPath;
|
|
569
640
|
const worktrees = this._worktreesByCommonPath.get(commonPath);
|
|
570
641
|
// After removing repoPath, would the commonPath have any worktrees left?
|
|
@@ -595,6 +666,10 @@ export class Cache {
|
|
|
595
666
|
evict(repoPath);
|
|
596
667
|
}
|
|
597
668
|
}
|
|
669
|
+
// Shared, commonPath-keyed like `gkConfigMap` — only evict once no worktree still depends on it.
|
|
670
|
+
if (isLastWorktree) {
|
|
671
|
+
this._gkConfigMergeSnapshots.delete(commonPath);
|
|
672
|
+
}
|
|
598
673
|
this._commonPathRegistry.delete(repoPath);
|
|
599
674
|
if (worktrees != null) {
|
|
600
675
|
worktrees.delete(repoPath);
|
|
@@ -604,9 +679,19 @@ export class Cache {
|
|
|
604
679
|
}
|
|
605
680
|
}
|
|
606
681
|
reset() {
|
|
682
|
+
// Advance the close clock BEFORE dropping the registry it reads from. Advancing rather than
|
|
683
|
+
// clearing is the point: an async step that captured a generation must see a mismatch and bail,
|
|
684
|
+
// where a cleared map would hand it a fresh `0` that matches and let it repopulate what was just
|
|
685
|
+
// torn down. Union of registered paths and any already carrying a generation, mirroring
|
|
686
|
+
// `incrementStatusGenerations`.
|
|
687
|
+
for (const path of new Set([...this._commonPathRegistry.keys(), ...this._closeGenerations.keys()])) {
|
|
688
|
+
this._closeGenerations.set(path, this.getCloseGeneration(path) + 1);
|
|
689
|
+
}
|
|
607
690
|
this._commonPathRegistry.clear();
|
|
608
691
|
this._worktreesByCommonPath.clear();
|
|
609
692
|
this._statusGenerations.clear();
|
|
693
|
+
this._gkConfigMergeSnapshots.clear();
|
|
694
|
+
this._gkConfigReconciler = undefined;
|
|
610
695
|
this._caches = createEmptyCaches();
|
|
611
696
|
}
|
|
612
697
|
onRepositoryChanged(repoPath, changes) {
|
|
@@ -653,7 +738,10 @@ export class Cache {
|
|
|
653
738
|
types.add('gitignore');
|
|
654
739
|
}
|
|
655
740
|
if (hasAny('gkConfig')) {
|
|
656
|
-
types
|
|
741
|
+
// Handled separately (not folded into `types`/`clearCaches` below) — a gk write is usually a
|
|
742
|
+
// bookkeeping timestamp that can't affect `baseBranchName`/`branchOverviews`, so this reconciles
|
|
743
|
+
// down to only the keys that actually changed instead of coarsely clearing both on every write.
|
|
744
|
+
this.handleGkConfigChanged(repoPath);
|
|
657
745
|
}
|
|
658
746
|
if (hasAny('lastFetched')) {
|
|
659
747
|
types.add('lastFetched');
|
|
@@ -678,6 +766,48 @@ export class Cache {
|
|
|
678
766
|
this.clearCaches(repoPath, ...types);
|
|
679
767
|
}
|
|
680
768
|
}
|
|
769
|
+
/**
|
|
770
|
+
* Handles a watcher-observed `'gkConfig'` change. Always evicts the cached bulk map (forcing the
|
|
771
|
+
* next read to hit disk). If a reconciler is registered (see {@link setGkConfigReconciler}),
|
|
772
|
+
* defers to it instead of coarsely clearing `baseBranchName`/`branchOverviews` — it re-reads the
|
|
773
|
+
* map and diffs it against the snapshot captured here (i.e. as it stood right before this change),
|
|
774
|
+
* cascading only the refs whose merge-relevant keys actually changed. Falls back to the coarse
|
|
775
|
+
* clear when no reconciler is registered (e.g. the GitHub provider) so nothing can go stale.
|
|
776
|
+
*/
|
|
777
|
+
handleGkConfigChanged(repoPath) {
|
|
778
|
+
const commonPath = this.getCommonPath(repoPath);
|
|
779
|
+
// Hard-delete rather than `evictShared`'s soft-invalidate: the reconcile below needs a
|
|
780
|
+
// point-in-time read of the post-change file, and a soft-invalidated entry stays joinable — the
|
|
781
|
+
// re-read would ride a bulk read that started before this change and diff it as unchanged.
|
|
782
|
+
// Same reasoning as `refs.ts`'s `force: true` path and `deleteGkConfig`'s own hard delete.
|
|
783
|
+
this._caches.gkConfigMap?.delete(commonPath);
|
|
784
|
+
if (this._gkConfigReconciler == null) {
|
|
785
|
+
this.clearCaches(repoPath, 'gkConfig');
|
|
786
|
+
return;
|
|
787
|
+
}
|
|
788
|
+
const priorSnapshot = this._gkConfigMergeSnapshots.get(commonPath);
|
|
789
|
+
// Fire-and-forget, but the outcome still decides whether the coarse clear is owed: a reconcile that
|
|
790
|
+
// FAILED leaves every derived cache holding pre-change values with nothing else to correct them, so
|
|
791
|
+
// it falls back to the blunt behavior that registering a reconciler replaced. Kept here rather than
|
|
792
|
+
// in the reconciler so a bail path added later can't silently skip it — the return type makes each
|
|
793
|
+
// one say what it did.
|
|
794
|
+
void Promise.resolve(this._gkConfigReconciler(repoPath, priorSnapshot)).then(outcome => {
|
|
795
|
+
if (outcome === 'failed') {
|
|
796
|
+
this.clearCaches(repoPath, 'gkConfig');
|
|
797
|
+
}
|
|
798
|
+
},
|
|
799
|
+
// An exception escaping the reconciler is a failure by definition — and one its own `catch`
|
|
800
|
+
// never saw, so nothing else will have cascaded.
|
|
801
|
+
() => this.clearCaches(repoPath, 'gkConfig'));
|
|
802
|
+
}
|
|
803
|
+
/** Hard-evicts the cached bulk `.git/gk/config` map so the next read hits disk. */
|
|
804
|
+
deleteGkConfigMap(repoPath) {
|
|
805
|
+
this._caches.gkConfigMap?.delete(this.getCommonPath(repoPath));
|
|
806
|
+
}
|
|
807
|
+
/** The merge-relevant gk config snapshot currently serving as the reconcile baseline. */
|
|
808
|
+
getGkConfigMergeSnapshot(repoPath) {
|
|
809
|
+
return this._gkConfigMergeSnapshots.get(this.getCommonPath(repoPath));
|
|
810
|
+
}
|
|
681
811
|
getBranches(repoPath, factory, mapper, cancellation) {
|
|
682
812
|
const commonPath = this.getCommonPath(repoPath);
|
|
683
813
|
// Register this caller with the shared factory's aggregate so that invariant 3
|
|
@@ -745,10 +875,34 @@ export class Cache {
|
|
|
745
875
|
/**
|
|
746
876
|
* The whole `.git/gk/config` is read once and cached as a single map per commonPath; per-key and
|
|
747
877
|
* per-namespace gk lookups are served from it in-memory (see `getGkConfigMap` in the CLI config
|
|
748
|
-
* sub-provider). Invalidated by `deleteGkConfig` (write) and
|
|
878
|
+
* sub-provider). Invalidated by `deleteGkConfig` (write) and, on a watcher `'gkConfig'` event, by
|
|
879
|
+
* `handleGkConfigChanged` (reconciled precisely when a reconciler is registered, or the coarse
|
|
880
|
+
* clear otherwise). The first fresh read seeds the merge-relevant snapshot used by
|
|
881
|
+
* `reconcileGkConfigMap`; later refreshes of that snapshot are owned by the reconcile itself.
|
|
749
882
|
*/
|
|
750
883
|
getGkConfigMap(repoPath, factory) {
|
|
751
|
-
return this.getSharedSimple(this.gkConfigMap, repoPath,
|
|
884
|
+
return this.getSharedSimple(this.gkConfigMap, repoPath, async (commonPath, cacheable) => {
|
|
885
|
+
const map = await factory(cacheable);
|
|
886
|
+
// Seed the reconcile baseline on first observation only. Refreshes belong to
|
|
887
|
+
// `reconcileGkConfigMap` (after it has cascaded) and `recordGkConfigWrite` (our own writes):
|
|
888
|
+
// an incidental read that happens to land between an external write and the watcher event
|
|
889
|
+
// would otherwise advance the baseline to the post-change value, so the reconcile would diff
|
|
890
|
+
// that value against itself and silently drop the change.
|
|
891
|
+
if (!this._gkConfigMergeSnapshots.has(commonPath)) {
|
|
892
|
+
this._gkConfigMergeSnapshots.set(commonPath, this.extractMergeRelevantGkConfig(map));
|
|
893
|
+
}
|
|
894
|
+
return map;
|
|
895
|
+
});
|
|
896
|
+
}
|
|
897
|
+
/** Extracts the subset of a gk config map whose keys participate in the `branchOverviews`/`baseBranchName` lineage. */
|
|
898
|
+
extractMergeRelevantGkConfig(map) {
|
|
899
|
+
const subset = new Map();
|
|
900
|
+
for (const [key, value] of map) {
|
|
901
|
+
if (branchOverviewGkConfigKeysRegex.test(key)) {
|
|
902
|
+
subset.set(key, value);
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
return subset;
|
|
752
906
|
}
|
|
753
907
|
/**
|
|
754
908
|
* Clears the cached `.git/gk/config` map and invalidates the derived caches
|
|
@@ -762,18 +916,87 @@ export class Cache {
|
|
|
762
916
|
* invalidates so subsequent reads see the new value.
|
|
763
917
|
*/
|
|
764
918
|
deleteGkConfig(repoPath, key, options) {
|
|
765
|
-
const
|
|
766
|
-
this._caches.gkConfigMap?.delete(
|
|
919
|
+
const commonPath = this.getCommonPath(repoPath);
|
|
920
|
+
this._caches.gkConfigMap?.delete(commonPath);
|
|
921
|
+
this.cascadeGkConfigKeyChange(commonPath, key, options?.skipInvalidation);
|
|
922
|
+
}
|
|
923
|
+
/**
|
|
924
|
+
* Keeps the merge-relevant gk config snapshot in sync with OUR OWN writes, so the next
|
|
925
|
+
* watcher-triggered `reconcileGkConfigMap` diffs a self-write as unchanged rather than as an
|
|
926
|
+
* external change (which would otherwise defeat `skipInvalidation`). No-ops for keys outside the
|
|
927
|
+
* merge-relevant subset, and if no snapshot exists yet for this repo — nothing to keep in sync;
|
|
928
|
+
* the next real read (`getGkConfigMap`) populates one from scratch.
|
|
929
|
+
*/
|
|
930
|
+
recordGkConfigWrite(repoPath, key, value) {
|
|
931
|
+
if (!branchOverviewGkConfigKeysRegex.test(key))
|
|
932
|
+
return;
|
|
933
|
+
const commonPath = this.getCommonPath(repoPath);
|
|
934
|
+
const snapshot = this._gkConfigMergeSnapshots.get(commonPath);
|
|
935
|
+
if (snapshot == null)
|
|
936
|
+
return;
|
|
937
|
+
// Copy-on-write: a reconcile in flight is holding this map as its `priorSnapshot` baseline, so
|
|
938
|
+
// mutating it in place would silently move that baseline mid-diff.
|
|
939
|
+
const next = new Map(snapshot);
|
|
940
|
+
if (value == null) {
|
|
941
|
+
next.delete(key);
|
|
942
|
+
}
|
|
943
|
+
else {
|
|
944
|
+
next.set(key, value);
|
|
945
|
+
}
|
|
946
|
+
this._gkConfigMergeSnapshots.set(commonPath, next);
|
|
947
|
+
}
|
|
948
|
+
/**
|
|
949
|
+
* Registers the reconciler invoked by {@link handleGkConfigChanged} on a watcher-observed
|
|
950
|
+
* `'gkConfig'` change. Only one reconciler is kept — later registrations replace earlier ones,
|
|
951
|
+
* which is harmless since every CLI config sub-provider sharing this `Cache` reconciles the same
|
|
952
|
+
* underlying `.git/gk/config` file identically.
|
|
953
|
+
*/
|
|
954
|
+
setGkConfigReconciler(reconciler) {
|
|
955
|
+
this._gkConfigReconciler = reconciler;
|
|
956
|
+
}
|
|
957
|
+
/**
|
|
958
|
+
* Diffs a freshly-read gk config map's merge-relevant subset against `priorSnapshot` (captured by
|
|
959
|
+
* `handleGkConfigChanged` before the reconcile started, so it reflects the pre-change state even
|
|
960
|
+
* though this call's own re-read already raced ahead and refreshed the live snapshot), cascading
|
|
961
|
+
* `baseBranchName`/`branchOverviews` for every ref whose merge-relevant key actually changed.
|
|
962
|
+
* `priorSnapshot` of `undefined` (never observed before this reconcile) is treated as "everything
|
|
963
|
+
* may have changed" — a full coarse clear, same as the pre-existing watcher behavior. Returns
|
|
964
|
+
* whether anything changed (i.e. whether a follow-up repository-changed event is warranted).
|
|
965
|
+
*/
|
|
966
|
+
reconcileGkConfigMap(repoPath, priorSnapshot, freshMap) {
|
|
967
|
+
const commonPath = this.getCommonPath(repoPath);
|
|
968
|
+
const newSubset = this.extractMergeRelevantGkConfig(freshMap);
|
|
969
|
+
this._gkConfigMergeSnapshots.set(commonPath, newSubset);
|
|
970
|
+
if (priorSnapshot == null) {
|
|
971
|
+
this.evictShared('baseBranchName', repoPath);
|
|
972
|
+
this.evictShared('branchOverviews', repoPath);
|
|
973
|
+
return true;
|
|
974
|
+
}
|
|
975
|
+
let changed = false;
|
|
976
|
+
for (const key of new Set([...priorSnapshot.keys(), ...newSubset.keys()])) {
|
|
977
|
+
if (priorSnapshot.get(key) !== newSubset.get(key)) {
|
|
978
|
+
changed = true;
|
|
979
|
+
this.cascadeGkConfigKeyChange(commonPath, key);
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
return changed;
|
|
983
|
+
}
|
|
984
|
+
/**
|
|
985
|
+
* Shared per-ref cascade for a changed `branch.<ref>.gk-...` key: invalidates `baseBranchName` (for
|
|
986
|
+
* `gk-merge-base`) and `branchOverviews` (for any merge-relevant key), honoring `skipInvalidation`.
|
|
987
|
+
* Used by both a direct write (`deleteGkConfig`) and a reconciled external change
|
|
988
|
+
* (`reconcileGkConfigMap`). No-ops for keys outside the merge-relevant subset.
|
|
989
|
+
*/
|
|
990
|
+
cascadeGkConfigKeyChange(commonPath, key, skip) {
|
|
767
991
|
const refMatch = key.match(branchOverviewGkConfigKeysRegex);
|
|
768
992
|
if (refMatch == null)
|
|
769
993
|
return;
|
|
770
994
|
const ref = refMatch[1];
|
|
771
|
-
const skip = options?.skipInvalidation;
|
|
772
995
|
// `getBaseBranchName` reads `branch.<ref>.gk-merge-base` and caches the resolved value
|
|
773
|
-
// per-ref. A
|
|
774
|
-
// `getBranchContributionsOverview` will resolve `mergeTarget` against the pre-
|
|
996
|
+
// per-ref. A change to that key must invalidate the cached base or Tier 3 of
|
|
997
|
+
// `getBranchContributionsOverview` will resolve `mergeTarget` against the pre-change value.
|
|
775
998
|
if (key.endsWith('.gk-merge-base') && !skip?.includes('baseBranchName')) {
|
|
776
|
-
this._caches.baseBranchName?.delete(
|
|
999
|
+
this._caches.baseBranchName?.delete(commonPath, ref);
|
|
777
1000
|
}
|
|
778
1001
|
if (skip?.includes('branchOverviews'))
|
|
779
1002
|
return;
|
|
@@ -783,7 +1006,18 @@ export class Cache {
|
|
|
783
1006
|
// invalidate every entry for the affected ref regardless of which target it resolved to.
|
|
784
1007
|
// Uses `invalidateByKeyPrefix` (not `deleteByKeyPrefix`) so an in-flight factory is still
|
|
785
1008
|
// shared with new callers instead of triggering a duplicate fetch.
|
|
786
|
-
|
|
1009
|
+
//
|
|
1010
|
+
// Sibling worktrees get their own bucket, not just the shared one: `getSharedOrCreateWithKey`
|
|
1011
|
+
// stores a per-worktree *mapped* entry under that worktree's own path, and prefix-invalidation
|
|
1012
|
+
// only reaches one bucket. The in-flight case self-propagates on settle, but an already-settled
|
|
1013
|
+
// overview would otherwise survive here — which the coarse `evictShared` path this replaced did
|
|
1014
|
+
// clear, since it iterated the worktrees.
|
|
1015
|
+
this._caches.branchOverviews?.invalidateByKeyPrefix(commonPath, `${ref}|`);
|
|
1016
|
+
for (const worktreePath of this.getWorktreePaths(commonPath)) {
|
|
1017
|
+
if (worktreePath === commonPath)
|
|
1018
|
+
continue;
|
|
1019
|
+
this._caches.branchOverviews?.invalidateByKeyPrefix(worktreePath, `${ref}|`);
|
|
1020
|
+
}
|
|
787
1021
|
}
|
|
788
1022
|
async getBranchOverview(repoPath, cacheKey, factory, options) {
|
|
789
1023
|
return this.getSharedOrCreateWithKey(this.branchOverviews, repoPath, cacheKey, factory, (data, newRepoPath) => data == null
|
|
@@ -808,9 +1042,31 @@ export class Cache {
|
|
|
808
1042
|
}
|
|
809
1043
|
getBaseBranchName(repoPath, ref, factory, cancellation) {
|
|
810
1044
|
return this.getSharedSimpleWithKey(this.baseBranchName, repoPath, ref, factory, {
|
|
1045
|
+
// A bounded ceiling, because the eviction signals can't cover every way a base changes. The
|
|
1046
|
+
// `'branches'` cascade deliberately doesn't clear this — a tip move can't change a base, and
|
|
1047
|
+
// re-deriving per commit is the cost this exists to avoid — but that leaves a hole: a branch
|
|
1048
|
+
// deleted and recreated OUTSIDE GitLens, and never checked out, emits only `heads`. A base
|
|
1049
|
+
// derived as "none" before that would otherwise stay "none" for the session.
|
|
1050
|
+
//
|
|
1051
|
+
// `createTTL`, NOT `accessTTL`: the sliding variant resets on every read, so a branch card
|
|
1052
|
+
// polling this entry would hold it alive forever and never re-derive — the exact case the
|
|
1053
|
+
// ceiling exists for. Absolute from creation bounds staleness regardless of read frequency.
|
|
1054
|
+
createTTL: baseBranchNameTTL,
|
|
811
1055
|
cancellation: cancellation,
|
|
812
1056
|
});
|
|
813
1057
|
}
|
|
1058
|
+
/**
|
|
1059
|
+
* Clears the cached base branch for `ref`. Call from ops that create/rename/delete a branch — the
|
|
1060
|
+
* `'branches'` cascade no longer clears these, since tip movement can't change a branch's base.
|
|
1061
|
+
*
|
|
1062
|
+
* Only clears the cache. A branch's base is *persisted* as `branch.<ref>.gk-merge-base` and read back
|
|
1063
|
+
* before the reflog fallback, so an op that ends a branch's identity under a name must drop or move
|
|
1064
|
+
* that key too (`removeGkConfigBranchSection`/`renameGkConfigBranchSection`) — otherwise the
|
|
1065
|
+
* re-derivation this triggers just reads the stale value straight back.
|
|
1066
|
+
*/
|
|
1067
|
+
deleteBaseBranchName(repoPath, ref) {
|
|
1068
|
+
this._caches.baseBranchName?.delete(this.getCommonPath(repoPath), ref);
|
|
1069
|
+
}
|
|
814
1070
|
getBranchMergedStatus(repoPath, cacheKey, factory, cancellation) {
|
|
815
1071
|
return this.getSharedOrCreateWithKey(this.branchMergedStatus, repoPath, cacheKey, factory, (data, newRepoPath) => {
|
|
816
1072
|
if (!data.merged)
|
|
@@ -834,8 +1090,14 @@ export class Cache {
|
|
|
834
1090
|
getBranchMetadataMap(repoPath, factory) {
|
|
835
1091
|
return this.getSharedSimple(this.branchMetadataMap, repoPath, factory);
|
|
836
1092
|
}
|
|
837
|
-
getDefaultBranchName(repoPath, remote, factory) {
|
|
838
|
-
return this.getSharedSimpleWithKey(this.defaultBranchName, repoPath, remote, factory
|
|
1093
|
+
getDefaultBranchName(repoPath, remote, factory, cancellation) {
|
|
1094
|
+
return this.getSharedSimpleWithKey(this.defaultBranchName, repoPath, remote, factory, {
|
|
1095
|
+
cancellation: cancellation,
|
|
1096
|
+
});
|
|
1097
|
+
}
|
|
1098
|
+
/** Clears the cached default branch for one `remote` key (the networked lookup or its `:local` variant). */
|
|
1099
|
+
deleteDefaultBranchName(repoPath, remote) {
|
|
1100
|
+
this._caches.defaultBranchName?.delete(this.getCommonPath(repoPath), remote);
|
|
839
1101
|
}
|
|
840
1102
|
getInitialCommitSha(repoPath, factory) {
|
|
841
1103
|
return this.getSharedSimple(this.initialCommitSha, repoPath, factory);
|
|
@@ -956,19 +1218,26 @@ export class Cache {
|
|
|
956
1218
|
}
|
|
957
1219
|
return sharedPromise;
|
|
958
1220
|
}
|
|
959
|
-
async getSharedSimple(cache, repoPath,
|
|
1221
|
+
async getSharedSimple(cache, repoPath,
|
|
1222
|
+
// `cacheable` is forwarded so a factory can refuse the entry when the read FAILED rather than
|
|
1223
|
+
// genuinely produced nothing — see `getSharedSimpleWithKey` for why that distinction matters.
|
|
1224
|
+
factory) {
|
|
960
1225
|
const commonPath = this.getCommonPath(repoPath);
|
|
961
1226
|
// `PromiseMap.getOrCreate(key, factory, cancellation?)` and
|
|
962
1227
|
// `PromiseCache.getOrCreate(key, factory, options?)` have different 3rd-argument shapes,
|
|
963
1228
|
// so we dispatch on cache type. Both register a `CacheController` so `invalidate` works.
|
|
964
1229
|
if (cache instanceof PromiseCache) {
|
|
965
|
-
return cache.getOrCreate(commonPath,
|
|
1230
|
+
return cache.getOrCreate(commonPath, cacheable => Promise.resolve(factory(commonPath, cacheable)));
|
|
966
1231
|
}
|
|
967
|
-
return cache.getOrCreate(commonPath,
|
|
1232
|
+
return cache.getOrCreate(commonPath, cacheable => Promise.resolve(factory(commonPath, cacheable)));
|
|
968
1233
|
}
|
|
969
|
-
async getSharedSimpleWithKey(cache, repoPath, cacheKey,
|
|
1234
|
+
async getSharedSimpleWithKey(cache, repoPath, cacheKey,
|
|
1235
|
+
// `cacheable` is forwarded so a factory can distinguish "the answer is genuinely nothing" from "the
|
|
1236
|
+
// read failed": callers here set no TTL by default, so a failure resolved as `undefined` would
|
|
1237
|
+
// otherwise be served as a real answer until something explicitly evicts it.
|
|
1238
|
+
factory, options) {
|
|
970
1239
|
const commonPath = this.getCommonPath(repoPath);
|
|
971
|
-
return cache.getOrCreate(commonPath, cacheKey, (
|
|
1240
|
+
return cache.getOrCreate(commonPath, cacheKey, (cacheable, signal) => Promise.resolve(factory(commonPath, cacheable, signal)), options);
|
|
972
1241
|
}
|
|
973
1242
|
}
|
|
974
1243
|
__decorate([
|