@gitkraken/core-gitlens 0.7.1 → 0.8.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.
Files changed (188) hide show
  1. package/CHANGELOG.md +48 -1
  2. package/dist/git/cache.d.ts +18 -5
  3. package/dist/git/cache.js +26 -8
  4. package/dist/git/cache.js.map +1 -1
  5. package/dist/git/context.d.ts +5 -1
  6. package/dist/git/context.js.map +1 -1
  7. package/dist/git/errors.d.ts +28 -1
  8. package/dist/git/errors.js +45 -1
  9. package/dist/git/errors.js.map +1 -1
  10. package/dist/git/providers/branches.d.ts +5 -1
  11. package/dist/git/providers/commits.d.ts +24 -1
  12. package/dist/git/providers/config.d.ts +7 -1
  13. package/dist/git/providers/operations.d.ts +6 -0
  14. package/dist/git/providers/provider.d.ts +17 -0
  15. package/dist/git/providers/refs.d.ts +38 -3
  16. package/dist/git/providers/revision.d.ts +5 -1
  17. package/dist/git/providers/staging.d.ts +12 -0
  18. package/dist/git/providers/worktrees.d.ts +23 -3
  19. package/dist/git/run.types.d.ts +6 -0
  20. package/dist/git-cli/cliGitProvider.d.ts +17 -1
  21. package/dist/git-cli/cliGitProvider.js +37 -1
  22. package/dist/git-cli/cliGitProvider.js.map +1 -1
  23. package/dist/git-cli/exec/git.d.ts +12 -2
  24. package/dist/git-cli/exec/git.js +48 -17
  25. package/dist/git-cli/exec/git.js.map +1 -1
  26. package/dist/git-cli/exec/gitQueue.d.ts +4 -1
  27. package/dist/git-cli/exec/gitQueue.js +1 -1
  28. package/dist/git-cli/exec/gitQueue.js.map +1 -1
  29. package/dist/git-cli/providers/branches.d.ts +10 -1
  30. package/dist/git-cli/providers/branches.js +15 -8
  31. package/dist/git-cli/providers/branches.js.map +1 -1
  32. package/dist/git-cli/providers/commits.d.ts +23 -1
  33. package/dist/git-cli/providers/commits.js +57 -8
  34. package/dist/git-cli/providers/commits.js.map +1 -1
  35. package/dist/git-cli/providers/config.js +4 -3
  36. package/dist/git-cli/providers/config.js.map +1 -1
  37. package/dist/git-cli/providers/operations.d.ts +1 -0
  38. package/dist/git-cli/providers/operations.js +39 -3
  39. package/dist/git-cli/providers/operations.js.map +1 -1
  40. package/dist/git-cli/providers/patch.js +20 -41
  41. package/dist/git-cli/providers/patch.js.map +1 -1
  42. package/dist/git-cli/providers/pausedOperations.js +2 -2
  43. package/dist/git-cli/providers/pausedOperations.js.map +1 -1
  44. package/dist/git-cli/providers/refs.d.ts +15 -3
  45. package/dist/git-cli/providers/refs.js +115 -10
  46. package/dist/git-cli/providers/refs.js.map +1 -1
  47. package/dist/git-cli/providers/revision.d.ts +3 -1
  48. package/dist/git-cli/providers/revision.js +9 -5
  49. package/dist/git-cli/providers/revision.js.map +1 -1
  50. package/dist/git-cli/providers/staging.d.ts +8 -0
  51. package/dist/git-cli/providers/staging.js +59 -7
  52. package/dist/git-cli/providers/staging.js.map +1 -1
  53. package/dist/git-cli/providers/worktrees.d.ts +31 -2
  54. package/dist/git-cli/providers/worktrees.js +75 -7
  55. package/dist/git-cli/providers/worktrees.js.map +1 -1
  56. package/dist/ipc/discovery.js +1 -1
  57. package/dist/plus/agents/providers/claudeCodeTranscript.js +6 -6
  58. package/dist/plus/agents/providers/claudeCodeTranscript.js.map +1 -1
  59. package/dist/plus/ai/providers/openAICompatibleProviderBase.js +1 -1
  60. package/dist/plus/git-github/api/github.d.ts +64 -3
  61. package/dist/plus/git-github/api/github.js +237 -24
  62. package/dist/plus/git-github/api/github.js.map +1 -1
  63. package/dist/plus/git-github/providers/github/branches.d.ts +3 -1
  64. package/dist/plus/git-github/providers/github/branches.js +2 -1
  65. package/dist/plus/git-github/providers/github/branches.js.map +1 -1
  66. package/dist/plus/git-github/providers/github/refs.d.ts +10 -3
  67. package/dist/plus/git-github/providers/github/refs.js +4 -4
  68. package/dist/plus/git-github/providers/github/refs.js.map +1 -1
  69. package/dist/plus/git-github/providers/github/revision.d.ts +3 -1
  70. package/dist/plus/git-github/providers/github/revision.js +1 -1
  71. package/dist/plus/git-github/providers/github/revision.js.map +1 -1
  72. package/dist/plus/integrations/collectionMetadata.d.ts +48 -3
  73. package/dist/plus/integrations/collectionMetadata.js +138 -8
  74. package/dist/plus/integrations/collectionMetadata.js.map +1 -1
  75. package/dist/plus/integrations/errors.d.ts +3 -1
  76. package/dist/plus/integrations/errors.js +7 -3
  77. package/dist/plus/integrations/errors.js.map +1 -1
  78. package/dist/plus/integrations/index.d.ts +6 -3
  79. package/dist/plus/integrations/index.js.map +1 -1
  80. package/dist/plus/integrations/integrationService.d.ts +36 -10
  81. package/dist/plus/integrations/integrationService.js +16 -3
  82. package/dist/plus/integrations/integrationService.js.map +1 -1
  83. package/dist/plus/integrations/manager.d.ts +107 -37
  84. package/dist/plus/integrations/models/gitHostIntegration.d.ts +129 -14
  85. package/dist/plus/integrations/models/gitHostIntegration.js +142 -18
  86. package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
  87. package/dist/plus/integrations/models/integration.d.ts +117 -11
  88. package/dist/plus/integrations/models/integration.js +175 -13
  89. package/dist/plus/integrations/models/integration.js.map +1 -1
  90. package/dist/plus/integrations/models/issuesIntegration.d.ts +18 -5
  91. package/dist/plus/integrations/models/issuesIntegration.js +42 -10
  92. package/dist/plus/integrations/models/issuesIntegration.js.map +1 -1
  93. package/dist/plus/integrations/providers/azure/azure.d.ts +1 -1
  94. package/dist/plus/integrations/providers/azure/azure.js +14 -18
  95. package/dist/plus/integrations/providers/azure/azure.js.map +1 -1
  96. package/dist/plus/integrations/providers/azure/models.d.ts +29 -0
  97. package/dist/plus/integrations/providers/azure/models.js +112 -1
  98. package/dist/plus/integrations/providers/azure/models.js.map +1 -1
  99. package/dist/plus/integrations/providers/azureDevOps.d.ts +73 -3
  100. package/dist/plus/integrations/providers/azureDevOps.js +117 -3
  101. package/dist/plus/integrations/providers/azureDevOps.js.map +1 -1
  102. package/dist/plus/integrations/providers/azureDevOpsServer.js +2 -1
  103. package/dist/plus/integrations/providers/azureDevOpsServer.js.map +1 -1
  104. package/dist/plus/integrations/providers/bitbucket/bitbucket.d.ts +61 -0
  105. package/dist/plus/integrations/providers/bitbucket/bitbucket.js +165 -23
  106. package/dist/plus/integrations/providers/bitbucket/bitbucket.js.map +1 -1
  107. package/dist/plus/integrations/providers/bitbucket/models.d.ts +6 -1
  108. package/dist/plus/integrations/providers/bitbucket/models.js +4 -3
  109. package/dist/plus/integrations/providers/bitbucket/models.js.map +1 -1
  110. package/dist/plus/integrations/providers/bitbucket-server/pullRequestSearch.js +2 -2
  111. package/dist/plus/integrations/providers/bitbucket-server/pullRequestSearch.js.map +1 -1
  112. package/dist/plus/integrations/providers/bitbucket-server.d.ts +48 -2
  113. package/dist/plus/integrations/providers/bitbucket-server.js +51 -1
  114. package/dist/plus/integrations/providers/bitbucket-server.js.map +1 -1
  115. package/dist/plus/integrations/providers/bitbucket.d.ts +45 -2
  116. package/dist/plus/integrations/providers/bitbucket.js +41 -2
  117. package/dist/plus/integrations/providers/bitbucket.js.map +1 -1
  118. package/dist/plus/integrations/providers/github.d.ts +49 -5
  119. package/dist/plus/integrations/providers/github.js +102 -7
  120. package/dist/plus/integrations/providers/github.js.map +1 -1
  121. package/dist/plus/integrations/providers/gitlab/gitlab.d.ts +35 -0
  122. package/dist/plus/integrations/providers/gitlab/gitlab.js +132 -15
  123. package/dist/plus/integrations/providers/gitlab/gitlab.js.map +1 -1
  124. package/dist/plus/integrations/providers/gitlab/models.d.ts +1 -0
  125. package/dist/plus/integrations/providers/gitlab/models.js +1 -1
  126. package/dist/plus/integrations/providers/gitlab/models.js.map +1 -1
  127. package/dist/plus/integrations/providers/gitlab.d.ts +49 -2
  128. package/dist/plus/integrations/providers/gitlab.js +80 -4
  129. package/dist/plus/integrations/providers/gitlab.js.map +1 -1
  130. package/dist/plus/integrations/providers/jira-server.d.ts +3 -3
  131. package/dist/plus/integrations/providers/jira-server.js +5 -8
  132. package/dist/plus/integrations/providers/jira-server.js.map +1 -1
  133. package/dist/plus/integrations/providers/jira.d.ts +9 -0
  134. package/dist/plus/integrations/providers/jira.js +13 -1
  135. package/dist/plus/integrations/providers/jira.js.map +1 -1
  136. package/dist/plus/integrations/providers/linear.js +1 -1
  137. package/dist/plus/integrations/providers/models.d.ts +13 -2
  138. package/dist/plus/integrations/providers/models.js +11 -1
  139. package/dist/plus/integrations/providers/models.js.map +1 -1
  140. package/dist/plus/integrations/providers/providerErrors.d.ts +9 -1
  141. package/dist/plus/integrations/providers/providerErrors.js +10 -1
  142. package/dist/plus/integrations/providers/providerErrors.js.map +1 -1
  143. package/dist/plus/integrations/providers/providersApi.d.ts +60 -1
  144. package/dist/plus/integrations/providers/providersApi.js +137 -2
  145. package/dist/plus/integrations/providers/providersApi.js.map +1 -1
  146. package/dist/plus/integrations/providers/utils/providerPaging.d.ts +42 -0
  147. package/dist/plus/integrations/providers/utils/providerPaging.js +58 -1
  148. package/dist/plus/integrations/providers/utils/providerPaging.js.map +1 -1
  149. package/dist/plus/integrations/providers/utils.d.ts +1 -1
  150. package/dist/plus/integrations/reads/broaden.js +1 -1
  151. package/dist/plus/integrations/reads/context.d.ts +1 -1
  152. package/dist/plus/integrations/reads/counts.js +1 -1
  153. package/dist/plus/integrations/reads/currentAccount.d.ts +35 -0
  154. package/dist/plus/integrations/reads/currentAccount.js +46 -0
  155. package/dist/plus/integrations/reads/currentAccount.js.map +1 -0
  156. package/dist/plus/integrations/reads/drains.d.ts +5 -2
  157. package/dist/plus/integrations/reads/drains.js +8 -4
  158. package/dist/plus/integrations/reads/drains.js.map +1 -1
  159. package/dist/plus/integrations/reads/hierarchy.js +1 -1
  160. package/dist/plus/integrations/reads/hierarchy.utils.js +1 -1
  161. package/dist/plus/integrations/reads/issueBatch.d.ts +72 -12
  162. package/dist/plus/integrations/reads/issueBatch.js +193 -48
  163. package/dist/plus/integrations/reads/issueBatch.js.map +1 -1
  164. package/dist/plus/integrations/reads/issueTracker.js +1 -1
  165. package/dist/plus/integrations/reads/issues.js +1 -1
  166. package/dist/plus/integrations/reads/pullRequestBatch.d.ts +57 -0
  167. package/dist/plus/integrations/reads/pullRequestBatch.js +80 -0
  168. package/dist/plus/integrations/reads/pullRequestBatch.js.map +1 -0
  169. package/dist/plus/integrations/reads/pullRequestBranches.d.ts +58 -0
  170. package/dist/plus/integrations/reads/pullRequestBranches.js +111 -0
  171. package/dist/plus/integrations/reads/pullRequestBranches.js.map +1 -0
  172. package/dist/plus/integrations/reads/pullRequests.js +3 -3
  173. package/dist/plus/integrations/reads/pullRequests.js.map +1 -1
  174. package/dist/plus/integrations/reads/resolveRepository.js +1 -1
  175. package/dist/plus/integrations/reads/sweeps.js +4 -4
  176. package/dist/plus/integrations/reads/sweeps.js.map +1 -1
  177. package/dist/plus/integrations/results.d.ts +87 -6
  178. package/dist/plus/integrations/results.js +9 -2
  179. package/dist/plus/integrations/results.js.map +1 -1
  180. package/dist/utils/env/node/exec.js +3 -3
  181. package/dist/utils/env/node/exec.js.map +1 -1
  182. package/docs/integrations.md +175 -35
  183. package/docs/kepler-git-write-api-parity.md +239 -0
  184. package/docs/kepler-read-api-parity.md +75 -28
  185. package/package.json +1 -1
  186. package/dist/plus/integrations/reads/trackerIssue.d.ts +0 -33
  187. package/dist/plus/integrations/reads/trackerIssue.js +0 -60
  188. package/dist/plus/integrations/reads/trackerIssue.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"gitQueue.js","names":[],"sources":["../../../../git-cli/src/exec/gitQueue.ts"],"sourcesContent":["import type { GitCommandPriority } from './exec.types.js';\n\ninterface QueuedCommand {\n\trun: () => Promise<unknown>;\n\tresolve: (value: unknown) => void;\n\treject: (reason: unknown) => void;\n\tqueuedAt: number;\n\tpriority: GitCommandPriority;\n\tsignal?: AbortSignal;\n\tabortHandler?: () => void;\n}\n\n/** Priority levels in descending order (highest first) */\nconst priorities: GitCommandPriority[] = ['interactive', 'normal', 'background'];\n\n/** How many extra slots interactive commands can use when at capacity */\nconst interactiveBurstCapacity = 2;\n\nfunction abortReason(signal: AbortSignal): Error {\n\treturn signal.reason instanceof Error ? signal.reason : new Error('Aborted');\n}\n\nexport interface GitQueueConfig {\n\t/** Maximum number of concurrent git processes. Defaults to 7. */\n\tmaxConcurrent?: number;\n\t/** Maximum number of queued commands per priority level. Defaults to 500. Set to 0 to disable. */\n\tmaxQueueDepth?: number;\n}\n\nexport interface GitQueueHooks {\n\t/** Called when a queued command waited longer than 1 second before executing */\n\tonSlowQueue?(info: {\n\t\tpriority: GitCommandPriority;\n\t\twaitTime: number;\n\t\tactive: number;\n\t\tqueued: Record<GitCommandPriority, number>;\n\t\tmaxConcurrent: number;\n\t}): void;\n}\n\n/**\n * Priority-based concurrent queue for git command execution.\n *\n * Implements a multi-level feedback queue with:\n * - Configurable max concurrent processes\n * - Strict priority ordering (interactive > normal > background)\n * - Burst capacity for interactive commands under pressure\n *\n * Capacity rules (with limit N, burst B=2):\n * - All priorities share N slots normally\n * - When at capacity, interactive can burst up to N+B total\n *\n * Scheduling rules:\n * - Higher priority preempts: if interactive is waiting, normal/background queue\n * - Lower priority yields: background won't run if normal is waiting\n */\nexport class GitQueue {\n\tprivate readonly _queues = new Map<GitCommandPriority, QueuedCommand[]>([\n\t\t['interactive', []],\n\t\t['normal', []],\n\t\t['background', []],\n\t]);\n\n\tprivate _activeCount = 0;\n\tprivate _disposed = false;\n\n\tconstructor(\n\t\tprivate readonly _config: GitQueueConfig = {},\n\t\tprivate readonly _hooks: GitQueueHooks = {},\n\t) {}\n\n\tdispose(): void {\n\t\tthis._disposed = true;\n\t\tfor (const queue of this._queues.values()) {\n\t\t\tfor (const cmd of queue) {\n\t\t\t\tif (cmd.signal != null && cmd.abortHandler != null) {\n\t\t\t\t\tcmd.signal.removeEventListener('abort', cmd.abortHandler);\n\t\t\t\t}\n\t\t\t\tcmd.reject(new Error('GitQueue disposed'));\n\t\t\t}\n\t\t\tqueue.length = 0;\n\t\t}\n\t}\n\n\t/** Get the configured max concurrent processes */\n\tprivate get maxConcurrent(): number {\n\t\treturn this._config.maxConcurrent ?? 7;\n\t}\n\n\t/** Update configuration (e.g., when user changes settings) */\n\tupdateConfig(config: Partial<GitQueueConfig>): void {\n\t\tif (config.maxConcurrent != null && config.maxConcurrent > 0) {\n\t\t\tthis._config.maxConcurrent = config.maxConcurrent;\n\t\t}\n\t\tif (config.maxQueueDepth != null && config.maxQueueDepth > 0) {\n\t\t\tthis._config.maxQueueDepth = config.maxQueueDepth;\n\t\t}\n\t}\n\n\t/** Check if a command at the given priority can execute immediately */\n\tprivate canRunNow(priority: GitCommandPriority): boolean {\n\t\t// Must yield to higher priority waiting\n\t\tif (this.hasHigherPriorityWaiting(priority)) return false;\n\n\t\tconst max = this.maxConcurrent;\n\n\t\t// Under normal limit - all priorities can run\n\t\tif (this._activeCount < max) return true;\n\n\t\t// At or over normal limit - only interactive can burst\n\t\tif (priority === 'interactive' && this._activeCount < max + interactiveBurstCapacity) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/** Check if any higher-priority commands are waiting */\n\tprivate hasHigherPriorityWaiting(priority: GitCommandPriority): boolean {\n\t\tfor (const p of priorities) {\n\t\t\tif (p === priority) return false;\n\t\t\tif (this._queues.get(p)!.length > 0) return true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Execute a git command with the specified priority.\n\t *\n\t * When `signal` is provided:\n\t * - If already aborted, rejects immediately without running.\n\t * - If aborted while queued, the command is removed from the queue and rejected before it ever runs.\n\t * - If aborted while running, the in-flight spawn must honor the same signal separately\n\t * (callers pass it via `runOpts.cancellation`); the queue does not interrupt running work.\n\t */\n\trun<T>(priority: GitCommandPriority, fn: () => Promise<T>, signal?: AbortSignal): Promise<T> {\n\t\tif (this._disposed) {\n\t\t\treturn Promise.reject(new Error('GitQueue disposed'));\n\t\t}\n\n\t\tif (signal?.aborted) {\n\t\t\treturn Promise.reject(abortReason(signal));\n\t\t}\n\n\t\tif (!this.canRunNow(priority)) {\n\t\t\treturn this.enqueue(fn, priority, signal);\n\t\t}\n\n\t\treturn this.runcore(fn);\n\t}\n\n\tprivate async runcore<T>(fn: () => Promise<T>): Promise<T> {\n\t\tthis._activeCount++;\n\t\ttry {\n\t\t\treturn await fn();\n\t\t} finally {\n\t\t\tthis._activeCount--;\n\t\t\tthis.processQueues();\n\t\t}\n\t}\n\n\tprivate enqueue<T>(fn: () => Promise<T>, priority: GitCommandPriority, signal?: AbortSignal): Promise<T> {\n\t\tconst queue = this._queues.get(priority)!;\n\t\tconst maxDepth = this._config.maxQueueDepth ?? 500;\n\t\tif (maxDepth > 0 && queue.length >= maxDepth) {\n\t\t\treturn Promise.reject(new Error(`GitQueue '${priority}' queue is full (${maxDepth} commands pending)`));\n\t\t}\n\n\t\treturn new Promise<T>((resolve, reject) => {\n\t\t\tconst cmd: QueuedCommand = {\n\t\t\t\trun: fn,\n\t\t\t\tresolve: resolve as (value: unknown) => void,\n\t\t\t\treject: reject,\n\t\t\t\tqueuedAt: Date.now(),\n\t\t\t\tpriority: priority,\n\t\t\t\tsignal: signal,\n\t\t\t};\n\n\t\t\tif (signal != null) {\n\t\t\t\tcmd.abortHandler = () => {\n\t\t\t\t\tconst idx = queue.indexOf(cmd);\n\t\t\t\t\t// If still queued, remove and reject so it never runs.\n\t\t\t\t\t// If already dequeued, the running command should honor the signal at its own layer.\n\t\t\t\t\tif (idx !== -1) {\n\t\t\t\t\t\tqueue.splice(idx, 1);\n\t\t\t\t\t\tcmd.reject(abortReason(signal));\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\tsignal.addEventListener('abort', cmd.abortHandler, { once: true });\n\t\t\t}\n\n\t\t\tqueue.push(cmd);\n\t\t});\n\t}\n\n\tprivate processQueues(): void {\n\t\tif (this._disposed) return;\n\n\t\tconst max = this.maxConcurrent;\n\n\t\tfor (const priority of priorities) {\n\t\t\tconst queue = this._queues.get(priority)!;\n\t\t\tconst limit = priority === 'interactive' ? max + interactiveBurstCapacity : max;\n\n\t\t\twhile (queue.length > 0 && this._activeCount < limit && !this.hasHigherPriorityWaiting(priority)) {\n\t\t\t\tthis.runQueued(queue.shift()!);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate runQueued(cmd: QueuedCommand): void {\n\t\t// Detach the abort listener now that the command has left the queue — any subsequent\n\t\t// abort must be handled by the running spawn itself (via runOpts.cancellation).\n\t\tif (cmd.signal != null && cmd.abortHandler != null) {\n\t\t\tcmd.signal.removeEventListener('abort', cmd.abortHandler);\n\t\t\tcmd.abortHandler = undefined;\n\t\t}\n\n\t\tconst waitTime = Date.now() - cmd.queuedAt;\n\t\tif (waitTime > 1000) {\n\t\t\tthis._hooks.onSlowQueue?.({\n\t\t\t\tpriority: cmd.priority,\n\t\t\t\twaitTime: waitTime,\n\t\t\t\tactive: this._activeCount,\n\t\t\t\tqueued: {\n\t\t\t\t\tinteractive: this._queues.get('interactive')!.length,\n\t\t\t\t\tnormal: this._queues.get('normal')!.length,\n\t\t\t\t\tbackground: this._queues.get('background')!.length,\n\t\t\t\t},\n\t\t\t\tmaxConcurrent: this.maxConcurrent,\n\t\t\t});\n\t\t}\n\n\t\tthis._activeCount++;\n\t\ttry {\n\t\t\tcmd.run()\n\t\t\t\t.then(cmd.resolve, cmd.reject)\n\t\t\t\t.finally(() => {\n\t\t\t\t\tthis._activeCount--;\n\t\t\t\t\tthis.processQueues();\n\t\t\t\t});\n\t\t} catch (ex) {\n\t\t\tthis._activeCount--;\n\t\t\tcmd.reject(ex);\n\t\t\tthis.processQueues();\n\t\t}\n\t}\n\n\t/** Returns current queue statistics for diagnostics */\n\tgetStats(): { active: number; queued: Record<GitCommandPriority, number>; maxConcurrent: number } {\n\t\treturn {\n\t\t\tactive: this._activeCount,\n\t\t\tqueued: {\n\t\t\t\tinteractive: this._queues.get('interactive')!.length,\n\t\t\t\tnormal: this._queues.get('normal')!.length,\n\t\t\t\tbackground: this._queues.get('background')!.length,\n\t\t\t},\n\t\t\tmaxConcurrent: this.maxConcurrent,\n\t\t};\n\t}\n}\n\n/**\n * Git global options that consume the next positional arg as their value\n * (e.g. `--work-tree <path>`). Long-form `--name=value` is already skipped by\n * the leading-dash check, so only the separated form needs explicit handling.\n */\nconst optionsTakingValue = new Set([\n\t'-c',\n\t'-C',\n\t'--git-dir',\n\t'--work-tree',\n\t'--namespace',\n\t'--exec-path',\n\t'--super-prefix',\n\t'--config-env',\n\t'--attr-source',\n\t'--list-cmds',\n]);\n\n/** Extracts the primary git subcommand from an arg list, skipping global options and their values. */\nexport function getPrimaryGitCommand(args: readonly (string | undefined)[]): string | undefined {\n\tfor (let i = 0; i < args.length; i++) {\n\t\tconst a = args[i];\n\t\tif (a == null) continue;\n\t\tif (optionsTakingValue.has(a)) {\n\t\t\tconst next = args[i + 1];\n\t\t\tif (next != null && !next.startsWith('-')) {\n\t\t\t\ti++;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (a.startsWith('-')) continue;\n\n\t\treturn a;\n\t}\n\treturn undefined;\n}\n\n/**\n * Infers a queue priority from the git command being invoked.\n *\n * Intentionally narrow: only returns 'background' for commands that are\n * *always* read-only AND *always* potentially expensive. Polymorphic commands\n * like `log` and `rev-list` (which can be quick bounded lookups or full-history\n * walks) are deliberately omitted — call sites that perform heavy walks must\n * pass `priority: 'background'` explicitly. Never upgrades to 'interactive'.\n *\n * No subcommand awareness (e.g. `stash list`, `branch -l`): the risk of\n * misclassifying a write subcommand as background outweighs the gain.\n */\nexport function inferGitCommandPriority(args: readonly (string | undefined)[]): GitCommandPriority {\n\tswitch (getPrimaryGitCommand(args)) {\n\t\tcase 'for-each-ref':\n\t\tcase 'shortlog':\n\t\tcase 'reflog':\n\t\tcase 'name-rev':\n\t\tcase 'describe':\n\t\tcase 'cherry':\n\t\tcase 'count-objects':\n\t\tcase 'fsck':\n\t\t\treturn 'background';\n\t\tdefault:\n\t\t\treturn 'normal';\n\t}\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"gitQueue.js","names":[],"sources":["../../../../git-cli/src/exec/gitQueue.ts"],"sourcesContent":["import type { GitCommandPriority } from './exec.types.js';\n\ninterface QueuedCommand {\n\trun: () => Promise<unknown>;\n\tresolve: (value: unknown) => void;\n\treject: (reason: unknown) => void;\n\tqueuedAt: number;\n\tpriority: GitCommandPriority;\n\tsignal?: AbortSignal;\n\tabortHandler?: () => void;\n}\n\n/** Priority levels in descending order (highest first) */\nconst priorities: GitCommandPriority[] = ['interactive', 'normal', 'background'];\n\n/** How many extra slots interactive commands can use when at capacity */\nconst interactiveBurstCapacity = 2;\n\nfunction abortReason(signal: AbortSignal): Error {\n\treturn signal.reason instanceof Error ? signal.reason : new Error('Aborted');\n}\n\nexport interface GitQueueConfig {\n\t/**\n\t * Maximum number of concurrent git processes. Defaults to 20, the default of GitLens'\n\t * `advanced.git.maxConcurrentProcesses`.\n\t */\n\tmaxConcurrent?: number;\n\t/** Maximum number of queued commands per priority level. Defaults to 500. Set to 0 to disable. */\n\tmaxQueueDepth?: number;\n}\n\nexport interface GitQueueHooks {\n\t/** Called when a queued command waited longer than 1 second before executing */\n\tonSlowQueue?(info: {\n\t\tpriority: GitCommandPriority;\n\t\twaitTime: number;\n\t\tactive: number;\n\t\tqueued: Record<GitCommandPriority, number>;\n\t\tmaxConcurrent: number;\n\t}): void;\n}\n\n/**\n * Priority-based concurrent queue for git command execution.\n *\n * Implements a multi-level feedback queue with:\n * - Configurable max concurrent processes\n * - Strict priority ordering (interactive > normal > background)\n * - Burst capacity for interactive commands under pressure\n *\n * Capacity rules (with limit N, burst B=2):\n * - All priorities share N slots normally\n * - When at capacity, interactive can burst up to N+B total\n *\n * Scheduling rules:\n * - Higher priority preempts: if interactive is waiting, normal/background queue\n * - Lower priority yields: background won't run if normal is waiting\n */\nexport class GitQueue {\n\tprivate readonly _queues = new Map<GitCommandPriority, QueuedCommand[]>([\n\t\t['interactive', []],\n\t\t['normal', []],\n\t\t['background', []],\n\t]);\n\n\tprivate _activeCount = 0;\n\tprivate _disposed = false;\n\n\tconstructor(\n\t\tprivate readonly _config: GitQueueConfig = {},\n\t\tprivate readonly _hooks: GitQueueHooks = {},\n\t) {}\n\n\tdispose(): void {\n\t\tthis._disposed = true;\n\t\tfor (const queue of this._queues.values()) {\n\t\t\tfor (const cmd of queue) {\n\t\t\t\tif (cmd.signal != null && cmd.abortHandler != null) {\n\t\t\t\t\tcmd.signal.removeEventListener('abort', cmd.abortHandler);\n\t\t\t\t}\n\t\t\t\tcmd.reject(new Error('GitQueue disposed'));\n\t\t\t}\n\t\t\tqueue.length = 0;\n\t\t}\n\t}\n\n\t/** Get the configured max concurrent processes */\n\tprivate get maxConcurrent(): number {\n\t\treturn this._config.maxConcurrent ?? 20;\n\t}\n\n\t/** Update configuration (e.g., when user changes settings) */\n\tupdateConfig(config: Partial<GitQueueConfig>): void {\n\t\tif (config.maxConcurrent != null && config.maxConcurrent > 0) {\n\t\t\tthis._config.maxConcurrent = config.maxConcurrent;\n\t\t}\n\t\tif (config.maxQueueDepth != null && config.maxQueueDepth > 0) {\n\t\t\tthis._config.maxQueueDepth = config.maxQueueDepth;\n\t\t}\n\t}\n\n\t/** Check if a command at the given priority can execute immediately */\n\tprivate canRunNow(priority: GitCommandPriority): boolean {\n\t\t// Must yield to higher priority waiting\n\t\tif (this.hasHigherPriorityWaiting(priority)) return false;\n\n\t\tconst max = this.maxConcurrent;\n\n\t\t// Under normal limit - all priorities can run\n\t\tif (this._activeCount < max) return true;\n\n\t\t// At or over normal limit - only interactive can burst\n\t\tif (priority === 'interactive' && this._activeCount < max + interactiveBurstCapacity) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/** Check if any higher-priority commands are waiting */\n\tprivate hasHigherPriorityWaiting(priority: GitCommandPriority): boolean {\n\t\tfor (const p of priorities) {\n\t\t\tif (p === priority) return false;\n\t\t\tif (this._queues.get(p)!.length > 0) return true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Execute a git command with the specified priority.\n\t *\n\t * When `signal` is provided:\n\t * - If already aborted, rejects immediately without running.\n\t * - If aborted while queued, the command is removed from the queue and rejected before it ever runs.\n\t * - If aborted while running, the in-flight spawn must honor the same signal separately\n\t * (callers pass it via `runOpts.cancellation`); the queue does not interrupt running work.\n\t */\n\trun<T>(priority: GitCommandPriority, fn: () => Promise<T>, signal?: AbortSignal): Promise<T> {\n\t\tif (this._disposed) {\n\t\t\treturn Promise.reject(new Error('GitQueue disposed'));\n\t\t}\n\n\t\tif (signal?.aborted) {\n\t\t\treturn Promise.reject(abortReason(signal));\n\t\t}\n\n\t\tif (!this.canRunNow(priority)) {\n\t\t\treturn this.enqueue(fn, priority, signal);\n\t\t}\n\n\t\treturn this.runcore(fn);\n\t}\n\n\tprivate async runcore<T>(fn: () => Promise<T>): Promise<T> {\n\t\tthis._activeCount++;\n\t\ttry {\n\t\t\treturn await fn();\n\t\t} finally {\n\t\t\tthis._activeCount--;\n\t\t\tthis.processQueues();\n\t\t}\n\t}\n\n\tprivate enqueue<T>(fn: () => Promise<T>, priority: GitCommandPriority, signal?: AbortSignal): Promise<T> {\n\t\tconst queue = this._queues.get(priority)!;\n\t\tconst maxDepth = this._config.maxQueueDepth ?? 500;\n\t\tif (maxDepth > 0 && queue.length >= maxDepth) {\n\t\t\treturn Promise.reject(new Error(`GitQueue '${priority}' queue is full (${maxDepth} commands pending)`));\n\t\t}\n\n\t\treturn new Promise<T>((resolve, reject) => {\n\t\t\tconst cmd: QueuedCommand = {\n\t\t\t\trun: fn,\n\t\t\t\tresolve: resolve as (value: unknown) => void,\n\t\t\t\treject: reject,\n\t\t\t\tqueuedAt: Date.now(),\n\t\t\t\tpriority: priority,\n\t\t\t\tsignal: signal,\n\t\t\t};\n\n\t\t\tif (signal != null) {\n\t\t\t\tcmd.abortHandler = () => {\n\t\t\t\t\tconst idx = queue.indexOf(cmd);\n\t\t\t\t\t// If still queued, remove and reject so it never runs.\n\t\t\t\t\t// If already dequeued, the running command should honor the signal at its own layer.\n\t\t\t\t\tif (idx !== -1) {\n\t\t\t\t\t\tqueue.splice(idx, 1);\n\t\t\t\t\t\tcmd.reject(abortReason(signal));\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\tsignal.addEventListener('abort', cmd.abortHandler, { once: true });\n\t\t\t}\n\n\t\t\tqueue.push(cmd);\n\t\t});\n\t}\n\n\tprivate processQueues(): void {\n\t\tif (this._disposed) return;\n\n\t\tconst max = this.maxConcurrent;\n\n\t\tfor (const priority of priorities) {\n\t\t\tconst queue = this._queues.get(priority)!;\n\t\t\tconst limit = priority === 'interactive' ? max + interactiveBurstCapacity : max;\n\n\t\t\twhile (queue.length > 0 && this._activeCount < limit && !this.hasHigherPriorityWaiting(priority)) {\n\t\t\t\tthis.runQueued(queue.shift()!);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate runQueued(cmd: QueuedCommand): void {\n\t\t// Detach the abort listener now that the command has left the queue — any subsequent\n\t\t// abort must be handled by the running spawn itself (via runOpts.cancellation).\n\t\tif (cmd.signal != null && cmd.abortHandler != null) {\n\t\t\tcmd.signal.removeEventListener('abort', cmd.abortHandler);\n\t\t\tcmd.abortHandler = undefined;\n\t\t}\n\n\t\tconst waitTime = Date.now() - cmd.queuedAt;\n\t\tif (waitTime > 1000) {\n\t\t\tthis._hooks.onSlowQueue?.({\n\t\t\t\tpriority: cmd.priority,\n\t\t\t\twaitTime: waitTime,\n\t\t\t\tactive: this._activeCount,\n\t\t\t\tqueued: {\n\t\t\t\t\tinteractive: this._queues.get('interactive')!.length,\n\t\t\t\t\tnormal: this._queues.get('normal')!.length,\n\t\t\t\t\tbackground: this._queues.get('background')!.length,\n\t\t\t\t},\n\t\t\t\tmaxConcurrent: this.maxConcurrent,\n\t\t\t});\n\t\t}\n\n\t\tthis._activeCount++;\n\t\ttry {\n\t\t\tcmd.run()\n\t\t\t\t.then(cmd.resolve, cmd.reject)\n\t\t\t\t.finally(() => {\n\t\t\t\t\tthis._activeCount--;\n\t\t\t\t\tthis.processQueues();\n\t\t\t\t});\n\t\t} catch (ex) {\n\t\t\tthis._activeCount--;\n\t\t\tcmd.reject(ex);\n\t\t\tthis.processQueues();\n\t\t}\n\t}\n\n\t/** Returns current queue statistics for diagnostics */\n\tgetStats(): { active: number; queued: Record<GitCommandPriority, number>; maxConcurrent: number } {\n\t\treturn {\n\t\t\tactive: this._activeCount,\n\t\t\tqueued: {\n\t\t\t\tinteractive: this._queues.get('interactive')!.length,\n\t\t\t\tnormal: this._queues.get('normal')!.length,\n\t\t\t\tbackground: this._queues.get('background')!.length,\n\t\t\t},\n\t\t\tmaxConcurrent: this.maxConcurrent,\n\t\t};\n\t}\n}\n\n/**\n * Git global options that consume the next positional arg as their value\n * (e.g. `--work-tree <path>`). Long-form `--name=value` is already skipped by\n * the leading-dash check, so only the separated form needs explicit handling.\n */\nconst optionsTakingValue = new Set([\n\t'-c',\n\t'-C',\n\t'--git-dir',\n\t'--work-tree',\n\t'--namespace',\n\t'--exec-path',\n\t'--super-prefix',\n\t'--config-env',\n\t'--attr-source',\n\t'--list-cmds',\n]);\n\n/** Extracts the primary git subcommand from an arg list, skipping global options and their values. */\nexport function getPrimaryGitCommand(args: readonly (string | undefined)[]): string | undefined {\n\tfor (let i = 0; i < args.length; i++) {\n\t\tconst a = args[i];\n\t\tif (a == null) continue;\n\t\tif (optionsTakingValue.has(a)) {\n\t\t\tconst next = args[i + 1];\n\t\t\tif (next != null && !next.startsWith('-')) {\n\t\t\t\ti++;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (a.startsWith('-')) continue;\n\n\t\treturn a;\n\t}\n\treturn undefined;\n}\n\n/**\n * Infers a queue priority from the git command being invoked.\n *\n * Intentionally narrow: only returns 'background' for commands that are\n * *always* read-only AND *always* potentially expensive. Polymorphic commands\n * like `log` and `rev-list` (which can be quick bounded lookups or full-history\n * walks) are deliberately omitted — call sites that perform heavy walks must\n * pass `priority: 'background'` explicitly. Never upgrades to 'interactive'.\n *\n * No subcommand awareness (e.g. `stash list`, `branch -l`): the risk of\n * misclassifying a write subcommand as background outweighs the gain.\n */\nexport function inferGitCommandPriority(args: readonly (string | undefined)[]): GitCommandPriority {\n\tswitch (getPrimaryGitCommand(args)) {\n\t\tcase 'for-each-ref':\n\t\tcase 'shortlog':\n\t\tcase 'reflog':\n\t\tcase 'name-rev':\n\t\tcase 'describe':\n\t\tcase 'cherry':\n\t\tcase 'count-objects':\n\t\tcase 'fsck':\n\t\t\treturn 'background';\n\t\tdefault:\n\t\t\treturn 'normal';\n\t}\n}\n"],"mappings":"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"}
@@ -16,7 +16,9 @@ export declare class BranchesGitSubProvider implements GitBranchesSubProvider {
16
16
  private readonly cache;
17
17
  private readonly provider;
18
18
  constructor(context: GitServiceContext, git: Git, cache: Cache, provider: CliGitProviderInternal);
19
- getBranch(repoPath: string, name?: string, cancellation?: AbortSignal): Promise<GitBranch | undefined>;
19
+ getBranch(repoPath: string, name?: string, options?: {
20
+ force?: boolean;
21
+ }, cancellation?: AbortSignal): Promise<GitBranch | undefined>;
20
22
  private getCurrentBranch;
21
23
  getBranches(repoPath: string, options?: {
22
24
  filter?: (b: GitBranch) => boolean;
@@ -59,6 +61,13 @@ export declare class BranchesGitSubProvider implements GitBranchesSubProvider {
59
61
  deleteLocalBranch(repoPath: string, names: string | string[], options?: {
60
62
  force?: boolean;
61
63
  }): Promise<void>;
64
+ /**
65
+ * Drops what GitLens keeps for a local branch beyond its ref, for both ways one is deleted
66
+ * (`deleteLocalBranch` and `refs.deleteReference`). The persisted gk metadata goes too, not just the
67
+ * cached resolution: `getBaseBranchName` reads `branch.<ref>.gk-merge-base` before falling back to the
68
+ * reflog, so leaving it behind would hand a later branch reusing this name its predecessor's base.
69
+ */
70
+ forgetDeletedBranch(repoPath: string, name: string): Promise<void>;
62
71
  /**
63
72
  * Drops the cached and persisted per-branch metadata for whichever of `names` no longer exists. Only
64
73
  * for the partial-failure path — one extra `for-each-ref` is cheap while already handling an error,
@@ -34,7 +34,8 @@ var BranchesGitSubProvider = class {
34
34
  this.cache = cache;
35
35
  this.provider = provider;
36
36
  }
37
- async getBranch(repoPath, name, cancellation) {
37
+ async getBranch(repoPath, name, options, cancellation) {
38
+ if (options?.force) this.cache.evictCaches(repoPath, "branches");
38
39
  if (name != null) {
39
40
  const { values: [branch] } = await this.getBranches(repoPath, { filter: (b) => b.name === name }, cancellation);
40
41
  return branch;
@@ -244,7 +245,7 @@ var BranchesGitSubProvider = class {
244
245
  if (mergeTarget == null && options?.associatedPullRequest != null) {
245
246
  const pr = await options.associatedPullRequest;
246
247
  if (pr?.refs?.base != null) {
247
- const branch = await this.getBranch(repoPath, ref, cancellation);
248
+ const branch = await this.getBranch(repoPath, ref, void 0, cancellation);
248
249
  if (branch == null) return void 0;
249
250
  mergeTarget = `${branch.remoteName}/${pr.refs.base.branch}`;
250
251
  if (pr.stack == null) this.storeMergeTargetBranchName(repoPath, ref, mergeTarget, { skipInvalidation: ["branchOverviews"] });
@@ -460,10 +461,7 @@ var BranchesGitSubProvider = class {
460
461
  ];
461
462
  try {
462
463
  await this.git.run({ cwd: repoPath }, ...args);
463
- for (const branch of branches) {
464
- this.cache.deleteBaseBranchName(repoPath, branch);
465
- await this.provider.config.removeGkConfigBranchSection(repoPath, branch);
466
- }
464
+ for (const branch of branches) await this.forgetDeletedBranch(repoPath, branch);
467
465
  this.context.hooks?.cache?.onReset?.(repoPath, "branches");
468
466
  this.context.hooks?.repository?.onChanged?.(repoPath, ["heads"]);
469
467
  } catch (ex) {
@@ -491,6 +489,16 @@ var BranchesGitSubProvider = class {
491
489
  }
492
490
  }
493
491
  /**
492
+ * Drops what GitLens keeps for a local branch beyond its ref, for both ways one is deleted
493
+ * (`deleteLocalBranch` and `refs.deleteReference`). The persisted gk metadata goes too, not just the
494
+ * cached resolution: `getBaseBranchName` reads `branch.<ref>.gk-merge-base` before falling back to the
495
+ * reflog, so leaving it behind would hand a later branch reusing this name its predecessor's base.
496
+ */
497
+ async forgetDeletedBranch(repoPath, name) {
498
+ this.cache.deleteBaseBranchName(repoPath, name);
499
+ await this.provider.config.removeGkConfigBranchSection(repoPath, name);
500
+ }
501
+ /**
494
502
  * Drops the cached and persisted per-branch metadata for whichever of `names` no longer exists. Only
495
503
  * for the partial-failure path — one extra `for-each-ref` is cheap while already handling an error,
496
504
  * and keeps the success path free of it.
@@ -511,8 +519,7 @@ var BranchesGitSubProvider = class {
511
519
  for (const name of names) {
512
520
  if (surviving.has(name)) continue;
513
521
  anyDeleted = true;
514
- this.cache.deleteBaseBranchName(repoPath, name);
515
- await this.provider.config.removeGkConfigBranchSection(repoPath, name);
522
+ await this.forgetDeletedBranch(repoPath, name);
516
523
  }
517
524
  return anyDeleted;
518
525
  } catch {