@gitkraken/core-gitlens 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -1
- package/README.md +13 -10
- package/dist/git/cache.d.ts +12 -6
- package/dist/git/cache.d.ts.map +1 -1
- package/dist/git/cache.js +40 -39
- package/dist/git/cache.js.map +1 -1
- package/dist/git/context.d.ts +23 -3
- package/dist/git/context.d.ts.map +1 -1
- package/dist/git/context.js.map +1 -1
- package/dist/git/features.d.ts +1 -1
- package/dist/git/features.d.ts.map +1 -1
- package/dist/git/features.js +1 -0
- package/dist/git/features.js.map +1 -1
- package/dist/git/models/graph.d.ts +96 -0
- package/dist/git/models/graph.d.ts.map +1 -1
- package/dist/git/models/graph.js +24 -1
- package/dist/git/models/graph.js.map +1 -1
- package/dist/git/models/remoteProvider.d.ts +1 -0
- package/dist/git/models/remoteProvider.d.ts.map +1 -1
- package/dist/git/models/remoteProvider.js.map +1 -1
- package/dist/git/models/repository.d.ts +21 -12
- package/dist/git/models/repository.d.ts.map +1 -1
- package/dist/git/models/repository.js +70 -84
- package/dist/git/models/repository.js.map +1 -1
- package/dist/git/models/statusFile.d.ts +9 -0
- package/dist/git/models/statusFile.d.ts.map +1 -1
- package/dist/git/models/statusFile.js +11 -0
- package/dist/git/models/statusFile.js.map +1 -1
- package/dist/git/providers/commits.d.ts +4 -0
- package/dist/git/providers/commits.d.ts.map +1 -1
- package/dist/git/providers/config.d.ts +1 -3
- package/dist/git/providers/config.d.ts.map +1 -1
- package/dist/git/providers/operations.d.ts +40 -13
- package/dist/git/providers/operations.d.ts.map +1 -1
- package/dist/git/providers/worktrees.d.ts +2 -0
- package/dist/git/providers/worktrees.d.ts.map +1 -1
- package/dist/git/remotes/custom.d.ts +2 -0
- package/dist/git/remotes/custom.d.ts.map +1 -1
- package/dist/git/remotes/custom.js +20 -0
- package/dist/git/remotes/custom.js.map +1 -1
- package/dist/git/utils/conflictResolution.utils.d.ts +32 -0
- package/dist/git/utils/conflictResolution.utils.d.ts.map +1 -1
- package/dist/git/utils/conflictResolution.utils.js +95 -0
- package/dist/git/utils/conflictResolution.utils.js.map +1 -1
- package/dist/git/utils/contributor.utils.d.ts +3 -0
- package/dist/git/utils/contributor.utils.d.ts.map +1 -1
- package/dist/git/utils/contributor.utils.js +22 -0
- package/dist/git/utils/contributor.utils.js.map +1 -1
- package/dist/git/utils/reachability.utils.d.ts +37 -0
- package/dist/git/utils/reachability.utils.d.ts.map +1 -0
- package/dist/git/utils/reachability.utils.js +96 -0
- package/dist/git/utils/reachability.utils.js.map +1 -0
- package/dist/git/watching/watchService.d.ts +4 -2
- package/dist/git/watching/watchService.d.ts.map +1 -1
- package/dist/git/watching/watchService.js +8 -3
- package/dist/git/watching/watchService.js.map +1 -1
- package/dist/git/watching/watchSession.d.ts +14 -12
- package/dist/git/watching/watchSession.d.ts.map +1 -1
- package/dist/git/watching/watchSession.js +56 -55
- package/dist/git/watching/watchSession.js.map +1 -1
- package/dist/git-cli/providers/branches.d.ts.map +1 -1
- package/dist/git-cli/providers/branches.js +1 -0
- package/dist/git-cli/providers/branches.js.map +1 -1
- package/dist/git-cli/providers/commits.d.ts +1 -0
- package/dist/git-cli/providers/commits.d.ts.map +1 -1
- package/dist/git-cli/providers/commits.js +12 -0
- package/dist/git-cli/providers/commits.js.map +1 -1
- package/dist/git-cli/providers/config.d.ts +8 -4
- package/dist/git-cli/providers/config.d.ts.map +1 -1
- package/dist/git-cli/providers/config.js +62 -39
- package/dist/git-cli/providers/config.js.map +1 -1
- package/dist/git-cli/providers/diff.d.ts.map +1 -1
- package/dist/git-cli/providers/diff.js +1 -1
- package/dist/git-cli/providers/diff.js.map +1 -1
- package/dist/git-cli/providers/graph.d.ts.map +1 -1
- package/dist/git-cli/providers/graph.js +132 -14
- package/dist/git-cli/providers/graph.js.map +1 -1
- package/dist/git-cli/providers/operations.d.ts +7 -5
- package/dist/git-cli/providers/operations.d.ts.map +1 -1
- package/dist/git-cli/providers/operations.js +118 -95
- package/dist/git-cli/providers/operations.js.map +1 -1
- package/dist/git-cli/providers/stash.d.ts.map +1 -1
- package/dist/git-cli/providers/stash.js +20 -2
- package/dist/git-cli/providers/stash.js.map +1 -1
- package/dist/git-cli/providers/status.d.ts.map +1 -1
- package/dist/git-cli/providers/status.js +5 -2
- package/dist/git-cli/providers/status.js.map +1 -1
- package/dist/git-cli/providers/worktrees.d.ts +2 -0
- package/dist/git-cli/providers/worktrees.d.ts.map +1 -1
- package/dist/git-cli/providers/worktrees.js +3 -0
- package/dist/git-cli/providers/worktrees.js.map +1 -1
- package/dist/ipc/discovery.d.ts +22 -0
- package/dist/ipc/discovery.d.ts.map +1 -1
- package/dist/ipc/discovery.js +111 -2
- package/dist/ipc/discovery.js.map +1 -1
- package/dist/plus/agents/providers/claudeCodeProvider.d.ts +73 -20
- package/dist/plus/agents/providers/claudeCodeProvider.d.ts.map +1 -1
- package/dist/plus/agents/providers/claudeCodeProvider.js +394 -88
- package/dist/plus/agents/providers/claudeCodeProvider.js.map +1 -1
- package/dist/plus/agents/types.d.ts +62 -11
- package/dist/plus/agents/types.d.ts.map +1 -1
- package/dist/plus/ai/models/model.d.ts +1 -1
- package/dist/plus/ai/models/model.d.ts.map +1 -1
- package/dist/plus/ai/models/model.js.map +1 -1
- package/dist/plus/ai/models/provider.d.ts +3 -0
- package/dist/plus/ai/models/provider.d.ts.map +1 -1
- package/dist/plus/ai/providers/gitkrakenProvider.d.ts +1 -1
- package/dist/plus/ai/providers/gitkrakenProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/gitkrakenProvider.js +4 -1
- package/dist/plus/ai/providers/gitkrakenProvider.js.map +1 -1
- package/dist/plus/ai/providers/openAICompatibleProviderBase.d.ts +4 -3
- package/dist/plus/ai/providers/openAICompatibleProviderBase.d.ts.map +1 -1
- package/dist/plus/ai/providers/openAICompatibleProviderBase.js +9 -6
- package/dist/plus/ai/providers/openAICompatibleProviderBase.js.map +1 -1
- package/dist/plus/ai/utils/ai.utils.d.ts.map +1 -1
- package/dist/plus/ai/utils/ai.utils.js +6 -4
- package/dist/plus/ai/utils/ai.utils.js.map +1 -1
- package/dist/plus/git-github/api/github.d.ts +8 -13
- package/dist/plus/git-github/api/github.d.ts.map +1 -1
- package/dist/plus/git-github/api/github.js +96 -14
- package/dist/plus/git-github/api/github.js.map +1 -1
- package/dist/plus/git-github/providers/github/refs.js +1 -1
- package/dist/plus/integrations/authentication/cloudIntegrationService.d.ts +11 -0
- package/dist/plus/integrations/authentication/cloudIntegrationService.d.ts.map +1 -0
- package/dist/plus/integrations/authentication/cloudIntegrationService.js +90 -0
- package/dist/plus/integrations/authentication/cloudIntegrationService.js.map +1 -0
- package/dist/plus/integrations/authentication/configuredIntegrationService.d.ts +67 -0
- package/dist/plus/integrations/authentication/configuredIntegrationService.d.ts.map +1 -0
- package/dist/plus/integrations/authentication/configuredIntegrationService.js +295 -0
- package/dist/plus/integrations/authentication/configuredIntegrationService.js.map +1 -0
- package/dist/plus/integrations/authentication/integrationAuthenticationProvider.d.ts +92 -0
- package/dist/plus/integrations/authentication/integrationAuthenticationProvider.d.ts.map +1 -0
- package/dist/plus/integrations/authentication/integrationAuthenticationProvider.js +185 -0
- package/dist/plus/integrations/authentication/integrationAuthenticationProvider.js.map +1 -0
- package/dist/plus/integrations/authentication/integrationAuthenticationService.d.ts +62 -0
- package/dist/plus/integrations/authentication/integrationAuthenticationService.d.ts.map +1 -0
- package/dist/plus/integrations/authentication/integrationAuthenticationService.js +122 -0
- package/dist/plus/integrations/authentication/integrationAuthenticationService.js.map +1 -0
- package/dist/plus/integrations/authentication/manualTokenProvider.d.ts +15 -0
- package/dist/plus/integrations/authentication/manualTokenProvider.d.ts.map +1 -0
- package/dist/plus/integrations/authentication/manualTokenProvider.js +49 -0
- package/dist/plus/integrations/authentication/manualTokenProvider.js.map +1 -0
- package/dist/plus/integrations/authentication/models.d.ts +87 -0
- package/dist/plus/integrations/authentication/models.d.ts.map +1 -0
- package/dist/plus/integrations/authentication/models.js +64 -0
- package/dist/plus/integrations/authentication/models.js.map +1 -0
- package/dist/plus/integrations/constants.d.ts +47 -0
- package/dist/plus/integrations/constants.d.ts.map +1 -0
- package/dist/plus/integrations/constants.js +128 -0
- package/dist/plus/integrations/constants.js.map +1 -0
- package/dist/plus/integrations/context.d.ts +354 -0
- package/dist/plus/integrations/context.d.ts.map +1 -0
- package/dist/plus/integrations/context.js +2 -0
- package/dist/plus/integrations/context.js.map +1 -0
- package/dist/plus/integrations/errors.d.ts +14 -0
- package/dist/plus/integrations/errors.d.ts.map +1 -0
- package/dist/plus/integrations/errors.js +19 -0
- package/dist/plus/integrations/errors.js.map +1 -0
- package/dist/plus/integrations/index.d.ts +32 -0
- package/dist/plus/integrations/index.d.ts.map +1 -0
- package/dist/plus/integrations/index.js +62 -0
- package/dist/plus/integrations/index.js.map +1 -0
- package/dist/plus/integrations/integrationService.d.ts +98 -0
- package/dist/plus/integrations/integrationService.d.ts.map +1 -0
- package/dist/plus/integrations/integrationService.js +627 -0
- package/dist/plus/integrations/integrationService.js.map +1 -0
- package/dist/plus/integrations/models/gitHostIntegration.d.ts +82 -0
- package/dist/plus/integrations/models/gitHostIntegration.d.ts.map +1 -0
- package/dist/plus/integrations/models/gitHostIntegration.js +522 -0
- package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -0
- package/dist/plus/integrations/models/integration.d.ts +127 -0
- package/dist/plus/integrations/models/integration.d.ts.map +1 -0
- package/dist/plus/integrations/models/integration.js +456 -0
- package/dist/plus/integrations/models/integration.js.map +1 -0
- package/dist/plus/integrations/models/issuesIntegration.d.ts +28 -0
- package/dist/plus/integrations/models/issuesIntegration.d.ts.map +1 -0
- package/dist/plus/integrations/models/issuesIntegration.js +101 -0
- package/dist/plus/integrations/models/issuesIntegration.js.map +1 -0
- package/dist/plus/integrations/providers/apiClients.d.ts +25 -0
- package/dist/plus/integrations/providers/apiClients.d.ts.map +1 -0
- package/dist/plus/integrations/providers/apiClients.js +39 -0
- package/dist/plus/integrations/providers/apiClients.js.map +1 -0
- package/dist/plus/integrations/providers/azure/azure.d.ts +47 -0
- package/dist/plus/integrations/providers/azure/azure.d.ts.map +1 -0
- package/dist/plus/integrations/providers/azure/azure.js +444 -0
- package/dist/plus/integrations/providers/azure/azure.js.map +1 -0
- package/dist/plus/integrations/providers/azure/models.d.ts +286 -0
- package/dist/plus/integrations/providers/azure/models.d.ts.map +1 -0
- package/dist/plus/integrations/providers/azure/models.js +203 -0
- package/dist/plus/integrations/providers/azure/models.js.map +1 -0
- package/dist/plus/integrations/providers/azureDevOps.d.ts +95 -0
- package/dist/plus/integrations/providers/azureDevOps.d.ts.map +1 -0
- package/dist/plus/integrations/providers/azureDevOps.js +432 -0
- package/dist/plus/integrations/providers/azureDevOps.js.map +1 -0
- package/dist/plus/integrations/providers/bitbucket/bitbucket.d.ts +42 -0
- package/dist/plus/integrations/providers/bitbucket/bitbucket.d.ts.map +1 -0
- package/dist/plus/integrations/providers/bitbucket/bitbucket.js +513 -0
- package/dist/plus/integrations/providers/bitbucket/bitbucket.js.map +1 -0
- package/dist/plus/integrations/providers/bitbucket/models.d.ts +222 -0
- package/dist/plus/integrations/providers/bitbucket/models.d.ts.map +1 -0
- package/dist/plus/integrations/providers/bitbucket/models.js +158 -0
- package/dist/plus/integrations/providers/bitbucket/models.js.map +1 -0
- package/dist/plus/integrations/providers/bitbucket-server/models.d.ts +120 -0
- package/dist/plus/integrations/providers/bitbucket-server/models.d.ts.map +1 -0
- package/dist/plus/integrations/providers/bitbucket-server/models.js +111 -0
- package/dist/plus/integrations/providers/bitbucket-server/models.js.map +1 -0
- package/dist/plus/integrations/providers/bitbucket-server.d.ts +60 -0
- package/dist/plus/integrations/providers/bitbucket-server.d.ts.map +1 -0
- package/dist/plus/integrations/providers/bitbucket-server.js +138 -0
- package/dist/plus/integrations/providers/bitbucket-server.js.map +1 -0
- package/dist/plus/integrations/providers/bitbucket.d.ts +50 -0
- package/dist/plus/integrations/providers/bitbucket.d.ts.map +1 -0
- package/dist/plus/integrations/providers/bitbucket.js +181 -0
- package/dist/plus/integrations/providers/bitbucket.js.map +1 -0
- package/dist/plus/integrations/providers/github/github.d.ts +5 -0
- package/dist/plus/integrations/providers/github/github.d.ts.map +1 -0
- package/dist/plus/integrations/providers/github/github.js +47 -0
- package/dist/plus/integrations/providers/github/github.js.map +1 -0
- package/dist/plus/integrations/providers/github/github.utils.d.ts +11 -0
- package/dist/plus/integrations/providers/github/github.utils.d.ts.map +1 -0
- package/dist/plus/integrations/providers/github/github.utils.js +6 -0
- package/dist/plus/integrations/providers/github/github.utils.js.map +1 -0
- package/dist/plus/integrations/providers/github/models.d.ts +3 -0
- package/dist/plus/integrations/providers/github/models.d.ts.map +1 -0
- package/dist/plus/integrations/providers/github/models.js +2 -0
- package/dist/plus/integrations/providers/github/models.js.map +1 -0
- package/dist/plus/integrations/providers/github.d.ts +73 -0
- package/dist/plus/integrations/providers/github.d.ts.map +1 -0
- package/dist/plus/integrations/providers/github.js +160 -0
- package/dist/plus/integrations/providers/github.js.map +1 -0
- package/dist/plus/integrations/providers/gitlab/gitlab.d.ts +63 -0
- package/dist/plus/integrations/providers/gitlab/gitlab.d.ts.map +1 -0
- package/dist/plus/integrations/providers/gitlab/gitlab.js +828 -0
- package/dist/plus/integrations/providers/gitlab/gitlab.js.map +1 -0
- package/dist/plus/integrations/providers/gitlab/gitlab.utils.d.ts +21 -0
- package/dist/plus/integrations/providers/gitlab/gitlab.utils.d.ts.map +1 -0
- package/dist/plus/integrations/providers/gitlab/gitlab.utils.js +45 -0
- package/dist/plus/integrations/providers/gitlab/gitlab.utils.js.map +1 -0
- package/dist/plus/integrations/providers/gitlab/models.d.ts +128 -0
- package/dist/plus/integrations/providers/gitlab/models.d.ts.map +1 -0
- package/dist/plus/integrations/providers/gitlab/models.js +96 -0
- package/dist/plus/integrations/providers/gitlab/models.js.map +1 -0
- package/dist/plus/integrations/providers/gitlab.d.ts +79 -0
- package/dist/plus/integrations/providers/gitlab.d.ts.map +1 -0
- package/dist/plus/integrations/providers/gitlab.js +253 -0
- package/dist/plus/integrations/providers/gitlab.js.map +1 -0
- package/dist/plus/integrations/providers/jira.d.ts +46 -0
- package/dist/plus/integrations/providers/jira.d.ts.map +1 -0
- package/dist/plus/integrations/providers/jira.js +255 -0
- package/dist/plus/integrations/providers/jira.js.map +1 -0
- package/dist/plus/integrations/providers/linear.d.ts +47 -0
- package/dist/plus/integrations/providers/linear.d.ts.map +1 -0
- package/dist/plus/integrations/providers/linear.js +198 -0
- package/dist/plus/integrations/providers/linear.js.map +1 -0
- package/dist/plus/integrations/providers/models.d.ts +433 -0
- package/dist/plus/integrations/providers/models.d.ts.map +1 -0
- package/dist/plus/integrations/providers/models.js +602 -0
- package/dist/plus/integrations/providers/models.js.map +1 -0
- package/dist/plus/integrations/providers/providersApi.d.ts +129 -0
- package/dist/plus/integrations/providers/providersApi.d.ts.map +1 -0
- package/dist/plus/integrations/providers/providersApi.js +602 -0
- package/dist/plus/integrations/providers/providersApi.js.map +1 -0
- package/dist/plus/integrations/providers/utils.d.ts +54 -0
- package/dist/plus/integrations/providers/utils.d.ts.map +1 -0
- package/dist/plus/integrations/providers/utils.js +262 -0
- package/dist/plus/integrations/providers/utils.js.map +1 -0
- package/dist/plus/integrations/telemetry.d.ts +26 -0
- package/dist/plus/integrations/telemetry.d.ts.map +1 -0
- package/dist/plus/integrations/telemetry.js +11 -0
- package/dist/plus/integrations/telemetry.js.map +1 -0
- package/dist/plus/integrations/utils/integration.utils.d.ts +14 -0
- package/dist/plus/integrations/utils/integration.utils.d.ts.map +1 -0
- package/dist/plus/integrations/utils/integration.utils.js +111 -0
- package/dist/plus/integrations/utils/integration.utils.js.map +1 -0
- package/dist/utils/date.d.ts.map +1 -1
- package/dist/utils/date.js +6 -0
- package/dist/utils/date.js.map +1 -1
- package/dist/utils/debounce.js +1 -1
- package/dist/utils/disposable.d.ts +15 -2
- package/dist/utils/disposable.d.ts.map +1 -1
- package/dist/utils/disposable.js.map +1 -1
- package/dist/utils/iterable.d.ts +7 -1
- package/dist/utils/iterable.d.ts.map +1 -1
- package/dist/utils/iterable.js +12 -4
- package/dist/utils/iterable.js.map +1 -1
- package/dist/utils/object.d.ts +22 -1
- package/dist/utils/object.d.ts.map +1 -1
- package/dist/utils/object.js +56 -3
- package/dist/utils/object.js.map +1 -1
- package/dist/utils/paging.js +14 -15
- package/dist/utils/paging.js.map +1 -1
- package/dist/utils/promiseCache.d.ts.map +1 -1
- package/dist/utils/promiseCache.js +12 -4
- package/dist/utils/promiseCache.js.map +1 -1
- package/dist/utils/string.js +1 -1
- package/package.json +43 -2
- package/src/git/cache.ts +58 -70
- package/src/git/context.ts +25 -3
- package/src/git/features.ts +2 -0
- package/src/git/models/graph.ts +97 -0
- package/src/git/models/remoteProvider.ts +1 -0
- package/src/git/models/repository.ts +84 -93
- package/src/git/models/statusFile.ts +12 -0
- package/src/git/providers/commits.ts +4 -0
- package/src/git/providers/config.ts +1 -5
- package/src/git/providers/operations.ts +42 -22
- package/src/git/providers/worktrees.ts +14 -2
- package/src/git/remotes/custom.ts +23 -0
- package/src/git/utils/conflictResolution.utils.ts +126 -0
- package/src/git/utils/contributor.utils.ts +24 -0
- package/src/git/utils/reachability.utils.ts +109 -0
- package/src/git/watching/watchService.ts +9 -4
- package/src/git/watching/watchSession.ts +61 -55
- package/src/git-cli/providers/branches.ts +1 -0
- package/src/git-cli/providers/commits.ts +24 -0
- package/src/git-cli/providers/config.ts +63 -49
- package/src/git-cli/providers/diff.ts +2 -1
- package/src/git-cli/providers/graph.ts +145 -14
- package/src/git-cli/providers/operations.ts +138 -130
- package/src/git-cli/providers/stash.ts +20 -2
- package/src/git-cli/providers/status.ts +11 -3
- package/src/git-cli/providers/worktrees.ts +17 -2
- package/src/ipc/discovery.ts +132 -2
- package/src/plus/agents/providers/claudeCodeProvider.ts +430 -90
- package/src/plus/agents/types.ts +59 -11
- package/src/plus/ai/models/model.ts +1 -0
- package/src/plus/ai/models/provider.ts +7 -1
- package/src/plus/ai/providers/gitkrakenProvider.ts +4 -0
- package/src/plus/ai/providers/openAICompatibleProviderBase.ts +21 -4
- package/src/plus/ai/utils/ai.utils.ts +6 -4
- package/src/plus/git-github/api/github.ts +131 -31
- package/src/plus/git-github/providers/github/refs.ts +1 -1
- package/src/plus/integrations/authentication/cloudIntegrationService.ts +120 -0
- package/src/plus/integrations/authentication/configuredIntegrationService.ts +414 -0
- package/src/plus/integrations/authentication/integrationAuthenticationProvider.ts +289 -0
- package/src/plus/integrations/authentication/integrationAuthenticationService.ts +144 -0
- package/src/plus/integrations/authentication/manualTokenProvider.ts +72 -0
- package/src/plus/integrations/authentication/models.ts +168 -0
- package/src/plus/integrations/constants.ts +169 -0
- package/src/plus/integrations/context.ts +383 -0
- package/src/plus/integrations/errors.ts +35 -0
- package/src/plus/integrations/index.ts +119 -0
- package/src/plus/integrations/integrationService.ts +924 -0
- package/src/plus/integrations/models/gitHostIntegration.ts +738 -0
- package/src/plus/integrations/models/integration.ts +657 -0
- package/src/plus/integrations/models/issuesIntegration.ts +124 -0
- package/src/plus/integrations/providers/apiClients.ts +72 -0
- package/src/plus/integrations/providers/azure/azure.ts +691 -0
- package/src/plus/integrations/providers/azure/models.ts +605 -0
- package/src/plus/integrations/providers/azureDevOps.ts +677 -0
- package/src/plus/integrations/providers/bitbucket/bitbucket.ts +774 -0
- package/src/plus/integrations/providers/bitbucket/models.ts +445 -0
- package/src/plus/integrations/providers/bitbucket-server/models.ts +252 -0
- package/src/plus/integrations/providers/bitbucket-server.ts +282 -0
- package/src/plus/integrations/providers/bitbucket.ts +350 -0
- package/src/plus/integrations/providers/github/github.ts +64 -0
- package/src/plus/integrations/providers/github/github.utils.ts +23 -0
- package/src/plus/integrations/providers/github/models.ts +29 -0
- package/src/plus/integrations/providers/github.ts +366 -0
- package/src/plus/integrations/providers/gitlab/gitlab.ts +1210 -0
- package/src/plus/integrations/providers/gitlab/gitlab.utils.ts +71 -0
- package/src/plus/integrations/providers/gitlab/models.ts +257 -0
- package/src/plus/integrations/providers/gitlab.ts +473 -0
- package/src/plus/integrations/providers/jira.ts +359 -0
- package/src/plus/integrations/providers/linear.ts +275 -0
- package/src/plus/integrations/providers/models.ts +1114 -0
- package/src/plus/integrations/providers/providersApi.ts +1126 -0
- package/src/plus/integrations/providers/utils.ts +359 -0
- package/src/plus/integrations/telemetry.ts +29 -0
- package/src/plus/integrations/utils/integration.utils.ts +138 -0
- package/src/utils/date.ts +5 -0
- package/src/utils/debounce.ts +1 -1
- package/src/utils/disposable.ts +15 -2
- package/src/utils/iterable.ts +14 -3
- package/src/utils/object.ts +55 -4
- package/src/utils/paging.ts +14 -14
- package/src/utils/promiseCache.ts +24 -16
- package/src/utils/string.ts +1 -1
package/src/plus/agents/types.ts
CHANGED
|
@@ -135,22 +135,46 @@ export interface AgentSession {
|
|
|
135
135
|
* identity. For "what repo is this session in", use {@link commonPath}. */
|
|
136
136
|
readonly workspacePath?: string;
|
|
137
137
|
readonly cwd?: string;
|
|
138
|
+
/** The session's `cwd` at first observation. Set once and never overwritten — captures the
|
|
139
|
+
* agent's launch directory so consumers can detect drift (e.g. an agent that `cd`'d into a
|
|
140
|
+
* sibling worktree). Pairs with {@link initialWorktreePath} / {@link initialCommonPath}; for
|
|
141
|
+
* the live cwd, see {@link cwd}. */
|
|
142
|
+
readonly initialCwd?: string;
|
|
143
|
+
/** The session's `worktreePath` at first successful git-info resolution. Set once and never
|
|
144
|
+
* overwritten — compare against {@link worktreePath} to detect cross-worktree drift. Undefined
|
|
145
|
+
* if the session has never resolved into a git repo. */
|
|
146
|
+
readonly initialWorktreePath?: string;
|
|
147
|
+
/** The session's `commonPath` at first successful git-info resolution. Set once and never
|
|
148
|
+
* overwritten — compare against {@link commonPath} to detect cross-repo drift. Undefined if
|
|
149
|
+
* the session has never resolved into a git repo. */
|
|
150
|
+
readonly initialCommonPath?: string;
|
|
138
151
|
readonly planFile?: string;
|
|
139
152
|
readonly isInWorkspace: boolean;
|
|
140
153
|
readonly lastPrompt?: string;
|
|
141
154
|
readonly firstPrompt?: string;
|
|
142
|
-
/**
|
|
143
|
-
* NotebookEdit). Populated on PreToolUse
|
|
144
|
-
*
|
|
155
|
+
/** Per-file activity record covering both read-class (Read/NotebookRead) and edit-class
|
|
156
|
+
* (Edit/Write/MultiEdit/NotebookEdit) tool calls. Populated on PreToolUse; each path is retained
|
|
157
|
+
* and fades for the configured decay window measured from its own last PostToolUse — the tail
|
|
158
|
+
* survives the turn-end Stop (which only drops the live `editing`/`reading` flags) and is fully
|
|
159
|
+
* cleared only on SessionEnd or once the decay window elapses.
|
|
145
160
|
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
|
|
161
|
+
* A sub-agent's file activity appears on its PARENT's `fileActivity`, not the sub-agent's own:
|
|
162
|
+
* the GK CLI keys a sub-agent's tool events under the parent session id (with `agentId` set), so
|
|
163
|
+
* they accumulate in the parent's bookkeeping directly. Consumers never need to recurse into
|
|
164
|
+
* `subagents[]`; sub-agent `AgentSession` objects carry `fileActivity: undefined`.
|
|
165
|
+
*
|
|
166
|
+
* Field semantics:
|
|
167
|
+
* - `path`: absolute path on the agent's filesystem.
|
|
168
|
+
* - `readAt` / `editedAt`: milliseconds since the last PreToolUse for that kind, computed by
|
|
169
|
+
* the host at serialization time (relative — avoids clock-skew). Omitted when never touched
|
|
170
|
+
* by that kind within the window.
|
|
171
|
+
* - `reading` / `editing`: `true` when at least one tool of that kind is in flight on this
|
|
172
|
+
* path right now (refcount > 0 in the host bookkeeping). Omitted when false to keep the
|
|
173
|
+
* wire minimal.
|
|
174
|
+
*
|
|
175
|
+
* Mutable array form so `Shape<AgentSession>` projects it cleanly (the `Shape<>` type mangles
|
|
176
|
+
* `readonly T[]` into a mapped object that loses its iterator). Treat as immutable. */
|
|
177
|
+
fileActivity?: { path: string; readAt?: number; editedAt?: number; reading?: true; editing?: true }[];
|
|
154
178
|
/** `true` when the session was discovered via peer IPC sync (i.e. another GitLens window hosts
|
|
155
179
|
* the agent's hook flow and Claude Code extension panel). Locally-owned sessions leave this
|
|
156
180
|
* unset. The dispatcher uses this to route opens through the peer's IPC route + an OS-level
|
|
@@ -186,6 +210,11 @@ export interface AgentSessionProvider extends UnifiedDisposable {
|
|
|
186
210
|
stop(): void;
|
|
187
211
|
updateWorkspacePaths?(workspacePaths: string[]): void;
|
|
188
212
|
|
|
213
|
+
/** Pushed by the host from its cached agent detection. Lets the provider gate its reconciliation
|
|
214
|
+
* poll (the CLI `list-sessions` call) so an idle window with no sessions and no installed hooks
|
|
215
|
+
* doesn't spawn the CLI every interval. */
|
|
216
|
+
setClaudeHooksInstalled?(installed: boolean): void;
|
|
217
|
+
|
|
189
218
|
/** Resolves a pending permission. Returns `true` when the resolve was routed (the local IPC
|
|
190
219
|
* owns the session's pending entry); `false` when no local entry exists (typically a peer-
|
|
191
220
|
* discovered session owned by another GitLens window). Callers use this to give the user
|
|
@@ -231,6 +260,13 @@ export interface AgentProviderCallbacks {
|
|
|
231
260
|
/** Host-supplied IPC service. Required for agents to receive hook events from the GK CLI. */
|
|
232
261
|
ipc: IpcRegistrar;
|
|
233
262
|
|
|
263
|
+
/** Returns the current "activity decay" window in milliseconds — the cooldown between a tool
|
|
264
|
+
* call finishing and the file being dropped from `AgentSession.fileActivity`. Optional — when
|
|
265
|
+
* omitted the provider falls back to its built-in default (5 min). Read by the provider at
|
|
266
|
+
* schedule time so changes to the host setting take effect on the next tool call without
|
|
267
|
+
* needing a re-wiring step. */
|
|
268
|
+
getActivityDecayMs?(): number;
|
|
269
|
+
|
|
234
270
|
/** Report that an agent session started. No-op if the host has no telemetry. */
|
|
235
271
|
onSessionStarted?(provider: string): void;
|
|
236
272
|
|
|
@@ -240,6 +276,18 @@ export interface AgentProviderCallbacks {
|
|
|
240
276
|
/** Report that a permission request was resolved. No-op if the host has no telemetry. */
|
|
241
277
|
onPermissionResolved?(info: { provider: string; tool: string; decision: PermissionDecision }): void;
|
|
242
278
|
|
|
279
|
+
/** Report that a reconciliation poll found the polled session set drift from what the live IPC
|
|
280
|
+
* path had already tracked — `discovered` sessions the poll saw but we weren't tracking,
|
|
281
|
+
* `missing` sessions we track that the poll no longer reports alive. Ideally always zero. No-op
|
|
282
|
+
* if the host has no telemetry. */
|
|
283
|
+
onSyncDiscrepancy?(info: {
|
|
284
|
+
provider: string;
|
|
285
|
+
discovered: number;
|
|
286
|
+
missing: number;
|
|
287
|
+
polled: number;
|
|
288
|
+
tracked: number;
|
|
289
|
+
}): void;
|
|
290
|
+
|
|
243
291
|
/** Notify the host that a branch has agent activity. */
|
|
244
292
|
onBranchAgentActivity?(cwd: string): void;
|
|
245
293
|
|
|
@@ -28,6 +28,7 @@ export type AIActionType =
|
|
|
28
28
|
| 'generate-changelog'
|
|
29
29
|
| `generate-create-${'cloudPatch' | 'codeSuggestion' | 'pullRequest'}`
|
|
30
30
|
| 'generate-commits'
|
|
31
|
+
| 'conflict-resolution'
|
|
31
32
|
| 'generate-searchQuery';
|
|
32
33
|
|
|
33
34
|
export interface AIProviderDescriptor<T extends AIProviders = AIProviders> {
|
|
@@ -47,6 +47,12 @@ export interface AIProvider<Provider extends AIProviders = AIProviders> extends
|
|
|
47
47
|
model: AIModel<Provider>,
|
|
48
48
|
apiKey: string,
|
|
49
49
|
getMessages: (maxInputTokens: number, retries: number) => Promise<AIChatMessage[]>,
|
|
50
|
-
options: {
|
|
50
|
+
options: {
|
|
51
|
+
signal: AbortSignal;
|
|
52
|
+
modelOptions?: { outputTokens?: number; temperature?: number };
|
|
53
|
+
/** Opaque session ID the GitKraken provider sends as `GK-Conversation-ID` so the backend
|
|
54
|
+
* charges its per-feature fee once per session; ignored by all other providers. */
|
|
55
|
+
conversationId?: string;
|
|
56
|
+
},
|
|
51
57
|
): Promise<AIProviderResponse<void> | undefined>;
|
|
52
58
|
}
|
|
@@ -87,11 +87,15 @@ export class GitKrakenProvider extends OpenAICompatibleProviderBase<typeof provi
|
|
|
87
87
|
apiKey: string,
|
|
88
88
|
_model: AIModel<typeof provider.id>,
|
|
89
89
|
_url: string,
|
|
90
|
+
conversationId?: string,
|
|
90
91
|
): Record<string, string> {
|
|
91
92
|
return {
|
|
92
93
|
Accept: 'application/json',
|
|
93
94
|
Authorization: `Bearer ${apiKey}`,
|
|
94
95
|
'GK-Action': action,
|
|
96
|
+
// Scopes the backend's once-per-conversation feature fee — without it every request in a
|
|
97
|
+
// multi-call session (e.g. conflict resolution) is charged the full flat fee.
|
|
98
|
+
...(conversationId ? { 'GK-Conversation-ID': conversationId } : {}),
|
|
95
99
|
};
|
|
96
100
|
}
|
|
97
101
|
|
|
@@ -61,6 +61,9 @@ export abstract class OpenAICompatibleProviderBase<T extends AIProviders> implem
|
|
|
61
61
|
apiKey: string,
|
|
62
62
|
_model: AIModel<T>,
|
|
63
63
|
_url: string,
|
|
64
|
+
// Deliberately unused here: only the GitKraken provider forwards the conversation ID (as
|
|
65
|
+
// `GK-Conversation-ID`); it must never reach third-party APIs.
|
|
66
|
+
_conversationId?: string,
|
|
64
67
|
): Record<string, string> | Promise<Record<string, string>> {
|
|
65
68
|
return {
|
|
66
69
|
Accept: 'application/json',
|
|
@@ -74,12 +77,24 @@ export abstract class OpenAICompatibleProviderBase<T extends AIProviders> implem
|
|
|
74
77
|
model: AIModel<T>,
|
|
75
78
|
apiKey: string,
|
|
76
79
|
getMessages: (maxInputTokens: number, retries: number) => Promise<AIChatMessage[]>,
|
|
77
|
-
options: {
|
|
80
|
+
options: {
|
|
81
|
+
signal: AbortSignal;
|
|
82
|
+
modelOptions?: { outputTokens?: number; temperature?: number };
|
|
83
|
+
conversationId?: string;
|
|
84
|
+
},
|
|
78
85
|
): Promise<AIProviderResponse<void> | undefined> {
|
|
79
86
|
using scope = maybeStartScopedLogger(`${getLoggableName(this)}.sendRequest`);
|
|
80
87
|
|
|
81
88
|
try {
|
|
82
|
-
const result = await this.fetch(
|
|
89
|
+
const result = await this.fetch(
|
|
90
|
+
action,
|
|
91
|
+
model,
|
|
92
|
+
apiKey,
|
|
93
|
+
getMessages,
|
|
94
|
+
options.modelOptions,
|
|
95
|
+
options.signal,
|
|
96
|
+
options.conversationId,
|
|
97
|
+
);
|
|
83
98
|
return result;
|
|
84
99
|
} catch (ex) {
|
|
85
100
|
if (isCancellationError(ex)) {
|
|
@@ -104,6 +119,7 @@ export abstract class OpenAICompatibleProviderBase<T extends AIProviders> implem
|
|
|
104
119
|
messages: (maxInputTokens: number, retries: number) => Promise<AIChatMessage[]>,
|
|
105
120
|
modelOptions?: { outputTokens?: number; temperature?: number },
|
|
106
121
|
signal?: AbortSignal,
|
|
122
|
+
conversationId?: string,
|
|
107
123
|
): Promise<AIProviderResponse<void>> {
|
|
108
124
|
let retries = 0;
|
|
109
125
|
let maxInputTokens = model.maxTokens.input;
|
|
@@ -123,7 +139,7 @@ export abstract class OpenAICompatibleProviderBase<T extends AIProviders> implem
|
|
|
123
139
|
),
|
|
124
140
|
};
|
|
125
141
|
|
|
126
|
-
const rsp = await this.fetchCore(action, model, apiKey, request, signal);
|
|
142
|
+
const rsp = await this.fetchCore(action, model, apiKey, request, signal, conversationId);
|
|
127
143
|
if (!rsp.ok) {
|
|
128
144
|
const result = await this.handleFetchFailure(rsp, action, model, retries, maxInputTokens);
|
|
129
145
|
if (result.retry) {
|
|
@@ -207,6 +223,7 @@ export abstract class OpenAICompatibleProviderBase<T extends AIProviders> implem
|
|
|
207
223
|
apiKey: string,
|
|
208
224
|
request: object,
|
|
209
225
|
signal: AbortSignal | undefined,
|
|
226
|
+
conversationId?: string,
|
|
210
227
|
): Promise<Response> {
|
|
211
228
|
const url = this.getUrl(model);
|
|
212
229
|
if (!url) {
|
|
@@ -215,7 +232,7 @@ export abstract class OpenAICompatibleProviderBase<T extends AIProviders> implem
|
|
|
215
232
|
|
|
216
233
|
try {
|
|
217
234
|
return await this.context.fetch(url, {
|
|
218
|
-
headers: await this.getHeaders(action, apiKey, model, url),
|
|
235
|
+
headers: await this.getHeaders(action, apiKey, model, url, conversationId),
|
|
219
236
|
method: 'POST',
|
|
220
237
|
body: JSON.stringify(request),
|
|
221
238
|
signal: signal,
|
|
@@ -11,17 +11,19 @@ export function getActionName(action: AIActionType): string {
|
|
|
11
11
|
case 'generate-stashMessage':
|
|
12
12
|
return 'Generate Stash Message';
|
|
13
13
|
case 'generate-changelog':
|
|
14
|
-
return 'Generate Changelog
|
|
14
|
+
return 'Generate Changelog';
|
|
15
15
|
case 'generate-create-cloudPatch':
|
|
16
16
|
return 'Create Cloud Patch Details';
|
|
17
17
|
case 'generate-create-codeSuggestion':
|
|
18
18
|
return 'Create Code Suggestion Details';
|
|
19
19
|
case 'generate-create-pullRequest':
|
|
20
|
-
return 'Create Pull Request Details
|
|
20
|
+
return 'Create Pull Request Details';
|
|
21
21
|
case 'generate-commits':
|
|
22
|
-
return 'Generate Commits
|
|
22
|
+
return 'Generate Commits';
|
|
23
|
+
case 'conflict-resolution':
|
|
24
|
+
return 'Resolve Conflicts (Preview)';
|
|
23
25
|
case 'generate-searchQuery':
|
|
24
|
-
return 'Generate Search Query
|
|
26
|
+
return 'Generate Search Query';
|
|
25
27
|
}
|
|
26
28
|
}
|
|
27
29
|
|
|
@@ -66,14 +66,49 @@ import {
|
|
|
66
66
|
import type { GitHubApiConfig } from './config.js';
|
|
67
67
|
import type { GitHubTokenInfo } from './token.js';
|
|
68
68
|
|
|
69
|
-
interface CancellationToken {
|
|
70
|
-
isCancellationRequested: boolean;
|
|
71
|
-
onCancellationRequested(fn: () => void): { dispose(): void };
|
|
72
|
-
}
|
|
73
|
-
|
|
74
69
|
const emptyPagedResult: PagedResult<any> = Object.freeze({ values: [] });
|
|
75
70
|
const emptyBlameResult: GitHubBlame = Object.freeze({ ranges: [] });
|
|
76
71
|
|
|
72
|
+
// Transient gateway/network failures (e.g. an upstream `502 Bad Gateway`) are worth a few quick
|
|
73
|
+
// retries before surfacing to the caller. octokit provides no built-in retry for the standalone
|
|
74
|
+
// `request`/`graphql` functions we use (its retry/throttle plugins only attach to the `Octokit`
|
|
75
|
+
// class), so we retry here — but only for idempotent reads (REST GET/HEAD, GraphQL queries),
|
|
76
|
+
// never for mutations.
|
|
77
|
+
const maxRequestRetries = 2;
|
|
78
|
+
const requestRetryBaseDelay = 300; // ms
|
|
79
|
+
const requestRetryMaxDelay = 2000; // ms
|
|
80
|
+
|
|
81
|
+
function isRetryableTransientError(ex: unknown): ex is RequestError {
|
|
82
|
+
// An aborted request is rethrown as the original `AbortError` (not a `RequestError`), so it is
|
|
83
|
+
// excluded here. octokit maps a fetch/network failure to a `RequestError` with status 500 and
|
|
84
|
+
// no response — those, along with real gateway statuses, are transient and safe to retry.
|
|
85
|
+
if (!(ex instanceof RequestError)) return false;
|
|
86
|
+
|
|
87
|
+
switch (ex.status) {
|
|
88
|
+
case 502: // Bad Gateway
|
|
89
|
+
case 503: // Service Unavailable
|
|
90
|
+
case 504: // Gateway Timeout
|
|
91
|
+
return true;
|
|
92
|
+
case 500: // Internal Server Error — only the network-failure variant (no response)
|
|
93
|
+
return ex.response == null;
|
|
94
|
+
default:
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function getRequestRetryDelay(attempt: number): number {
|
|
100
|
+
// Exponential backoff with equal jitter, capped — spreads retries so a brief upstream blip
|
|
101
|
+
// isn't hammered by every in-flight request landing on the same schedule.
|
|
102
|
+
const backoff = Math.min(requestRetryMaxDelay, requestRetryBaseDelay * 2 ** (attempt - 1));
|
|
103
|
+
return Math.round(backoff / 2 + Math.random() * (backoff / 2));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Matches a GraphQL document whose operation is definitely a read query — the `query` keyword as
|
|
107
|
+
// the first significant token, after any leading whitespace or `#` comment lines. We retry only
|
|
108
|
+
// when this matches; a mutation (even one prefixed by a comment), a subscription, or anything we
|
|
109
|
+
// can't classify is left non-retryable so a transient failure can never re-run a mutation.
|
|
110
|
+
const graphqlReadQueryRegex = /^(?:\s|#[^\n]*\n?)*query\b/;
|
|
111
|
+
|
|
77
112
|
const gqlIssueOrPullRequestFragment = `
|
|
78
113
|
closed
|
|
79
114
|
closedAt
|
|
@@ -919,7 +954,7 @@ export class GitHubApi {
|
|
|
919
954
|
baseUrl?: string;
|
|
920
955
|
avatarSize?: number;
|
|
921
956
|
},
|
|
922
|
-
cancellation?:
|
|
957
|
+
cancellation?: AbortSignal,
|
|
923
958
|
): Promise<PullRequest | undefined> {
|
|
924
959
|
const scope = getScopedLogger();
|
|
925
960
|
|
|
@@ -1009,7 +1044,7 @@ export class GitHubApi {
|
|
|
1009
1044
|
options?: {
|
|
1010
1045
|
baseUrl?: string;
|
|
1011
1046
|
},
|
|
1012
|
-
cancellation?:
|
|
1047
|
+
cancellation?: AbortSignal,
|
|
1013
1048
|
): Promise<RepositoryMetadata | undefined> {
|
|
1014
1049
|
const scope = getScopedLogger();
|
|
1015
1050
|
|
|
@@ -2866,6 +2901,55 @@ export class GitHubApi {
|
|
|
2866
2901
|
return version ?? undefined;
|
|
2867
2902
|
}
|
|
2868
2903
|
|
|
2904
|
+
// Runs `execute`, retrying transient gateway/network failures with backoff. `retryable` gates
|
|
2905
|
+
// retries to idempotent reads; `signal` lets an in-flight cancellation abort the backoff wait.
|
|
2906
|
+
private async requestWithRetries<T>(
|
|
2907
|
+
execute: () => Promise<T>,
|
|
2908
|
+
retryable: boolean,
|
|
2909
|
+
signal: AbortSignal | undefined,
|
|
2910
|
+
scope: ScopedLogger | undefined,
|
|
2911
|
+
): Promise<T> {
|
|
2912
|
+
let attempt = 0;
|
|
2913
|
+
while (true) {
|
|
2914
|
+
try {
|
|
2915
|
+
return await execute();
|
|
2916
|
+
} catch (ex) {
|
|
2917
|
+
if (!retryable || attempt >= maxRequestRetries || signal?.aborted || !isRetryableTransientError(ex)) {
|
|
2918
|
+
throw ex;
|
|
2919
|
+
}
|
|
2920
|
+
|
|
2921
|
+
attempt++;
|
|
2922
|
+
const delay = getRequestRetryDelay(attempt);
|
|
2923
|
+
scope?.warn(
|
|
2924
|
+
`Transient request failure (status ${ex.status}); retrying ${attempt}/${maxRequestRetries} in ${delay}ms`,
|
|
2925
|
+
);
|
|
2926
|
+
await this.delayWithAbort(delay, signal);
|
|
2927
|
+
// Bail rather than retry if we were cancelled while waiting
|
|
2928
|
+
if (signal?.aborted) throw new CancellationError();
|
|
2929
|
+
}
|
|
2930
|
+
}
|
|
2931
|
+
}
|
|
2932
|
+
|
|
2933
|
+
private delayWithAbort(ms: number, signal: AbortSignal | undefined): Promise<void> {
|
|
2934
|
+
return new Promise<void>(resolve => {
|
|
2935
|
+
if (signal?.aborted) {
|
|
2936
|
+
resolve();
|
|
2937
|
+
return;
|
|
2938
|
+
}
|
|
2939
|
+
|
|
2940
|
+
let timer: ReturnType<typeof setTimeout>;
|
|
2941
|
+
const onAbort = () => {
|
|
2942
|
+
clearTimeout(timer);
|
|
2943
|
+
resolve();
|
|
2944
|
+
};
|
|
2945
|
+
timer = setTimeout(() => {
|
|
2946
|
+
signal?.removeEventListener('abort', onAbort);
|
|
2947
|
+
resolve();
|
|
2948
|
+
}, ms);
|
|
2949
|
+
signal?.addEventListener('abort', onAbort, { once: true });
|
|
2950
|
+
});
|
|
2951
|
+
}
|
|
2952
|
+
|
|
2869
2953
|
// Inflight dedupe: identical concurrent GraphQL requests share a single promise
|
|
2870
2954
|
// to cut redundant traffic during graph/details enrichment bursts.
|
|
2871
2955
|
private readonly _pendingGraphQL = new Map<string, Promise<unknown>>();
|
|
@@ -2876,10 +2960,9 @@ export class GitHubApi {
|
|
|
2876
2960
|
query: string,
|
|
2877
2961
|
variables: RequestParameters,
|
|
2878
2962
|
scope: ScopedLogger | undefined,
|
|
2879
|
-
cancellation?:
|
|
2963
|
+
cancellation?: AbortSignal | undefined,
|
|
2880
2964
|
): Promise<T | undefined> {
|
|
2881
2965
|
const { accessToken, ...tokenInfo } = token;
|
|
2882
|
-
|
|
2883
2966
|
// Only dedupe when no cancellation/request option is in play — sharing a promise that
|
|
2884
2967
|
// carries one caller's AbortSignal would let one cancellation cancel for everyone.
|
|
2885
2968
|
const dedupable = cancellation == null && variables?.request == null;
|
|
@@ -2899,21 +2982,26 @@ export class GitHubApi {
|
|
|
2899
2982
|
|
|
2900
2983
|
const run = async (): Promise<T | undefined> => {
|
|
2901
2984
|
try {
|
|
2902
|
-
let aborter: AbortController | undefined;
|
|
2903
2985
|
if (cancellation != null) {
|
|
2904
|
-
if (cancellation.
|
|
2905
|
-
|
|
2906
|
-
aborter = new AbortController();
|
|
2907
|
-
cancellation.onCancellationRequested(() => aborter!.abort());
|
|
2986
|
+
if (cancellation.aborted) throw new CancellationError();
|
|
2908
2987
|
|
|
2909
2988
|
variables = {
|
|
2910
2989
|
...variables,
|
|
2911
|
-
request: { ...variables?.request, signal:
|
|
2990
|
+
request: { ...variables?.request, signal: cancellation },
|
|
2912
2991
|
};
|
|
2913
2992
|
}
|
|
2914
2993
|
|
|
2915
|
-
|
|
2916
|
-
|
|
2994
|
+
// Retry transient gateway/network failures, but only confirmed read queries — never
|
|
2995
|
+
// mutations (re-running one isn't idempotent)
|
|
2996
|
+
const retryable = graphqlReadQueryRegex.test(query);
|
|
2997
|
+
return await this.requestWithRetries(
|
|
2998
|
+
() =>
|
|
2999
|
+
this.config.wrapForForcedInsecureSSL(provider?.getIgnoreSSLErrors() ?? false, () =>
|
|
3000
|
+
this.getDefaults(accessToken, graphql)(query, variables),
|
|
3001
|
+
),
|
|
3002
|
+
retryable,
|
|
3003
|
+
cancellation,
|
|
3004
|
+
scope,
|
|
2917
3005
|
);
|
|
2918
3006
|
} catch (ex) {
|
|
2919
3007
|
if (ex instanceof GraphqlResponseError) {
|
|
@@ -2955,12 +3043,15 @@ export class GitHubApi {
|
|
|
2955
3043
|
const promise = run();
|
|
2956
3044
|
this._pendingGraphQL.set(dedupeKey, promise);
|
|
2957
3045
|
// Clear from the inflight map once the promise settles — successes and failures both
|
|
2958
|
-
// clear, so failed requests don't poison subsequent retries.
|
|
2959
|
-
|
|
3046
|
+
// clear, so failed requests don't poison subsequent retries. Use `then(cleanup, cleanup)`
|
|
3047
|
+
// rather than `finally` so a rejected request doesn't spawn an orphaned (unhandled) promise;
|
|
3048
|
+
// the real caller still receives the rejection via the returned `promise`.
|
|
3049
|
+
const cleanup = () => {
|
|
2960
3050
|
if (this._pendingGraphQL.get(dedupeKey) === promise) {
|
|
2961
3051
|
this._pendingGraphQL.delete(dedupeKey);
|
|
2962
3052
|
}
|
|
2963
|
-
}
|
|
3053
|
+
};
|
|
3054
|
+
promise.then(cleanup, cleanup);
|
|
2964
3055
|
return promise;
|
|
2965
3056
|
}
|
|
2966
3057
|
|
|
@@ -2970,20 +3061,29 @@ export class GitHubApi {
|
|
|
2970
3061
|
route: R,
|
|
2971
3062
|
options: (Endpoints[R]['parameters'] & RequestParameters) | undefined,
|
|
2972
3063
|
scope: ScopedLogger | undefined,
|
|
2973
|
-
cancellation?:
|
|
3064
|
+
cancellation?: AbortSignal | undefined,
|
|
2974
3065
|
): Promise<Endpoints[R]['response']> {
|
|
2975
3066
|
const { accessToken } = token;
|
|
2976
3067
|
try {
|
|
3068
|
+
let signal: AbortSignal | undefined;
|
|
2977
3069
|
if (cancellation != null) {
|
|
2978
|
-
if (cancellation.
|
|
3070
|
+
if (cancellation.aborted) throw new CancellationError();
|
|
2979
3071
|
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
options = { ...options, request: { ...options?.request, signal: aborter.signal } };
|
|
3072
|
+
signal = cancellation;
|
|
3073
|
+
options = { ...options, request: { ...options?.request, signal: signal } };
|
|
2983
3074
|
}
|
|
2984
3075
|
|
|
2985
|
-
|
|
2986
|
-
|
|
3076
|
+
// Retry transient gateway/network failures on idempotent reads only
|
|
3077
|
+
const method = route.split(' ', 1)[0].toUpperCase();
|
|
3078
|
+
const retryable = method === 'GET' || method === 'HEAD';
|
|
3079
|
+
return (await this.requestWithRetries(
|
|
3080
|
+
() =>
|
|
3081
|
+
this.config.wrapForForcedInsecureSSL(provider?.getIgnoreSSLErrors() ?? false, () =>
|
|
3082
|
+
this.getDefaults(accessToken, request)(route as string, options),
|
|
3083
|
+
),
|
|
3084
|
+
retryable,
|
|
3085
|
+
signal,
|
|
3086
|
+
scope,
|
|
2987
3087
|
)) as Endpoints[R]['response'];
|
|
2988
3088
|
} catch (ex) {
|
|
2989
3089
|
if (ex instanceof RequestError || ex.name === 'AbortError') {
|
|
@@ -3218,7 +3318,7 @@ export class GitHubApi {
|
|
|
3218
3318
|
avatarSize?: number;
|
|
3219
3319
|
silent?: boolean;
|
|
3220
3320
|
},
|
|
3221
|
-
cancellation?:
|
|
3321
|
+
cancellation?: AbortSignal,
|
|
3222
3322
|
): Promise<PullRequest[]> {
|
|
3223
3323
|
const scope = getScopedLogger();
|
|
3224
3324
|
|
|
@@ -3333,7 +3433,7 @@ export class GitHubApi {
|
|
|
3333
3433
|
avatarSize?: number;
|
|
3334
3434
|
includeBody?: boolean;
|
|
3335
3435
|
},
|
|
3336
|
-
cancellation?:
|
|
3436
|
+
cancellation?: AbortSignal,
|
|
3337
3437
|
): Promise<IssueShape[] | undefined> {
|
|
3338
3438
|
const scope = getScopedLogger();
|
|
3339
3439
|
|
|
@@ -3436,7 +3536,7 @@ export class GitHubApi {
|
|
|
3436
3536
|
provider: Provider,
|
|
3437
3537
|
token: GitHubTokenInfo,
|
|
3438
3538
|
options?: { search?: string; user?: string; repos?: string[]; baseUrl?: string; avatarSize?: number },
|
|
3439
|
-
cancellation?:
|
|
3539
|
+
cancellation?: AbortSignal,
|
|
3440
3540
|
): Promise<PullRequest[]> {
|
|
3441
3541
|
const scope = getScopedLogger();
|
|
3442
3542
|
|
|
@@ -3506,7 +3606,7 @@ export class GitHubApi {
|
|
|
3506
3606
|
nodeId: string,
|
|
3507
3607
|
expectedSourceSha: string,
|
|
3508
3608
|
options?: { mergeMethod?: PullRequestMergeMethod; baseUrl?: string },
|
|
3509
|
-
cancellation?:
|
|
3609
|
+
cancellation?: AbortSignal,
|
|
3510
3610
|
): Promise<boolean> {
|
|
3511
3611
|
const scope = getScopedLogger();
|
|
3512
3612
|
interface QueryResult {
|
|
@@ -17,7 +17,7 @@ import { toTokenInfo } from '../../api/tokenUtils.js';
|
|
|
17
17
|
import type { GitHubGitProviderInternal } from '../githubProvider.js';
|
|
18
18
|
|
|
19
19
|
// Since negative lookbehind isn't supported in all browsers, this leaves out the negative lookbehind condition `(?<!\.lock)` to ensure the branch name doesn't end with `.lock`
|
|
20
|
-
//
|
|
20
|
+
// oxlint-disable-next-line no-control-regex
|
|
21
21
|
const validBranchOrTagRegex = /^[^/](?!.*\/\.)(?!.*\.\.)(?!.*\/\/)(?!.*@\{)[^\x00-\x1F\x7F ~^:?*[\\]+[^./]$/;
|
|
22
22
|
|
|
23
23
|
export class RefsGitSubProvider implements GitRefsSubProvider {
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { getScopedLogger } from '../../../utils/logger.scoped.js';
|
|
2
|
+
import type { IntegrationIds } from '../constants.js';
|
|
3
|
+
import type { IntegrationServiceContext } from '../context.js';
|
|
4
|
+
import type { CloudIntegrationAuthenticationSession, CloudIntegrationConnection } from './models.js';
|
|
5
|
+
import { toCloudIntegrationType } from './models.js';
|
|
6
|
+
|
|
7
|
+
export class CloudIntegrationService {
|
|
8
|
+
constructor(private readonly ctx: IntegrationServiceContext) {}
|
|
9
|
+
|
|
10
|
+
async getConnections(): Promise<CloudIntegrationConnection[] | undefined> {
|
|
11
|
+
const scope = getScopedLogger();
|
|
12
|
+
|
|
13
|
+
const providersRsp = await this.ctx.account.fetchGkApi('v1/provider-tokens', { method: 'GET' });
|
|
14
|
+
if (!providersRsp.ok) {
|
|
15
|
+
const error = ((await providersRsp.json()) as { error?: unknown })?.error;
|
|
16
|
+
const errorMessage =
|
|
17
|
+
typeof error === 'string'
|
|
18
|
+
? error
|
|
19
|
+
: ((error as { message?: string })?.message ?? providersRsp.statusText);
|
|
20
|
+
if (error != null) {
|
|
21
|
+
scope?.error(undefined, `Failed to get connected providers from cloud: ${errorMessage}`);
|
|
22
|
+
}
|
|
23
|
+
this.ctx.hooks?.connection?.onConnectionsFetchFailed?.({ code: providersRsp.status });
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return ((await providersRsp.json()) as { data?: unknown })?.data as CloudIntegrationConnection[] | undefined;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async getConnectionSession(
|
|
31
|
+
id: IntegrationIds,
|
|
32
|
+
refreshToken?: string,
|
|
33
|
+
): Promise<CloudIntegrationAuthenticationSession | undefined> {
|
|
34
|
+
const scope = getScopedLogger();
|
|
35
|
+
|
|
36
|
+
const refresh = Boolean(refreshToken);
|
|
37
|
+
const cloudIntegrationType = toCloudIntegrationType[id];
|
|
38
|
+
if (cloudIntegrationType == null) {
|
|
39
|
+
scope?.error(undefined, `Unsupported cloud integration type: ${id}`);
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const reqInitOptions = refreshToken
|
|
44
|
+
? {
|
|
45
|
+
method: 'POST',
|
|
46
|
+
body: JSON.stringify({
|
|
47
|
+
access_token: refreshToken,
|
|
48
|
+
}),
|
|
49
|
+
}
|
|
50
|
+
: { method: 'GET' };
|
|
51
|
+
|
|
52
|
+
const tokenRsp = await this.ctx.account.fetchGkApi(
|
|
53
|
+
`v1/provider-tokens/${cloudIntegrationType}${refresh ? '/refresh' : ''}`,
|
|
54
|
+
reqInitOptions,
|
|
55
|
+
);
|
|
56
|
+
if (!tokenRsp.ok) {
|
|
57
|
+
const error = ((await tokenRsp.json()) as { error?: unknown })?.error;
|
|
58
|
+
const errorMessage =
|
|
59
|
+
typeof error === 'string' ? error : ((error as { message?: string })?.message ?? tokenRsp.statusText);
|
|
60
|
+
if (error != null) {
|
|
61
|
+
scope?.error(
|
|
62
|
+
undefined,
|
|
63
|
+
`Failed to ${refresh ? 'refresh' : 'get'} ${id} token from cloud: ${errorMessage}`,
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
this.ctx.hooks?.connection?.onConnectionFetchFailed?.({
|
|
67
|
+
id: id,
|
|
68
|
+
code: tokenRsp.status,
|
|
69
|
+
refreshing: refresh,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
if (refresh) {
|
|
73
|
+
// try once to just get the latest token if the refresh fails, and give up if that fails too
|
|
74
|
+
const newTokenRsp = await this.ctx.account.fetchGkApi(`v1/provider-tokens/${cloudIntegrationType}`, {
|
|
75
|
+
method: 'GET',
|
|
76
|
+
});
|
|
77
|
+
if (newTokenRsp.ok) {
|
|
78
|
+
return ((await newTokenRsp.json()) as { data?: unknown })?.data as
|
|
79
|
+
| CloudIntegrationAuthenticationSession
|
|
80
|
+
| undefined;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return ((await tokenRsp.json()) as { data?: unknown })?.data as
|
|
88
|
+
| CloudIntegrationAuthenticationSession
|
|
89
|
+
| undefined;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async disconnect(id: IntegrationIds): Promise<boolean> {
|
|
93
|
+
const scope = getScopedLogger();
|
|
94
|
+
|
|
95
|
+
const cloudIntegrationType = toCloudIntegrationType[id];
|
|
96
|
+
if (cloudIntegrationType == null) {
|
|
97
|
+
scope?.error(undefined, `Unsupported cloud integration type: ${id}`);
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const tokenRsp = await this.ctx.account.fetchGkApi(`v1/provider-tokens/${cloudIntegrationType}`, {
|
|
102
|
+
method: 'DELETE',
|
|
103
|
+
});
|
|
104
|
+
if (!tokenRsp.ok) {
|
|
105
|
+
const error = ((await tokenRsp.json()) as { error?: unknown })?.error;
|
|
106
|
+
const errorMessage =
|
|
107
|
+
typeof error === 'string' ? error : ((error as { message?: string })?.message ?? tokenRsp.statusText);
|
|
108
|
+
if (error != null) {
|
|
109
|
+
scope?.error(undefined, `Failed to disconnect ${id} token from cloud: ${errorMessage}`);
|
|
110
|
+
}
|
|
111
|
+
this.ctx.hooks?.connection?.onDisconnectFailed?.({
|
|
112
|
+
id: id,
|
|
113
|
+
code: tokenRsp.status,
|
|
114
|
+
});
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
}
|