@gitkraken/core-gitlens 0.5.109 → 0.5.111
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 +48 -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 +119 -2
- package/dist/git/models/pullRequest.d.ts.map +1 -1
- package/dist/git/models/pullRequest.js +27 -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 +24 -1
- package/dist/git/utils/pullRequest.utils.d.ts.map +1 -1
- package/dist/git/utils/pullRequest.utils.js +71 -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 +92 -4
- package/dist/plus/git-github/api/github.d.ts.map +1 -1
- package/dist/plus/git-github/api/github.js +324 -20
- package/dist/plus/git-github/api/github.js.map +1 -1
- package/dist/plus/git-github/api/pullRequestSearchQuery.d.ts +27 -1
- package/dist/plus/git-github/api/pullRequestSearchQuery.d.ts.map +1 -1
- package/dist/plus/git-github/api/pullRequestSearchQuery.js +73 -6
- package/dist/plus/git-github/api/pullRequestSearchQuery.js.map +1 -1
- package/dist/plus/git-github/models.d.ts +33 -5
- package/dist/plus/git-github/models.d.ts.map +1 -1
- package/dist/plus/git-github/models.js +43 -4
- 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/integrationService.d.ts +16 -1
- package/dist/plus/integrations/integrationService.d.ts.map +1 -1
- package/dist/plus/integrations/integrationService.js +9 -1
- package/dist/plus/integrations/integrationService.js.map +1 -1
- package/dist/plus/integrations/manager.d.ts +45 -5
- package/dist/plus/integrations/manager.d.ts.map +1 -1
- package/dist/plus/integrations/models/gitHostIntegration.d.ts +18 -3
- package/dist/plus/integrations/models/gitHostIntegration.d.ts.map +1 -1
- package/dist/plus/integrations/models/gitHostIntegration.js +30 -2
- package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
- package/dist/plus/integrations/models/integration.d.ts +4 -2
- 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/providerFilters.d.ts +1 -1
- package/dist/plus/integrations/providerFilters.d.ts.map +1 -1
- package/dist/plus/integrations/providers/accounts.d.ts +6 -0
- package/dist/plus/integrations/providers/accounts.d.ts.map +1 -0
- package/dist/plus/integrations/providers/accounts.js +34 -0
- package/dist/plus/integrations/providers/accounts.js.map +1 -0
- 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 +23 -2
- package/dist/plus/integrations/providers/github.d.ts.map +1 -1
- package/dist/plus/integrations/providers/github.js +169 -138
- package/dist/plus/integrations/providers/github.js.map +1 -1
- package/dist/plus/integrations/providers/gitlab.d.ts +9 -0
- package/dist/plus/integrations/providers/gitlab.d.ts.map +1 -1
- package/dist/plus/integrations/providers/gitlab.js +23 -4
- package/dist/plus/integrations/providers/gitlab.js.map +1 -1
- package/dist/plus/integrations/providers/models.d.ts +14 -32
- package/dist/plus/integrations/providers/models.d.ts.map +1 -1
- package/dist/plus/integrations/providers/models.js +66 -109
- package/dist/plus/integrations/providers/models.js.map +1 -1
- package/dist/plus/integrations/providers/pullRequestReviews.d.ts +50 -0
- package/dist/plus/integrations/providers/pullRequestReviews.d.ts.map +1 -0
- package/dist/plus/integrations/providers/pullRequestReviews.js +99 -0
- package/dist/plus/integrations/providers/pullRequestReviews.js.map +1 -0
- 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/counts.d.ts +55 -0
- package/dist/plus/integrations/reads/counts.d.ts.map +1 -1
- package/dist/plus/integrations/reads/counts.js +146 -2
- package/dist/plus/integrations/reads/counts.js.map +1 -1
- package/dist/plus/integrations/reads/drains.d.ts +7 -1
- package/dist/plus/integrations/reads/drains.d.ts.map +1 -1
- package/dist/plus/integrations/reads/drains.js +20 -6
- package/dist/plus/integrations/reads/drains.js.map +1 -1
- package/dist/plus/integrations/reads/filters.d.ts.map +1 -1
- package/dist/plus/integrations/reads/filters.js +22 -0
- package/dist/plus/integrations/reads/filters.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/plus/integrations/reads/searchPullRequests.d.ts +4 -3
- package/dist/plus/integrations/reads/searchPullRequests.d.ts.map +1 -1
- package/dist/plus/integrations/reads/searchPullRequests.js +6 -4
- package/dist/plus/integrations/reads/searchPullRequests.js.map +1 -1
- package/dist/plus/integrations/reads/sweeps.js +1 -1
- package/dist/plus/integrations/reads/sweeps.js.map +1 -1
- package/dist/plus/integrations/reads/warnings.d.ts +2 -2
- package/dist/plus/integrations/reads/warnings.d.ts.map +1 -1
- package/dist/plus/integrations/reads/warnings.js +11 -2
- package/dist/plus/integrations/reads/warnings.js.map +1 -1
- package/dist/plus/integrations/results.d.ts +6 -1
- package/dist/plus/integrations/results.d.ts.map +1 -1
- package/dist/plus/integrations/results.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/docs/integrations.md +76 -10
- package/docs/kepler-read-api-parity.md +9 -0
- 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 +117 -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 +86 -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 +467 -23
- package/src/plus/git-github/api/pullRequestSearchQuery.ts +81 -7
- package/src/plus/git-github/models.ts +77 -7
- 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/integrationService.ts +25 -2
- package/src/plus/integrations/manager.ts +50 -5
- package/src/plus/integrations/models/gitHostIntegration.ts +54 -2
- package/src/plus/integrations/models/integration.ts +24 -13
- package/src/plus/integrations/providerFilters.ts +6 -1
- package/src/plus/integrations/providers/accounts.ts +38 -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 +218 -145
- package/src/plus/integrations/providers/gitlab.ts +30 -20
- package/src/plus/integrations/providers/models.ts +99 -127
- package/src/plus/integrations/providers/pullRequestReviews.ts +122 -0
- package/src/plus/integrations/reads/broaden.ts +6 -1
- package/src/plus/integrations/reads/counts.ts +273 -2
- package/src/plus/integrations/reads/drains.ts +19 -6
- package/src/plus/integrations/reads/filters.ts +22 -0
- 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/plus/integrations/reads/searchPullRequests.ts +12 -4
- package/src/plus/integrations/reads/sweeps.ts +1 -1
- package/src/plus/integrations/reads/warnings.ts +12 -1
- package/src/plus/integrations/results.ts +6 -1
- 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
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { IssueSearchCriteria } from '../../../git/models/issue.js';
|
|
2
|
+
import type { PullRequestSearchCriteria } from '../../../git/models/pullRequest.js';
|
|
2
3
|
import { chunk } from '../../../utils/array.js';
|
|
3
4
|
import { mapBounded } from '../../../utils/promise.js';
|
|
4
5
|
import type { IntegrationIds } from '../constants.js';
|
|
@@ -14,12 +15,18 @@ import {
|
|
|
14
15
|
} from '../utils/integration.utils.js';
|
|
15
16
|
import type { ProviderReadContext } from './context.js';
|
|
16
17
|
import { runCaptured } from './drains.js';
|
|
17
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
resolveIssueSearchCriteria,
|
|
20
|
+
resolveIssueSearchScope,
|
|
21
|
+
resolvePullRequestSearchCriteria,
|
|
22
|
+
resolvePullRequestSearchScope,
|
|
23
|
+
} from './filters.js';
|
|
18
24
|
import {
|
|
19
25
|
gitHostOnlySurfaceWarning,
|
|
20
26
|
issuesUnsupportedWarning,
|
|
21
27
|
otherWarning,
|
|
22
28
|
unsupportedIssueSearchCriteriaWarning,
|
|
29
|
+
unsupportedPullRequestSearchCriteriaWarning,
|
|
23
30
|
} from './warnings.js';
|
|
24
31
|
|
|
25
32
|
/**
|
|
@@ -32,6 +39,15 @@ import {
|
|
|
32
39
|
*/
|
|
33
40
|
const issueCountChunkSize = 25;
|
|
34
41
|
|
|
42
|
+
/**
|
|
43
|
+
* How many pull-request scopes go into one upstream request.
|
|
44
|
+
*
|
|
45
|
+
* The same latency/complexity reasoning as {@link issueCountChunkSize}, kept slightly smaller because a pull-request
|
|
46
|
+
* scope can fan out into one aliased count PER requested state (open/closed/merged), so a chunk of scopes carries a
|
|
47
|
+
* small multiple of that many `search` aliases.
|
|
48
|
+
*/
|
|
49
|
+
const pullRequestCountChunkSize = 15;
|
|
50
|
+
|
|
35
51
|
/**
|
|
36
52
|
* One scope to count.
|
|
37
53
|
*
|
|
@@ -73,6 +89,42 @@ export interface IssueCountResult {
|
|
|
73
89
|
providerLimit?: number;
|
|
74
90
|
}
|
|
75
91
|
|
|
92
|
+
/**
|
|
93
|
+
* One scope to count pull requests over — the PR twin of {@link IssueCountScope}.
|
|
94
|
+
*
|
|
95
|
+
* `key` is caller-owned and echoed back verbatim, never reaching the provider query (the aliases are generated), so
|
|
96
|
+
* it can be any string the caller finds meaningful.
|
|
97
|
+
*/
|
|
98
|
+
export interface PullRequestCountScope {
|
|
99
|
+
key: string;
|
|
100
|
+
/** Repositories to count over. Combines with `org`, exactly as in `searchPullRequestsPage`. */
|
|
101
|
+
repos?: ProviderReposInput;
|
|
102
|
+
org?: string;
|
|
103
|
+
/**
|
|
104
|
+
* Same criteria model as `searchPullRequestsPage`, validated against the same capability table — so a count
|
|
105
|
+
* refuses exactly what the read would, and never previews a fetch that can't happen.
|
|
106
|
+
*/
|
|
107
|
+
criteria?: PullRequestSearchCriteria;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** The count for one {@link PullRequestCountScope}, echoed back under the caller's own `key`. */
|
|
111
|
+
export interface PullRequestCountResult {
|
|
112
|
+
key: string;
|
|
113
|
+
/**
|
|
114
|
+
* Total matches the provider reports. `undefined` when the provider didn't report one for this scope — NEVER
|
|
115
|
+
* zero, which is a real answer. For a multi-state scope this is the LARGEST of its per-state counts, the same
|
|
116
|
+
* total `searchPullRequestsPage` surfaces, not their sum.
|
|
117
|
+
*/
|
|
118
|
+
count?: number;
|
|
119
|
+
/**
|
|
120
|
+
* True when `count` exceeds the provider's own per-search result ceiling, so a full read CANNOT return
|
|
121
|
+
* everything no matter how it is paged. This is the signal to warn before starting an expensive fetch.
|
|
122
|
+
*/
|
|
123
|
+
exceedsProviderLimit: boolean;
|
|
124
|
+
/** The ceiling itself, when the provider declares one. */
|
|
125
|
+
providerLimit?: number;
|
|
126
|
+
}
|
|
127
|
+
|
|
76
128
|
/**
|
|
77
129
|
* Counts issues for many scopes without fetching any — the probe behind a "this will fetch ~N issues" preview.
|
|
78
130
|
*
|
|
@@ -228,7 +280,7 @@ export async function countIssues(
|
|
|
228
280
|
}
|
|
229
281
|
|
|
230
282
|
/** The first key that appears twice, or `undefined` when every key is unique. */
|
|
231
|
-
function findDuplicateKey(scopes: readonly
|
|
283
|
+
function findDuplicateKey(scopes: readonly { key: string }[]): string | undefined {
|
|
232
284
|
const seen = new Set<string>();
|
|
233
285
|
for (const scope of scopes) {
|
|
234
286
|
if (seen.has(scope.key)) return scope.key;
|
|
@@ -290,3 +342,222 @@ function rejectScope(
|
|
|
290
342
|
|
|
291
343
|
return undefined;
|
|
292
344
|
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Counts pull requests for many scopes without fetching any — the PR twin of {@link countIssues}, and the probe
|
|
348
|
+
* behind a "this will fetch ~N pull requests" preview.
|
|
349
|
+
*
|
|
350
|
+
* Identical batching, per-scope isolation, and `key`-echo contract as {@link countIssues}; see it for the cost
|
|
351
|
+
* model and the `count: undefined` ≠ zero rule. The one difference is inherent to pull requests: a scope's criteria
|
|
352
|
+
* can name several STATES, which the provider counts as independent searches — the reported `count` is the LARGEST
|
|
353
|
+
* of them (mirroring `searchPullRequestsPage`'s total), so an unpaged read still can't exceed a single search's
|
|
354
|
+
* ceiling undetected.
|
|
355
|
+
*/
|
|
356
|
+
export async function countPullRequests(
|
|
357
|
+
ctx: ProviderReadContext,
|
|
358
|
+
options: {
|
|
359
|
+
providerId: IntegrationIds;
|
|
360
|
+
scopes: readonly PullRequestCountScope[];
|
|
361
|
+
connectionId?: string;
|
|
362
|
+
/**
|
|
363
|
+
* Explicit self-managed host domain. Used only when the requested connection has no configured domain;
|
|
364
|
+
* it must come from the trusted authentication configuration, not repository or remote data.
|
|
365
|
+
*/
|
|
366
|
+
domain?: string;
|
|
367
|
+
},
|
|
368
|
+
): Promise<ProviderResult<PullRequestCountResult>> {
|
|
369
|
+
const refused = (warning: ProviderWarning): ProviderResult<PullRequestCountResult> => ({
|
|
370
|
+
items: [],
|
|
371
|
+
warnings: [warning],
|
|
372
|
+
fetchFailed: true,
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
if (isIssuesHostIntegrationId(options.providerId)) {
|
|
376
|
+
return refused(
|
|
377
|
+
gitHostOnlySurfaceWarning(options.providerId, undefined, options.connectionId, 'Pull request counts'),
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Nothing was asked for, so nothing is missing: an empty success, not a refusal.
|
|
382
|
+
if (options.scopes.length === 0) return { items: [], warnings: [] };
|
|
383
|
+
|
|
384
|
+
const duplicateKey = findDuplicateKey(options.scopes);
|
|
385
|
+
if (duplicateKey != null) {
|
|
386
|
+
// Refuses the whole call rather than deduping: `key` exists so the caller can match results without
|
|
387
|
+
// positional bookkeeping, and two results under one key make that ambiguous for EVERY scope, not just the
|
|
388
|
+
// repeated one.
|
|
389
|
+
return refused(
|
|
390
|
+
otherWarning(
|
|
391
|
+
options.providerId,
|
|
392
|
+
undefined,
|
|
393
|
+
options.connectionId,
|
|
394
|
+
`Duplicate pull request count scope key '${duplicateKey}'; keys identify results, so each must be unique.`,
|
|
395
|
+
),
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
const integration = await ctx.getIntegrationForRead(options.providerId, options.connectionId, options.domain);
|
|
400
|
+
if (integration == null) {
|
|
401
|
+
// A supplied connection or domain that no longer resolves is a broken target, not an empty account.
|
|
402
|
+
const early = ctx.earlyReturnConnectionWarnings(options.providerId, options.connectionId, options.domain);
|
|
403
|
+
return { items: [], warnings: early.warnings, fetchFailed: early.fetchFailed || undefined };
|
|
404
|
+
}
|
|
405
|
+
if (!isGitHostIntegration(integration)) {
|
|
406
|
+
return refused(
|
|
407
|
+
gitHostOnlySurfaceWarning(options.providerId, undefined, options.connectionId, 'Pull request counts'),
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const domain = ctx.domainForRead(integration, options.providerId, options.connectionId, options.domain);
|
|
412
|
+
const warnOnMissingSession = warnOnMissingSessionForDomain(options.providerId, options.domain);
|
|
413
|
+
|
|
414
|
+
// A provider with no filtered pull-request search has no count either: refuse ONCE for the provider rather than
|
|
415
|
+
// letting every scope repeat the same rejection. `undefined` criteria probes only the search's existence.
|
|
416
|
+
const searchSupport = resolvePullRequestSearchCriteria(options.providerId, undefined);
|
|
417
|
+
if (searchSupport.rejection != null) {
|
|
418
|
+
return refused(
|
|
419
|
+
unsupportedPullRequestSearchCriteriaWarning(
|
|
420
|
+
options.providerId,
|
|
421
|
+
domain,
|
|
422
|
+
options.connectionId,
|
|
423
|
+
searchSupport.rejection,
|
|
424
|
+
),
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
const providerLimit = providersMetadata[options.providerId]?.pullRequestSearchResultLimit;
|
|
429
|
+
const warnings: ProviderWarning[] = [];
|
|
430
|
+
let fetchFailed = false;
|
|
431
|
+
|
|
432
|
+
// Validate every scope first, so a refusal costs no request at all and the countable ones are still batched
|
|
433
|
+
// together.
|
|
434
|
+
const countable: PullRequestCountScope[] = [];
|
|
435
|
+
for (const scope of options.scopes) {
|
|
436
|
+
const warning = rejectPullRequestScope(options.providerId, domain, options.connectionId, scope);
|
|
437
|
+
if (warning != null) {
|
|
438
|
+
// `push`, not `appendDedupedWarning`: every rejection message embeds the scope's own key, and duplicate
|
|
439
|
+
// keys were already refused above, so no two of these can ever collapse.
|
|
440
|
+
warnings.push(warning);
|
|
441
|
+
fetchFailed = true;
|
|
442
|
+
continue;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
countable.push(scope);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// Chunks are independent requests over their own slice of scopes, `runCaptured` never throws, so they run
|
|
449
|
+
// concurrently, bounded like every other fan-out on the facade. `mapBounded` returns in input order, so `items`
|
|
450
|
+
// and `warnings` stay in scope order.
|
|
451
|
+
const batches = await mapBounded(chunk(countable, pullRequestCountChunkSize), providerFanOutConcurrency, batch =>
|
|
452
|
+
runCaptured(
|
|
453
|
+
options.providerId,
|
|
454
|
+
domain,
|
|
455
|
+
options.connectionId,
|
|
456
|
+
() =>
|
|
457
|
+
integration.countPullRequestsResult(
|
|
458
|
+
batch.map(s => ({
|
|
459
|
+
repos: s.repos as ProviderRepoInput[] | undefined,
|
|
460
|
+
org: s.org,
|
|
461
|
+
criteria: s.criteria,
|
|
462
|
+
})),
|
|
463
|
+
undefined,
|
|
464
|
+
options.connectionId,
|
|
465
|
+
),
|
|
466
|
+
{ warnOnMissingSession: warnOnMissingSession },
|
|
467
|
+
).then(result => ({ batch: batch, ...result })),
|
|
468
|
+
);
|
|
469
|
+
|
|
470
|
+
const items: PullRequestCountResult[] = [];
|
|
471
|
+
for (const { batch, value, warning } of batches) {
|
|
472
|
+
if (warning != null) {
|
|
473
|
+
appendDedupedWarning(warnings, warning);
|
|
474
|
+
}
|
|
475
|
+
if (value == null) {
|
|
476
|
+
// This batch contributes nothing, but the batches around it still do. Drop only these scopes.
|
|
477
|
+
fetchFailed = true;
|
|
478
|
+
continue;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
for (let i = 0; i < batch.length; i++) {
|
|
482
|
+
const count = value[i];
|
|
483
|
+
items.push({
|
|
484
|
+
key: batch[i].key,
|
|
485
|
+
count: count,
|
|
486
|
+
// Only a reported count can exceed a declared ceiling; unknown-vs-limit is not a comparison.
|
|
487
|
+
exceedsProviderLimit: count != null && providerLimit != null && count > providerLimit,
|
|
488
|
+
providerLimit: providerLimit,
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// A provider that reported nothing for any scope and raised no warning: say so explicitly rather than letting it
|
|
494
|
+
// read as "every scope matched nothing".
|
|
495
|
+
if (items.length === 0 && warnings.length === 0) {
|
|
496
|
+
return refused(
|
|
497
|
+
unsupportedPullRequestSearchCriteriaWarning(options.providerId, domain, options.connectionId, {
|
|
498
|
+
reason: 'unsupported-search',
|
|
499
|
+
}),
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
return { items: items, warnings: warnings, fetchFailed: fetchFailed || undefined };
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* Why one pull-request scope can't be counted, as the warning to report — or `undefined` when it can. The PR twin
|
|
508
|
+
* of {@link rejectScope}, validating against the same {@link resolvePullRequestSearchScope} /
|
|
509
|
+
* {@link resolvePullRequestSearchCriteria} the read uses, so a count always previews the constraints the read
|
|
510
|
+
* would apply.
|
|
511
|
+
*/
|
|
512
|
+
function rejectPullRequestScope(
|
|
513
|
+
providerId: IntegrationIds,
|
|
514
|
+
domain: string | undefined,
|
|
515
|
+
connectionId: string | undefined,
|
|
516
|
+
scope: PullRequestCountScope,
|
|
517
|
+
): ProviderWarning | undefined {
|
|
518
|
+
const scoping = resolvePullRequestSearchScope(providerId, scope.repos, scope.org, scope.criteria);
|
|
519
|
+
switch (scoping.rejection) {
|
|
520
|
+
case 'repo-ids':
|
|
521
|
+
return otherWarning(
|
|
522
|
+
providerId,
|
|
523
|
+
domain,
|
|
524
|
+
connectionId,
|
|
525
|
+
`Pull request count scope '${scope.key}' cannot be scoped by repository id; pass repository descriptors (namespace + name) instead.`,
|
|
526
|
+
);
|
|
527
|
+
case 'unscoped':
|
|
528
|
+
return otherWarning(
|
|
529
|
+
providerId,
|
|
530
|
+
domain,
|
|
531
|
+
connectionId,
|
|
532
|
+
`Pull request count scope '${scope.key}' is unscoped; pass \`repos\`, \`org\`, or at least one current-user relationship.`,
|
|
533
|
+
);
|
|
534
|
+
case 'unsupported-repository-scope':
|
|
535
|
+
case 'unsupported-organization-scope':
|
|
536
|
+
return unsupportedPullRequestSearchCriteriaWarning(providerId, domain, connectionId, {
|
|
537
|
+
reason: 'unsupported-criteria',
|
|
538
|
+
criteria: [
|
|
539
|
+
scoping.rejection === 'unsupported-repository-scope' ? 'repositoryScope' : 'organizationScope',
|
|
540
|
+
],
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
const resolved = resolvePullRequestSearchCriteria(providerId, scope.criteria);
|
|
545
|
+
if (resolved.rejection != null) {
|
|
546
|
+
return unsupportedPullRequestSearchCriteriaWarning(providerId, domain, connectionId, resolved.rejection);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// Count-only, with no counterpart in the read: a relationship set is an OR across several searches, which one
|
|
550
|
+
// count can't express — summing would double-count overlaps and max would under-report. Ask the caller to count
|
|
551
|
+
// each relationship as its own scope, where the keys make the OR explicit. (States are disjoint, so a scope may
|
|
552
|
+
// still name several — the provider counts them as the max, not a refusal.)
|
|
553
|
+
if ((scope.criteria?.relationships?.length ?? 0) > 1) {
|
|
554
|
+
return otherWarning(
|
|
555
|
+
providerId,
|
|
556
|
+
domain,
|
|
557
|
+
connectionId,
|
|
558
|
+
`Pull request count scope '${scope.key}' requests several relationships, which a single count can't express (they are OR-ed, so overlapping matches would be double-counted); pass one scope per relationship.`,
|
|
559
|
+
);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
return undefined;
|
|
563
|
+
}
|
|
@@ -70,7 +70,12 @@ export async function drainPullRequests(
|
|
|
70
70
|
repos: ProviderReposInput,
|
|
71
71
|
state: PullRequestStateFilter[] | undefined,
|
|
72
72
|
filters: PullRequestFilter[] | undefined,
|
|
73
|
-
|
|
73
|
+
/**
|
|
74
|
+
* Breadth opt-ins that only the account-wide read can express. Grouped rather than passed positionally
|
|
75
|
+
* because they are same-typed neighbors a transposition would silently swap, and picked from the sweep
|
|
76
|
+
* options rather than restated so a third opt-in is declared once.
|
|
77
|
+
*/
|
|
78
|
+
accountWideOptions: Pick<PullRequestSweepOptions, 'includeReviewRequested' | 'includeReviews'> | undefined,
|
|
74
79
|
connectionId: string | undefined,
|
|
75
80
|
maxPages: number,
|
|
76
81
|
attributeUnavailableProvider: boolean,
|
|
@@ -100,6 +105,10 @@ export async function drainPullRequests(
|
|
|
100
105
|
// With no repos this is an account-wide "my PRs" sweep. The repo-scoped core rejects an empty `repos`
|
|
101
106
|
// input, so read the provider-native account-wide core instead.
|
|
102
107
|
const accountWide = repos.length === 0;
|
|
108
|
+
// The breadth opt-ins are only expressible on the account-wide core, so gate them here — the single place
|
|
109
|
+
// that already knows which core it is about to call.
|
|
110
|
+
const includeReviewRequested = accountWide && (accountWideOptions?.includeReviewRequested ?? false);
|
|
111
|
+
const includeReviews = accountWide && (accountWideOptions?.includeReviews ?? false);
|
|
103
112
|
/** Every cursor already followed, so a provider that cycles them can't keep the drain walking in circles. */
|
|
104
113
|
const seenCursors = new Set<string>();
|
|
105
114
|
|
|
@@ -115,7 +124,8 @@ export async function drainPullRequests(
|
|
|
115
124
|
cursor: pageCursor,
|
|
116
125
|
includeReviewRequested: includeReviewRequested,
|
|
117
126
|
filters: filters,
|
|
118
|
-
|
|
127
|
+
// Lite by default; the full projection (reviews) only when a caller opts in.
|
|
128
|
+
summary: !includeReviews,
|
|
119
129
|
},
|
|
120
130
|
connectionId,
|
|
121
131
|
)
|
|
@@ -164,9 +174,10 @@ export async function drainPullRequests(
|
|
|
164
174
|
|
|
165
175
|
// Composite account-wide queries can surface the same PR on different relationship/state pages
|
|
166
176
|
// (for example authored + review-requested, or closed + merged). Keep the first stable position but
|
|
167
|
-
// replace its value with the latest representation so a later, richer merged state wins.
|
|
168
|
-
//
|
|
169
|
-
// unkeyed and is retained so unrelated incomplete rows are never
|
|
177
|
+
// replace its value with the latest representation so a later, richer merged state wins. Repository
|
|
178
|
+
// identity is what keys a row (see `getProviderPullRequestIdentity`), falling back to the canonical
|
|
179
|
+
// URL; a row with neither stays unkeyed and is retained so unrelated incomplete rows are never
|
|
180
|
+
// collapsed.
|
|
170
181
|
for (const pullRequest of value.values) {
|
|
171
182
|
const identity = getProviderPullRequestIdentity(pullRequest);
|
|
172
183
|
if (identity == null) {
|
|
@@ -309,7 +320,9 @@ export async function drainRepositories(
|
|
|
309
320
|
{ warnOnMissingSession: true },
|
|
310
321
|
);
|
|
311
322
|
if (warning != null) {
|
|
312
|
-
|
|
323
|
+
// Deduped, like every other accumulation here: a soft warning (`{ value, error }`) repeats verbatim on
|
|
324
|
+
// each page that hits the same condition, and the array's contract is that no two entries are equal.
|
|
325
|
+
appendDedupedWarning(warnings, warning);
|
|
313
326
|
}
|
|
314
327
|
if (value == null) {
|
|
315
328
|
const interruptedAfterProgress = page > 1;
|
|
@@ -104,9 +104,25 @@ export function resolvePullRequestSearchCriteria(
|
|
|
104
104
|
if (criteria.text != null && criteria.text.trim().length > 0 && !supported.text) {
|
|
105
105
|
unsupported.push('text');
|
|
106
106
|
}
|
|
107
|
+
if (criteria.updatedAfter != null && !supported.updatedAfter) {
|
|
108
|
+
unsupported.push('updatedAfter');
|
|
109
|
+
}
|
|
110
|
+
if (criteria.createdAfter != null && !supported.createdAfter) {
|
|
111
|
+
unsupported.push('createdAfter');
|
|
112
|
+
}
|
|
107
113
|
if (criteria.includeArchived === true && !supported.includeArchived) {
|
|
108
114
|
unsupported.push('includeArchived');
|
|
109
115
|
}
|
|
116
|
+
// `!= null`, not truthy: `draft: false` (only ready-for-review) is as much a request as `draft: true`.
|
|
117
|
+
if (criteria.draft != null && !supported.draft) {
|
|
118
|
+
unsupported.push('draft');
|
|
119
|
+
}
|
|
120
|
+
// Folded into the same `unsupported-criteria` rejection rather than its own reason, so a caller asking for one
|
|
121
|
+
// inexpressible filter and one inexpressible sort learns about both at once. `updated:desc` is always in
|
|
122
|
+
// `sorts` for a usable search, so the omitted (default) case never rejects.
|
|
123
|
+
if (criteria.sort != null && !supported.sorts.includes(criteria.sort)) {
|
|
124
|
+
unsupported.push(`sort:${criteria.sort}`);
|
|
125
|
+
}
|
|
110
126
|
|
|
111
127
|
return unsupported.length > 0 ? { rejection: { reason: 'unsupported-criteria', criteria: unsupported } } : {};
|
|
112
128
|
}
|
|
@@ -279,9 +295,13 @@ const unsupportedPullRequestSearchCapabilities: PullRequestSearchCapabilities =
|
|
|
279
295
|
relationships: [],
|
|
280
296
|
states: [],
|
|
281
297
|
text: false,
|
|
298
|
+
updatedAfter: false,
|
|
299
|
+
createdAfter: false,
|
|
282
300
|
includeArchived: false,
|
|
301
|
+
draft: false,
|
|
283
302
|
repositoryScope: false,
|
|
284
303
|
organizationScope: false,
|
|
304
|
+
sorts: [],
|
|
285
305
|
};
|
|
286
306
|
|
|
287
307
|
/** Why a filtered issue search's scope was refused, or `undefined` when it is usable. */
|
|
@@ -428,6 +448,8 @@ export function getSupportedFilters(providerId: IntegrationIds): SupportedFilter
|
|
|
428
448
|
...pullRequestSearch,
|
|
429
449
|
relationships: [...(pullRequestSearch?.relationships ?? [])],
|
|
430
450
|
states: [...(pullRequestSearch?.states ?? [])],
|
|
451
|
+
// Copied, so mutating the result can't corrupt the metadata table.
|
|
452
|
+
sorts: [...(pullRequestSearch?.sorts ?? [])],
|
|
431
453
|
},
|
|
432
454
|
issues: [...(metadata?.supportedIssueFilters ?? [])],
|
|
433
455
|
issuesAccountWide: [...(metadata?.supportedAccountWideIssueFilters ?? [])],
|
|
@@ -291,7 +291,9 @@ export async function listRepos(
|
|
|
291
291
|
domain?: string;
|
|
292
292
|
},
|
|
293
293
|
): Promise<ProviderPagedResult<ProviderRepositoryShape>> {
|
|
294
|
-
|
|
294
|
+
// Truncated as well as floored, like every other paged read here: `page` is reported back as
|
|
295
|
+
// `page.currentPage` and bounds the cursor walk below, and neither can be fractional.
|
|
296
|
+
const page = Math.max(1, Math.trunc(options.page ?? 1));
|
|
295
297
|
if (isIssuesHostIntegrationId(options.providerId)) {
|
|
296
298
|
return refusedPage(
|
|
297
299
|
page,
|
|
@@ -9,7 +9,7 @@ import { isIssuesIntegration } from '../models/issuesIntegration.js';
|
|
|
9
9
|
import { IssueFilter, providersMetadata } from '../providers/models.js';
|
|
10
10
|
import { mergeCollectionMetadata, parsePageCursor } from '../providers/utils/providerPaging.js';
|
|
11
11
|
import type { ProviderPagedResult, ProviderWarning } from '../results.js';
|
|
12
|
-
import { reconcileOmissionsWithFailure } from '../results.js';
|
|
12
|
+
import { appendDedupedWarning, reconcileOmissionsWithFailure } from '../results.js';
|
|
13
13
|
import { isIssuesHostIntegrationId } from '../utils/integration.utils.js';
|
|
14
14
|
import type { ProviderReadContext } from './context.js';
|
|
15
15
|
import { parseIssueTrackerPageCursor, toIssueTrackerPageCursor } from './cursors.js';
|
|
@@ -279,7 +279,11 @@ export async function listIssueTrackerIssuesPage(
|
|
|
279
279
|
continue;
|
|
280
280
|
}
|
|
281
281
|
|
|
282
|
-
|
|
282
|
+
// Deduped: a captured `accountWarning` carries only the provider error, with no resource in its
|
|
283
|
+
// message, so one expired token across N resources would otherwise repeat verbatim N times. The
|
|
284
|
+
// synthesized fallback names the resource, so those stay distinct on their own.
|
|
285
|
+
appendDedupedWarning(
|
|
286
|
+
warnings,
|
|
283
287
|
accountWarning ??
|
|
284
288
|
otherWarning(
|
|
285
289
|
options.providerId,
|
|
@@ -457,7 +461,9 @@ export async function listIssueTrackerIssuesPage(
|
|
|
457
461
|
const key = projectKey(project);
|
|
458
462
|
const retryProject = result == null;
|
|
459
463
|
if (warning != null) {
|
|
460
|
-
|
|
464
|
+
// Deduped: the per-project warning is built from the provider error alone and names no project, so a
|
|
465
|
+
// single failing token repeats verbatim once per project in the window.
|
|
466
|
+
appendDedupedWarning(warnings, warning);
|
|
461
467
|
fetchFailed = true;
|
|
462
468
|
projectTruncated = true;
|
|
463
469
|
}
|
|
@@ -143,7 +143,9 @@ export async function listIssuesPage(
|
|
|
143
143
|
ctx: ProviderReadContext,
|
|
144
144
|
options: ListIssuesPageOptions,
|
|
145
145
|
): Promise<ProviderPagedResult<IssueShape>> {
|
|
146
|
-
|
|
146
|
+
// Truncated as well as floored, like every other paged read here: `page` is reported back as
|
|
147
|
+
// `page.currentPage` and compared against the position a drain reached, and neither can be fractional.
|
|
148
|
+
const page = Math.max(1, Math.trunc(options.page ?? 1));
|
|
147
149
|
if (isIssuesHostIntegrationId(options.providerId)) {
|
|
148
150
|
return refusedPage(
|
|
149
151
|
page,
|
|
@@ -487,7 +489,10 @@ async function readRepoScopedIssuesPage({
|
|
|
487
489
|
filters: options.filters,
|
|
488
490
|
includeAllAssignees: options.includeAllAssignees,
|
|
489
491
|
cursor: cursor,
|
|
490
|
-
page
|
|
492
|
+
// The normalized `page`, so the number forwarded to the provider can't disagree with the
|
|
493
|
+
// page-number cursor beside it — both are built from the same value. Only when the caller asked
|
|
494
|
+
// for one: an omitted page is the provider's own first page.
|
|
495
|
+
page: options.page != null ? page : undefined,
|
|
491
496
|
pageSize: options.itemsPerPage,
|
|
492
497
|
sort: ordering.sort,
|
|
493
498
|
},
|
|
@@ -507,14 +512,14 @@ async function readRepoScopedIssuesPage({
|
|
|
507
512
|
if (
|
|
508
513
|
issuesPagingMode === PagingMode.Repos &&
|
|
509
514
|
options.page != null &&
|
|
510
|
-
|
|
515
|
+
page > 1 &&
|
|
511
516
|
options.cursor == null &&
|
|
512
517
|
paged.page.currentPage === 1
|
|
513
518
|
) {
|
|
514
519
|
const drained = await drainToRequestedPage(
|
|
515
520
|
{ items: items, paged: paged, metadata: allMetadata, fetchFailed: pageFetchFailed },
|
|
516
521
|
{
|
|
517
|
-
requestedPage:
|
|
522
|
+
requestedPage: page,
|
|
518
523
|
itemsPerPage: options.itemsPerPage,
|
|
519
524
|
warnings: warnings,
|
|
520
525
|
readPage: (cursor: string) =>
|
|
@@ -58,7 +58,9 @@ export async function listPullRequestsPage(
|
|
|
58
58
|
domain?: string;
|
|
59
59
|
},
|
|
60
60
|
): Promise<ProviderPagedResult<PullRequestShape>> {
|
|
61
|
-
|
|
61
|
+
// Truncated as well as floored, like every other paged read here: `page` is reported back as
|
|
62
|
+
// `page.currentPage` and compared against the position a drain reached, and neither can be fractional.
|
|
63
|
+
const page = Math.max(1, Math.trunc(options.page ?? 1));
|
|
62
64
|
if (isIssuesHostIntegrationId(options.providerId)) {
|
|
63
65
|
return refusedPage(
|
|
64
66
|
page,
|
|
@@ -140,7 +142,10 @@ export async function listPullRequestsPage(
|
|
|
140
142
|
state: options.states,
|
|
141
143
|
filters: resolvedFilters.filters,
|
|
142
144
|
cursor: cursor,
|
|
143
|
-
page
|
|
145
|
+
// The normalized `page`, so the number forwarded to the provider can't disagree with the
|
|
146
|
+
// page-number cursor beside it — both are built from the same value. Only when the caller
|
|
147
|
+
// asked for one: an omitted page is the provider's own first page.
|
|
148
|
+
page: options.page != null ? page : undefined,
|
|
144
149
|
pageSize: options.itemsPerPage,
|
|
145
150
|
},
|
|
146
151
|
options.connectionId,
|
|
@@ -165,14 +170,14 @@ export async function listPullRequestsPage(
|
|
|
165
170
|
if (
|
|
166
171
|
(accountWide || providersMetadata[options.providerId]?.pullRequestsPagingMode === PagingMode.Repos) &&
|
|
167
172
|
options.page != null &&
|
|
168
|
-
|
|
173
|
+
page > 1 &&
|
|
169
174
|
options.cursor == null &&
|
|
170
175
|
paged.page.currentPage === 1
|
|
171
176
|
) {
|
|
172
177
|
const drained = await drainToRequestedPage<ProviderPullRequest>(
|
|
173
178
|
{ items: items, paged: paged, metadata: allMetadata, fetchFailed: pageFetchFailed },
|
|
174
179
|
{
|
|
175
|
-
requestedPage:
|
|
180
|
+
requestedPage: page,
|
|
176
181
|
itemsPerPage: options.itemsPerPage,
|
|
177
182
|
warnings: warnings,
|
|
178
183
|
readPage: (cursor: string) =>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { PullRequestSearchCriteria, PullRequestShape } from '../../../git/models/pullRequest.js';
|
|
2
|
+
import { defaultPullRequestSort } from '../../../git/models/pullRequest.js';
|
|
2
3
|
import type { IntegrationIds } from '../constants.js';
|
|
3
4
|
import type { ProviderReposInput } from '../providers/models.js';
|
|
4
5
|
import type { ProviderPagedResult, ProviderWarning } from '../results.js';
|
|
@@ -29,9 +30,10 @@ import {
|
|
|
29
30
|
* Pull requests matching structured criteria over a repository/organization or current-user relationship scope.
|
|
30
31
|
*
|
|
31
32
|
* The read is deliberately separate from `listPullRequestsPage`: the list has provider-specific "my PRs"
|
|
32
|
-
* semantics and no text channel, while this method promises a sanitized query,
|
|
33
|
-
*
|
|
34
|
-
* ceiling
|
|
33
|
+
* semantics and no text channel, while this method promises a sanitized query, an ordering the caller chooses
|
|
34
|
+
* (`criteria.sort`, defaulting to most-recently-updated-first) and that is applied to the merged page as a whole,
|
|
35
|
+
* one upstream request per cursor-threaded page, and a quantified omission at the provider's result ceiling that
|
|
36
|
+
* names the order the reachable window was selected under.
|
|
35
37
|
*/
|
|
36
38
|
export async function searchPullRequestsPage(
|
|
37
39
|
ctx: ProviderReadContext,
|
|
@@ -183,7 +185,13 @@ export async function searchPullRequestsPage(
|
|
|
183
185
|
const truncated = continuation.truncated;
|
|
184
186
|
if (truncated && warnings.length === 0) {
|
|
185
187
|
warnings.push(
|
|
186
|
-
pullRequestSearchCapResultWarning(
|
|
188
|
+
pullRequestSearchCapResultWarning(
|
|
189
|
+
options.providerId,
|
|
190
|
+
domain,
|
|
191
|
+
options.connectionId,
|
|
192
|
+
totalCount,
|
|
193
|
+
options.criteria?.sort ?? defaultPullRequestSort,
|
|
194
|
+
) ??
|
|
187
195
|
truncationWarning(options.providerId, domain, options.connectionId, 'Pull request search', 'exhausted'),
|
|
188
196
|
);
|
|
189
197
|
}
|
|
@@ -5,6 +5,7 @@ import type {
|
|
|
5
5
|
IssueSorting,
|
|
6
6
|
PullRequestFilter,
|
|
7
7
|
PullRequestSearchCapabilities,
|
|
8
|
+
PullRequestSorting,
|
|
8
9
|
} from '../providerFilters.js';
|
|
9
10
|
import { providersMetadata } from '../providers/models.js';
|
|
10
11
|
import type { ProviderWarning } from '../results.js';
|
|
@@ -286,9 +287,13 @@ function describePullRequestSearchCapabilities(capabilities: PullRequestSearchCa
|
|
|
286
287
|
...(capabilities.relationships.length ? [`relationships:${capabilities.relationships.join('|')}`] : []),
|
|
287
288
|
...(capabilities.states.length ? [`states:${capabilities.states.join('|')}`] : []),
|
|
288
289
|
...(capabilities.text ? ['text'] : []),
|
|
290
|
+
...(capabilities.updatedAfter ? ['updatedAfter'] : []),
|
|
291
|
+
...(capabilities.createdAfter ? ['createdAfter'] : []),
|
|
289
292
|
...(capabilities.includeArchived ? ['includeArchived'] : []),
|
|
293
|
+
...(capabilities.draft ? ['draft'] : []),
|
|
290
294
|
...(capabilities.repositoryScope ? ['repository scope'] : []),
|
|
291
295
|
...(capabilities.organizationScope ? ['organization scope'] : []),
|
|
296
|
+
...(capabilities.sorts.length ? [`sorts:${capabilities.sorts.join('|')}`] : []),
|
|
292
297
|
].join(', ');
|
|
293
298
|
}
|
|
294
299
|
|
|
@@ -464,22 +469,28 @@ export function pullRequestSearchCapResultWarning(
|
|
|
464
469
|
domain: string | undefined,
|
|
465
470
|
connectionId: string | undefined,
|
|
466
471
|
totalCount: number | undefined,
|
|
472
|
+
sort: PullRequestSorting,
|
|
467
473
|
): ProviderWarning | undefined {
|
|
468
474
|
const limit = providersMetadata[id]?.pullRequestSearchResultLimit;
|
|
469
475
|
if (limit == null || totalCount == null || totalCount <= limit) return undefined;
|
|
470
476
|
|
|
477
|
+
// Name the order: the reachable window is the first `limit` under THIS sort, and a different key reaches a
|
|
478
|
+
// different subset, so a ceiling message that omits it can't say which slice was served. Same reasoning as
|
|
479
|
+
// `issueSearchCapResultWarning`.
|
|
480
|
+
const [field, direction] = sort.split(':');
|
|
471
481
|
return {
|
|
472
482
|
...otherWarning(
|
|
473
483
|
id,
|
|
474
484
|
domain,
|
|
475
485
|
connectionId,
|
|
476
|
-
`Pull request search matched ${totalCount} results, but '${id}' serves at most ${limit}; narrow the search to read the rest.`,
|
|
486
|
+
`Pull request search matched ${totalCount} results, but '${id}' serves at most ${limit}, ordered by ${field} ${direction}ending; narrow the search to read the rest.`,
|
|
477
487
|
),
|
|
478
488
|
omission: {
|
|
479
489
|
kind: 'provider-limit',
|
|
480
490
|
recovery: 'none',
|
|
481
491
|
limit: limit,
|
|
482
492
|
totalCount: totalCount,
|
|
493
|
+
sort: sort,
|
|
483
494
|
},
|
|
484
495
|
};
|
|
485
496
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AuthenticationError, RequestNotFoundError, RequestRateLimitError } from '../../git/errors.js';
|
|
2
2
|
import type { IssueSorting } from '../../git/models/issue.js';
|
|
3
|
+
import type { PullRequestSorting } from '../../git/models/pullRequest.js';
|
|
3
4
|
import type { IntegrationIds } from './constants.js';
|
|
4
5
|
|
|
5
6
|
export interface ConnectionStateChangeEvent {
|
|
@@ -85,8 +86,12 @@ export interface ProviderWarningOmission {
|
|
|
85
86
|
* Present so a consumer can word its own "N matched, showing the first M" without assuming WHICH M: the
|
|
86
87
|
* provider serves the top M under this key, so the sentence is only true if it names it. Absent for every
|
|
87
88
|
* omission that isn't a ceiling, where no window was selected by an order.
|
|
89
|
+
*
|
|
90
|
+
* A union of both vocabularies rather than the issue one alone: `PullRequestSorting` happens to be a subset
|
|
91
|
+
* today, so narrowing this to {@link IssueSorting} would still compile while describing only half the reads
|
|
92
|
+
* that set it — and would break the day the PR search gains a key the issue search has no name for.
|
|
88
93
|
*/
|
|
89
|
-
sort?: IssueSorting;
|
|
94
|
+
sort?: IssueSorting | PullRequestSorting;
|
|
90
95
|
/** Which repository / project / resource was affected, when one is attributed. */
|
|
91
96
|
scope?: ProviderWarningOmissionScope;
|
|
92
97
|
}
|