@gitkraken/core-gitlens 0.5.109 → 0.5.111

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (416) hide show
  1. package/CHANGELOG.md +48 -1
  2. package/dist/git/cache.d.ts +111 -6
  3. package/dist/git/cache.d.ts.map +1 -1
  4. package/dist/git/cache.js +312 -43
  5. package/dist/git/cache.js.map +1 -1
  6. package/dist/git/context.d.ts +11 -0
  7. package/dist/git/context.d.ts.map +1 -1
  8. package/dist/git/context.js.map +1 -1
  9. package/dist/git/models/fileStatus.d.ts +1 -0
  10. package/dist/git/models/fileStatus.d.ts.map +1 -1
  11. package/dist/git/models/fileStatus.js +1 -0
  12. package/dist/git/models/fileStatus.js.map +1 -1
  13. package/dist/git/models/issue.d.ts +4 -0
  14. package/dist/git/models/issue.d.ts.map +1 -1
  15. package/dist/git/models/mergeConflicts.d.ts +2 -0
  16. package/dist/git/models/mergeConflicts.d.ts.map +1 -1
  17. package/dist/git/models/pullRequest.d.ts +119 -2
  18. package/dist/git/models/pullRequest.d.ts.map +1 -1
  19. package/dist/git/models/pullRequest.js +27 -1
  20. package/dist/git/models/pullRequest.js.map +1 -1
  21. package/dist/git/models/repository.d.ts +32 -5
  22. package/dist/git/models/repository.d.ts.map +1 -1
  23. package/dist/git/models/repository.js +58 -12
  24. package/dist/git/models/repository.js.map +1 -1
  25. package/dist/git/models/statusFile.d.ts.map +1 -1
  26. package/dist/git/models/statusFile.js +3 -0
  27. package/dist/git/models/statusFile.js.map +1 -1
  28. package/dist/git/providers/branches.d.ts +2 -0
  29. package/dist/git/providers/branches.d.ts.map +1 -1
  30. package/dist/git/providers/commits.d.ts +8 -0
  31. package/dist/git/providers/commits.d.ts.map +1 -1
  32. package/dist/git/providers/config.d.ts +19 -1
  33. package/dist/git/providers/config.d.ts.map +1 -1
  34. package/dist/git/providers/operations.d.ts +1 -0
  35. package/dist/git/providers/operations.d.ts.map +1 -1
  36. package/dist/git/providers/pausedOperations.d.ts +2 -0
  37. package/dist/git/providers/pausedOperations.d.ts.map +1 -1
  38. package/dist/git/providers/status.d.ts +1 -0
  39. package/dist/git/providers/status.d.ts.map +1 -1
  40. package/dist/git/utils/config.utils.d.ts +3 -0
  41. package/dist/git/utils/config.utils.d.ts.map +1 -0
  42. package/dist/git/utils/config.utils.js +8 -0
  43. package/dist/git/utils/config.utils.js.map +1 -0
  44. package/dist/git/utils/issue.utils.d.ts.map +1 -1
  45. package/dist/git/utils/issue.utils.js +2 -0
  46. package/dist/git/utils/issue.utils.js.map +1 -1
  47. package/dist/git/utils/pausedOperationStatus.utils.d.ts +14 -0
  48. package/dist/git/utils/pausedOperationStatus.utils.d.ts.map +1 -1
  49. package/dist/git/utils/pausedOperationStatus.utils.js +23 -0
  50. package/dist/git/utils/pausedOperationStatus.utils.js.map +1 -1
  51. package/dist/git/utils/pullRequest.utils.d.ts +24 -1
  52. package/dist/git/utils/pullRequest.utils.d.ts.map +1 -1
  53. package/dist/git/utils/pullRequest.utils.js +71 -0
  54. package/dist/git/utils/pullRequest.utils.js.map +1 -1
  55. package/dist/git/watching/changeEvent.d.ts +6 -1
  56. package/dist/git/watching/changeEvent.d.ts.map +1 -1
  57. package/dist/git/watching/classifyChange.d.ts.map +1 -1
  58. package/dist/git/watching/classifyChange.js +14 -1
  59. package/dist/git/watching/classifyChange.js.map +1 -1
  60. package/dist/git/watching/watchService.d.ts.map +1 -1
  61. package/dist/git/watching/watchService.js +18 -3
  62. package/dist/git/watching/watchService.js.map +1 -1
  63. package/dist/git/watching/watchSession.d.ts +8 -1
  64. package/dist/git/watching/watchSession.d.ts.map +1 -1
  65. package/dist/git/watching/watchSession.js +38 -6
  66. package/dist/git/watching/watchSession.js.map +1 -1
  67. package/dist/git/watching/watcherPatterns.d.ts +2 -2
  68. package/dist/git/watching/watcherPatterns.d.ts.map +1 -1
  69. package/dist/git/watching/watcherPatterns.js +1 -1
  70. package/dist/git/watching/watcherPatterns.js.map +1 -1
  71. package/dist/git-cli/exec/git.d.ts +1 -1
  72. package/dist/git-cli/exec/git.d.ts.map +1 -1
  73. package/dist/git-cli/exec/git.js +13 -3
  74. package/dist/git-cli/exec/git.js.map +1 -1
  75. package/dist/git-cli/providers/branches.d.ts +19 -0
  76. package/dist/git-cli/providers/branches.d.ts.map +1 -1
  77. package/dist/git-cli/providers/branches.js +282 -78
  78. package/dist/git-cli/providers/branches.js.map +1 -1
  79. package/dist/git-cli/providers/commits.d.ts +4 -0
  80. package/dist/git-cli/providers/commits.d.ts.map +1 -1
  81. package/dist/git-cli/providers/commits.js +84 -11
  82. package/dist/git-cli/providers/commits.js.map +1 -1
  83. package/dist/git-cli/providers/config.d.ts +42 -0
  84. package/dist/git-cli/providers/config.d.ts.map +1 -1
  85. package/dist/git-cli/providers/config.js +186 -5
  86. package/dist/git-cli/providers/config.js.map +1 -1
  87. package/dist/git-cli/providers/contributors.d.ts.map +1 -1
  88. package/dist/git-cli/providers/contributors.js +1 -1
  89. package/dist/git-cli/providers/contributors.js.map +1 -1
  90. package/dist/git-cli/providers/graph.d.ts +2 -2
  91. package/dist/git-cli/providers/graph.d.ts.map +1 -1
  92. package/dist/git-cli/providers/graph.js +27 -9
  93. package/dist/git-cli/providers/graph.js.map +1 -1
  94. package/dist/git-cli/providers/operations.d.ts.map +1 -1
  95. package/dist/git-cli/providers/operations.js +40 -12
  96. package/dist/git-cli/providers/operations.js.map +1 -1
  97. package/dist/git-cli/providers/pausedOperations.d.ts +5 -0
  98. package/dist/git-cli/providers/pausedOperations.d.ts.map +1 -1
  99. package/dist/git-cli/providers/pausedOperations.js +87 -16
  100. package/dist/git-cli/providers/pausedOperations.js.map +1 -1
  101. package/dist/git-cli/providers/refs.d.ts +5 -3
  102. package/dist/git-cli/providers/refs.d.ts.map +1 -1
  103. package/dist/git-cli/providers/refs.js +33 -4
  104. package/dist/git-cli/providers/refs.js.map +1 -1
  105. package/dist/git-cli/providers/status.d.ts +1 -0
  106. package/dist/git-cli/providers/status.d.ts.map +1 -1
  107. package/dist/git-cli/providers/status.js +18 -3
  108. package/dist/git-cli/providers/status.js.map +1 -1
  109. package/dist/git-cli/providers/worktrees.d.ts.map +1 -1
  110. package/dist/git-cli/providers/worktrees.js +4 -0
  111. package/dist/git-cli/providers/worktrees.js.map +1 -1
  112. package/dist/git-cli/service.d.ts.map +1 -1
  113. package/dist/git-cli/service.js.map +1 -1
  114. package/dist/plus/agents/providers/claudeCodeProvider.d.ts +39 -1
  115. package/dist/plus/agents/providers/claudeCodeProvider.d.ts.map +1 -1
  116. package/dist/plus/agents/providers/claudeCodeProvider.js +978 -71
  117. package/dist/plus/agents/providers/claudeCodeProvider.js.map +1 -1
  118. package/dist/plus/agents/providers/claudeCodeTranscript.d.ts +24 -2
  119. package/dist/plus/agents/providers/claudeCodeTranscript.d.ts.map +1 -1
  120. package/dist/plus/agents/providers/claudeCodeTranscript.js +84 -9
  121. package/dist/plus/agents/providers/claudeCodeTranscript.js.map +1 -1
  122. package/dist/plus/agents/types.d.ts +37 -2
  123. package/dist/plus/agents/types.d.ts.map +1 -1
  124. package/dist/plus/agents/types.js +2 -0
  125. package/dist/plus/agents/types.js.map +1 -1
  126. package/dist/plus/ai/errors.d.ts +10 -0
  127. package/dist/plus/ai/errors.d.ts.map +1 -1
  128. package/dist/plus/ai/errors.js +29 -0
  129. package/dist/plus/ai/errors.js.map +1 -1
  130. package/dist/plus/ai/models/model.d.ts +4 -0
  131. package/dist/plus/ai/models/model.d.ts.map +1 -1
  132. package/dist/plus/ai/models/model.js +51 -6
  133. package/dist/plus/ai/models/model.js.map +1 -1
  134. package/dist/plus/ai/models/promptTemplates.d.ts +1 -1
  135. package/dist/plus/ai/models/promptTemplates.d.ts.map +1 -1
  136. package/dist/plus/ai/models/provider.d.ts +60 -2
  137. package/dist/plus/ai/models/provider.d.ts.map +1 -1
  138. package/dist/plus/ai/prompts.d.ts +12 -0
  139. package/dist/plus/ai/prompts.d.ts.map +1 -1
  140. package/dist/plus/ai/prompts.js +177 -61
  141. package/dist/plus/ai/prompts.js.map +1 -1
  142. package/dist/plus/ai/providers/anthropicProvider.d.ts +10 -2
  143. package/dist/plus/ai/providers/anthropicProvider.d.ts.map +1 -1
  144. package/dist/plus/ai/providers/anthropicProvider.js +139 -46
  145. package/dist/plus/ai/providers/anthropicProvider.js.map +1 -1
  146. package/dist/plus/ai/providers/deepSeekProvider.d.ts +2 -0
  147. package/dist/plus/ai/providers/deepSeekProvider.d.ts.map +1 -1
  148. package/dist/plus/ai/providers/deepSeekProvider.js +10 -21
  149. package/dist/plus/ai/providers/deepSeekProvider.js.map +1 -1
  150. package/dist/plus/ai/providers/geminiProvider.d.ts +1 -0
  151. package/dist/plus/ai/providers/geminiProvider.d.ts.map +1 -1
  152. package/dist/plus/ai/providers/geminiProvider.js +19 -0
  153. package/dist/plus/ai/providers/geminiProvider.js.map +1 -1
  154. package/dist/plus/ai/providers/gitkrakenProvider.d.ts +5 -1
  155. package/dist/plus/ai/providers/gitkrakenProvider.d.ts.map +1 -1
  156. package/dist/plus/ai/providers/gitkrakenProvider.js +118 -3
  157. package/dist/plus/ai/providers/gitkrakenProvider.js.map +1 -1
  158. package/dist/plus/ai/providers/huggingFaceProvider.d.ts +1 -0
  159. package/dist/plus/ai/providers/huggingFaceProvider.d.ts.map +1 -1
  160. package/dist/plus/ai/providers/huggingFaceProvider.js +5 -0
  161. package/dist/plus/ai/providers/huggingFaceProvider.js.map +1 -1
  162. package/dist/plus/ai/providers/mistralProvider.d.ts +3 -1
  163. package/dist/plus/ai/providers/mistralProvider.d.ts.map +1 -1
  164. package/dist/plus/ai/providers/mistralProvider.js +99 -19
  165. package/dist/plus/ai/providers/mistralProvider.js.map +1 -1
  166. package/dist/plus/ai/providers/ollamaProvider.d.ts +4 -3
  167. package/dist/plus/ai/providers/ollamaProvider.d.ts.map +1 -1
  168. package/dist/plus/ai/providers/ollamaProvider.js +38 -3
  169. package/dist/plus/ai/providers/ollamaProvider.js.map +1 -1
  170. package/dist/plus/ai/providers/openAICompatibleProvider.d.ts +1 -0
  171. package/dist/plus/ai/providers/openAICompatibleProvider.d.ts.map +1 -1
  172. package/dist/plus/ai/providers/openAICompatibleProvider.js +4 -0
  173. package/dist/plus/ai/providers/openAICompatibleProvider.js.map +1 -1
  174. package/dist/plus/ai/providers/openAICompatibleProviderBase.d.ts +154 -5
  175. package/dist/plus/ai/providers/openAICompatibleProviderBase.d.ts.map +1 -1
  176. package/dist/plus/ai/providers/openAICompatibleProviderBase.js +259 -10
  177. package/dist/plus/ai/providers/openAICompatibleProviderBase.js.map +1 -1
  178. package/dist/plus/ai/providers/openRouterProvider.d.ts +4 -0
  179. package/dist/plus/ai/providers/openRouterProvider.d.ts.map +1 -1
  180. package/dist/plus/ai/providers/openRouterProvider.js +9 -0
  181. package/dist/plus/ai/providers/openRouterProvider.js.map +1 -1
  182. package/dist/plus/ai/providers/openaiProvider.d.ts +1 -0
  183. package/dist/plus/ai/providers/openaiProvider.d.ts.map +1 -1
  184. package/dist/plus/ai/providers/openaiProvider.js +1 -0
  185. package/dist/plus/ai/providers/openaiProvider.js.map +1 -1
  186. package/dist/plus/ai/providers/responseFormatCache.d.ts +8 -0
  187. package/dist/plus/ai/providers/responseFormatCache.d.ts.map +1 -0
  188. package/dist/plus/ai/providers/responseFormatCache.js +25 -0
  189. package/dist/plus/ai/providers/responseFormatCache.js.map +1 -0
  190. package/dist/plus/ai/providers/xaiProvider.d.ts +1 -0
  191. package/dist/plus/ai/providers/xaiProvider.d.ts.map +1 -1
  192. package/dist/plus/ai/providers/xaiProvider.js +10 -1
  193. package/dist/plus/ai/providers/xaiProvider.js.map +1 -1
  194. package/dist/plus/ai/utils/ai.utils.d.ts +3 -0
  195. package/dist/plus/ai/utils/ai.utils.d.ts.map +1 -1
  196. package/dist/plus/ai/utils/ai.utils.js +13 -0
  197. package/dist/plus/ai/utils/ai.utils.js.map +1 -1
  198. package/dist/plus/ai/utils/results.utils.d.ts +16 -2
  199. package/dist/plus/ai/utils/results.utils.d.ts.map +1 -1
  200. package/dist/plus/ai/utils/results.utils.js +204 -28
  201. package/dist/plus/ai/utils/results.utils.js.map +1 -1
  202. package/dist/plus/git-github/api/github.d.ts +92 -4
  203. package/dist/plus/git-github/api/github.d.ts.map +1 -1
  204. package/dist/plus/git-github/api/github.js +324 -20
  205. package/dist/plus/git-github/api/github.js.map +1 -1
  206. package/dist/plus/git-github/api/pullRequestSearchQuery.d.ts +27 -1
  207. package/dist/plus/git-github/api/pullRequestSearchQuery.d.ts.map +1 -1
  208. package/dist/plus/git-github/api/pullRequestSearchQuery.js +73 -6
  209. package/dist/plus/git-github/api/pullRequestSearchQuery.js.map +1 -1
  210. package/dist/plus/git-github/models.d.ts +33 -5
  211. package/dist/plus/git-github/models.d.ts.map +1 -1
  212. package/dist/plus/git-github/models.js +43 -4
  213. package/dist/plus/git-github/models.js.map +1 -1
  214. package/dist/plus/git-github/providers/github/status.d.ts +1 -0
  215. package/dist/plus/git-github/providers/github/status.d.ts.map +1 -1
  216. package/dist/plus/git-github/providers/github/status.js.map +1 -1
  217. package/dist/plus/integrations/context.d.ts +4 -0
  218. package/dist/plus/integrations/context.d.ts.map +1 -1
  219. package/dist/plus/integrations/index.d.ts.map +1 -1
  220. package/dist/plus/integrations/index.js +2 -0
  221. package/dist/plus/integrations/index.js.map +1 -1
  222. package/dist/plus/integrations/integrationService.d.ts +16 -1
  223. package/dist/plus/integrations/integrationService.d.ts.map +1 -1
  224. package/dist/plus/integrations/integrationService.js +9 -1
  225. package/dist/plus/integrations/integrationService.js.map +1 -1
  226. package/dist/plus/integrations/manager.d.ts +45 -5
  227. package/dist/plus/integrations/manager.d.ts.map +1 -1
  228. package/dist/plus/integrations/models/gitHostIntegration.d.ts +18 -3
  229. package/dist/plus/integrations/models/gitHostIntegration.d.ts.map +1 -1
  230. package/dist/plus/integrations/models/gitHostIntegration.js +30 -2
  231. package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
  232. package/dist/plus/integrations/models/integration.d.ts +4 -2
  233. package/dist/plus/integrations/models/integration.d.ts.map +1 -1
  234. package/dist/plus/integrations/models/integration.js +2 -2
  235. package/dist/plus/integrations/models/integration.js.map +1 -1
  236. package/dist/plus/integrations/providerFilters.d.ts +1 -1
  237. package/dist/plus/integrations/providerFilters.d.ts.map +1 -1
  238. package/dist/plus/integrations/providers/accounts.d.ts +6 -0
  239. package/dist/plus/integrations/providers/accounts.d.ts.map +1 -0
  240. package/dist/plus/integrations/providers/accounts.js +34 -0
  241. package/dist/plus/integrations/providers/accounts.js.map +1 -0
  242. package/dist/plus/integrations/providers/azure/models.d.ts.map +1 -1
  243. package/dist/plus/integrations/providers/azure/models.js +3 -0
  244. package/dist/plus/integrations/providers/azure/models.js.map +1 -1
  245. package/dist/plus/integrations/providers/bitbucket/models.d.ts.map +1 -1
  246. package/dist/plus/integrations/providers/bitbucket/models.js +1 -0
  247. package/dist/plus/integrations/providers/bitbucket/models.js.map +1 -1
  248. package/dist/plus/integrations/providers/github.d.ts +23 -2
  249. package/dist/plus/integrations/providers/github.d.ts.map +1 -1
  250. package/dist/plus/integrations/providers/github.js +169 -138
  251. package/dist/plus/integrations/providers/github.js.map +1 -1
  252. package/dist/plus/integrations/providers/gitlab.d.ts +9 -0
  253. package/dist/plus/integrations/providers/gitlab.d.ts.map +1 -1
  254. package/dist/plus/integrations/providers/gitlab.js +23 -4
  255. package/dist/plus/integrations/providers/gitlab.js.map +1 -1
  256. package/dist/plus/integrations/providers/models.d.ts +14 -32
  257. package/dist/plus/integrations/providers/models.d.ts.map +1 -1
  258. package/dist/plus/integrations/providers/models.js +66 -109
  259. package/dist/plus/integrations/providers/models.js.map +1 -1
  260. package/dist/plus/integrations/providers/pullRequestReviews.d.ts +50 -0
  261. package/dist/plus/integrations/providers/pullRequestReviews.d.ts.map +1 -0
  262. package/dist/plus/integrations/providers/pullRequestReviews.js +99 -0
  263. package/dist/plus/integrations/providers/pullRequestReviews.js.map +1 -0
  264. package/dist/plus/integrations/reads/broaden.d.ts.map +1 -1
  265. package/dist/plus/integrations/reads/broaden.js +6 -1
  266. package/dist/plus/integrations/reads/broaden.js.map +1 -1
  267. package/dist/plus/integrations/reads/counts.d.ts +55 -0
  268. package/dist/plus/integrations/reads/counts.d.ts.map +1 -1
  269. package/dist/plus/integrations/reads/counts.js +146 -2
  270. package/dist/plus/integrations/reads/counts.js.map +1 -1
  271. package/dist/plus/integrations/reads/drains.d.ts +7 -1
  272. package/dist/plus/integrations/reads/drains.d.ts.map +1 -1
  273. package/dist/plus/integrations/reads/drains.js +20 -6
  274. package/dist/plus/integrations/reads/drains.js.map +1 -1
  275. package/dist/plus/integrations/reads/filters.d.ts.map +1 -1
  276. package/dist/plus/integrations/reads/filters.js +22 -0
  277. package/dist/plus/integrations/reads/filters.js.map +1 -1
  278. package/dist/plus/integrations/reads/hierarchy.d.ts.map +1 -1
  279. package/dist/plus/integrations/reads/hierarchy.js +3 -1
  280. package/dist/plus/integrations/reads/hierarchy.js.map +1 -1
  281. package/dist/plus/integrations/reads/issueTracker.d.ts.map +1 -1
  282. package/dist/plus/integrations/reads/issueTracker.js +8 -3
  283. package/dist/plus/integrations/reads/issueTracker.js.map +1 -1
  284. package/dist/plus/integrations/reads/issues.d.ts.map +1 -1
  285. package/dist/plus/integrations/reads/issues.js +9 -4
  286. package/dist/plus/integrations/reads/issues.js.map +1 -1
  287. package/dist/plus/integrations/reads/pullRequests.d.ts.map +1 -1
  288. package/dist/plus/integrations/reads/pullRequests.js +9 -4
  289. package/dist/plus/integrations/reads/pullRequests.js.map +1 -1
  290. package/dist/plus/integrations/reads/searchPullRequests.d.ts +4 -3
  291. package/dist/plus/integrations/reads/searchPullRequests.d.ts.map +1 -1
  292. package/dist/plus/integrations/reads/searchPullRequests.js +6 -4
  293. package/dist/plus/integrations/reads/searchPullRequests.js.map +1 -1
  294. package/dist/plus/integrations/reads/sweeps.js +1 -1
  295. package/dist/plus/integrations/reads/sweeps.js.map +1 -1
  296. package/dist/plus/integrations/reads/warnings.d.ts +2 -2
  297. package/dist/plus/integrations/reads/warnings.d.ts.map +1 -1
  298. package/dist/plus/integrations/reads/warnings.js +11 -2
  299. package/dist/plus/integrations/reads/warnings.js.map +1 -1
  300. package/dist/plus/integrations/results.d.ts +6 -1
  301. package/dist/plus/integrations/results.d.ts.map +1 -1
  302. package/dist/plus/integrations/results.js.map +1 -1
  303. package/dist/utils/env/browser/base64.d.ts +1 -1
  304. package/dist/utils/env/browser/base64.d.ts.map +1 -1
  305. package/dist/utils/env/node/base64.d.ts +1 -1
  306. package/dist/utils/env/node/base64.d.ts.map +1 -1
  307. package/dist/utils/env/node/base64.js +2 -0
  308. package/dist/utils/env/node/base64.js.map +1 -1
  309. package/dist/utils/keys/chord.d.ts +52 -0
  310. package/dist/utils/keys/chord.d.ts.map +1 -0
  311. package/dist/utils/keys/chord.js +135 -0
  312. package/dist/utils/keys/chord.js.map +1 -0
  313. package/dist/utils/keys/keybinding.d.ts +53 -0
  314. package/dist/utils/keys/keybinding.d.ts.map +1 -0
  315. package/dist/utils/keys/keybinding.js +58 -0
  316. package/dist/utils/keys/keybinding.js.map +1 -0
  317. package/dist/utils/path.d.ts +11 -0
  318. package/dist/utils/path.d.ts.map +1 -1
  319. package/dist/utils/path.js +13 -0
  320. package/dist/utils/path.js.map +1 -1
  321. package/docs/integrations.md +76 -10
  322. package/docs/kepler-read-api-parity.md +9 -0
  323. package/package.json +13 -5
  324. package/src/git/cache.ts +383 -47
  325. package/src/git/context.ts +11 -0
  326. package/src/git/models/fileStatus.ts +1 -0
  327. package/src/git/models/issue.ts +4 -0
  328. package/src/git/models/mergeConflicts.ts +3 -2
  329. package/src/git/models/pullRequest.ts +117 -1
  330. package/src/git/models/repository.ts +58 -17
  331. package/src/git/models/statusFile.ts +3 -0
  332. package/src/git/providers/branches.ts +6 -0
  333. package/src/git/providers/commits.ts +11 -0
  334. package/src/git/providers/config.ts +18 -0
  335. package/src/git/providers/operations.ts +1 -0
  336. package/src/git/providers/pausedOperations.ts +2 -0
  337. package/src/git/providers/status.ts +1 -0
  338. package/src/git/utils/config.utils.ts +8 -0
  339. package/src/git/utils/issue.utils.ts +2 -0
  340. package/src/git/utils/pausedOperationStatus.utils.ts +28 -0
  341. package/src/git/utils/pullRequest.utils.ts +86 -0
  342. package/src/git/watching/changeEvent.ts +6 -1
  343. package/src/git/watching/classifyChange.ts +15 -1
  344. package/src/git/watching/watchService.ts +20 -3
  345. package/src/git/watching/watchSession.ts +41 -6
  346. package/src/git/watching/watcherPatterns.ts +1 -1
  347. package/src/git-cli/exec/git.ts +13 -3
  348. package/src/git-cli/providers/branches.ts +384 -132
  349. package/src/git-cli/providers/commits.ts +106 -15
  350. package/src/git-cli/providers/config.ts +229 -8
  351. package/src/git-cli/providers/contributors.ts +5 -1
  352. package/src/git-cli/providers/graph.ts +26 -13
  353. package/src/git-cli/providers/operations.ts +45 -20
  354. package/src/git-cli/providers/pausedOperations.ts +109 -17
  355. package/src/git-cli/providers/refs.ts +33 -3
  356. package/src/git-cli/providers/status.ts +25 -4
  357. package/src/git-cli/providers/worktrees.ts +5 -0
  358. package/src/git-cli/service.ts +0 -1
  359. package/src/plus/agents/providers/claudeCodeProvider.ts +1130 -87
  360. package/src/plus/agents/providers/claudeCodeTranscript.ts +95 -9
  361. package/src/plus/agents/types.ts +46 -2
  362. package/src/plus/ai/errors.ts +30 -0
  363. package/src/plus/ai/models/model.ts +56 -6
  364. package/src/plus/ai/models/promptTemplates.ts +1 -1
  365. package/src/plus/ai/models/provider.ts +69 -2
  366. package/src/plus/ai/prompts.ts +186 -61
  367. package/src/plus/ai/providers/anthropicProvider.ts +155 -47
  368. package/src/plus/ai/providers/deepSeekProvider.ts +11 -21
  369. package/src/plus/ai/providers/geminiProvider.ts +19 -0
  370. package/src/plus/ai/providers/gitkrakenProvider.ts +126 -3
  371. package/src/plus/ai/providers/huggingFaceProvider.ts +6 -0
  372. package/src/plus/ai/providers/mistralProvider.ts +102 -19
  373. package/src/plus/ai/providers/ollamaProvider.ts +55 -4
  374. package/src/plus/ai/providers/openAICompatibleProvider.ts +5 -0
  375. package/src/plus/ai/providers/openAICompatibleProviderBase.ts +360 -17
  376. package/src/plus/ai/providers/openRouterProvider.ts +17 -0
  377. package/src/plus/ai/providers/openaiProvider.ts +1 -0
  378. package/src/plus/ai/providers/responseFormatCache.ts +39 -0
  379. package/src/plus/ai/providers/xaiProvider.ts +10 -1
  380. package/src/plus/ai/utils/ai.utils.ts +14 -0
  381. package/src/plus/ai/utils/results.utils.ts +255 -31
  382. package/src/plus/git-github/api/github.ts +467 -23
  383. package/src/plus/git-github/api/pullRequestSearchQuery.ts +81 -7
  384. package/src/plus/git-github/models.ts +77 -7
  385. package/src/plus/git-github/providers/github/status.ts +1 -0
  386. package/src/plus/integrations/context.ts +4 -0
  387. package/src/plus/integrations/index.ts +2 -0
  388. package/src/plus/integrations/integrationService.ts +25 -2
  389. package/src/plus/integrations/manager.ts +50 -5
  390. package/src/plus/integrations/models/gitHostIntegration.ts +54 -2
  391. package/src/plus/integrations/models/integration.ts +24 -13
  392. package/src/plus/integrations/providerFilters.ts +6 -1
  393. package/src/plus/integrations/providers/accounts.ts +38 -0
  394. package/src/plus/integrations/providers/azure/models.ts +3 -0
  395. package/src/plus/integrations/providers/bitbucket/models.ts +1 -0
  396. package/src/plus/integrations/providers/github.ts +218 -145
  397. package/src/plus/integrations/providers/gitlab.ts +30 -20
  398. package/src/plus/integrations/providers/models.ts +99 -127
  399. package/src/plus/integrations/providers/pullRequestReviews.ts +122 -0
  400. package/src/plus/integrations/reads/broaden.ts +6 -1
  401. package/src/plus/integrations/reads/counts.ts +273 -2
  402. package/src/plus/integrations/reads/drains.ts +19 -6
  403. package/src/plus/integrations/reads/filters.ts +22 -0
  404. package/src/plus/integrations/reads/hierarchy.ts +3 -1
  405. package/src/plus/integrations/reads/issueTracker.ts +9 -3
  406. package/src/plus/integrations/reads/issues.ts +9 -4
  407. package/src/plus/integrations/reads/pullRequests.ts +9 -4
  408. package/src/plus/integrations/reads/searchPullRequests.ts +12 -4
  409. package/src/plus/integrations/reads/sweeps.ts +1 -1
  410. package/src/plus/integrations/reads/warnings.ts +12 -1
  411. package/src/plus/integrations/results.ts +6 -1
  412. package/src/utils/env/browser/base64.ts +1 -1
  413. package/src/utils/env/node/base64.ts +3 -1
  414. package/src/utils/keys/chord.ts +184 -0
  415. package/src/utils/keys/keybinding.ts +116 -0
  416. package/src/utils/path.ts +14 -0
@@ -9,13 +9,14 @@ import { request } from '@octokit/request';
9
9
  import { RequestError } from '@octokit/request-error';
10
10
  import { AuthenticationError, AuthenticationErrorReason, RequestClientError, RequestNotFoundError, RequestRateLimitError, } from '../../../git/errors.js';
11
11
  import { defaultIssueSort } from '../../../git/models/issue.js';
12
- import { PullRequestMergeMethod } from '../../../git/models/pullRequest.js';
12
+ import { defaultPullRequestSort, PullRequestMergeMethod } from '../../../git/models/pullRequest.js';
13
13
  import { getGitHubNoReplyAddressParts } from '../../../git/remotes/github.js';
14
14
  import { effectiveIssueSort, getIssueComparator } from '../../../git/utils/issue.utils.js';
15
+ import { getPullRequestComparator } from '../../../git/utils/pullRequest.utils.js';
15
16
  import { createRevisionRange, getRevisionRangeParts, isRevisionRange, isSha, } from '../../../git/utils/revision.utils.js';
16
17
  import { chunk } from '../../../utils/array.js';
17
18
  import { base64 } from '../../../utils/base64.js';
18
- import { CancellationError } from '../../../utils/cancellation.js';
19
+ import { CancellationError, isCancellationError } from '../../../utils/cancellation.js';
19
20
  import { trace } from '../../../utils/decorators/log.js';
20
21
  import { Emitter } from '../../../utils/event.js';
21
22
  import { uniqueBy } from '../../../utils/iterable.js';
@@ -51,10 +52,17 @@ const requestRetryMaxDelay = 2000; // ms
51
52
  const accountResolveBatchSize = 25;
52
53
  // Pull-request search selects the full PR fragment (reviews, requests, refs, commits, etc.),
53
54
  // which makes GitHub reject broad 100-node searches with `Resource limits for this query
54
- // exceeded` on large repositories. Thirty keeps the default within that GraphQL cost budget
55
- // while callers that know their scope is cheap can still opt into the supported 100-node max.
55
+ // exceeded` on large repositories. Thirty keeps the default within that GraphQL cost budget;
56
+ // the 100-node maximum the connection accepts is for the lite shape, whose per-node cost is a
57
+ // fraction of it. The budget is per DOCUMENT, and one document holds every relationship × state
58
+ // facet, so the worst case scales with the facet count (five relationships × four states = 20).
56
59
  const defaultPullRequestSearchPageSize = 30;
57
60
  const maxPullRequestSearchPageSize = 100;
61
+ // Pages `searchMyPullRequests` drains for a caller that wants a whole list rather than a page.
62
+ // Four reduced pages cover more than the single 100-node page this read served before it paged,
63
+ // so the smaller page costs coverage nowhere; it bounds an unbounded drain on a read whose
64
+ // consumers (Launchpad, the Graph pull-request panel) block on it.
65
+ const maxMyPullRequestSearchPages = 4;
58
66
  function isRetryableTransientError(ex) {
59
67
  // An aborted request is rethrown as the original `AbortError` (not a `RequestError`), so it is
60
68
  // excluded here. octokit maps a fetch/network failure to a `RequestError` with status 500 and
@@ -117,6 +125,42 @@ title
117
125
  updatedAt
118
126
  url
119
127
  `;
128
+ /**
129
+ * Stacked-pull-request selections, appended to a pull request's selection set rather than baked into
130
+ * the fragments below: GitHub Enterprise Server schemas lag github.com, and selecting `stack` there
131
+ * fails the entire query with "Field 'stack' doesn't exist on type 'PullRequest'" — which would take
132
+ * every PR feature down with it, not just stacks. Always add these via `gqlPullRequestStackFragmentFor`.
133
+ */
134
+ const gqlPullRequestStackFragment = `
135
+ stack {
136
+ id
137
+ number
138
+ size
139
+ baseRefName
140
+ }
141
+ stackEntry {
142
+ position
143
+ }
144
+ `;
145
+ function gqlPullRequestStackFragmentFor(options) {
146
+ return isGitHubDotCom(options) ? gqlPullRequestStackFragment : '';
147
+ }
148
+ /**
149
+ * A 409 means a merge request is already in flight and carries its ticket, so it resumes rather than fails.
150
+ *
151
+ * The body has to be dug out of `original`: `requestCore` routes every 4xx through `handleRequestError`,
152
+ * which re-wraps octokit's `RequestError` in a `RequestClientError` carrying only `message` and `original`.
153
+ */
154
+ function getAsyncMergeUuidFromConflict(ex) {
155
+ const err = (RequestClientError.is(ex) ? ex.original : ex);
156
+ if (err?.status !== 409)
157
+ return undefined;
158
+ return err.response?.data?.details?.uuid;
159
+ }
160
+ const asyncMergePollIntervalMs = 2000;
161
+ /** A stack merges one layer at a time and GitHub only promises "a few minutes", so the ceiling is
162
+ * generous — giving up early would report a failure for a merge still in progress. */
163
+ const maxAsyncMergePolls = 300;
120
164
  const gqlPullRequestLiteFragment = `
121
165
  ${gqlIssueOrPullRequestFragment}
122
166
  author {
@@ -153,6 +197,24 @@ repository {
153
197
  viewerPermission
154
198
  }
155
199
  `;
200
+ /**
201
+ * One review's fields, shared by `latestReviews` and `viewerLatestReview`. The two selections must stay
202
+ * identical: `fromGitHubPullRequest` merges the viewer's review into the capped `latestReviews` window and
203
+ * dedups by `id`, so a field present in only one of them would produce rows that differ by where they came
204
+ * from rather than by what they are.
205
+ */
206
+ const gqlPullRequestReviewFragment = `
207
+ id
208
+ author {
209
+ login
210
+ avatarUrl(size: $avatarSize)
211
+ url
212
+ }
213
+ state
214
+ commit {
215
+ oid
216
+ }
217
+ `;
156
218
  const gqlPullRequestFragment = `
157
219
  ${gqlPullRequestLiteFragment}
158
220
  additions
@@ -163,6 +225,7 @@ assignees(first: 25) {
163
225
  url
164
226
  }
165
227
  }
228
+ changedFiles
166
229
  checksUrl
167
230
  deletions
168
231
  mergeable
@@ -172,14 +235,12 @@ mergedBy {
172
235
  reviewDecision
173
236
  latestReviews(first: 25) {
174
237
  nodes {
175
- author {
176
- login
177
- avatarUrl(size: $avatarSize)
178
- url
179
- }
180
- state
238
+ ${gqlPullRequestReviewFragment}
181
239
  }
182
240
  }
241
+ viewerLatestReview {
242
+ ${gqlPullRequestReviewFragment}
243
+ }
183
244
  reviewRequests(first: 25) {
184
245
  nodes {
185
246
  asCodeOwner
@@ -194,6 +255,7 @@ reviewRequests(first: 25) {
194
255
  }
195
256
  }
196
257
  commits(last: 1) {
258
+ totalCount
197
259
  nodes {
198
260
  commit {
199
261
  statusCheckRollup {
@@ -271,6 +333,7 @@ export class GitHubApi {
271
333
  try {
272
334
  const query = `query getCurrentAccount($avatarSize: Int) {
273
335
  viewer {
336
+ databaseId
274
337
  name
275
338
  email
276
339
  login
@@ -282,7 +345,10 @@ export class GitHubApi {
282
345
  return undefined;
283
346
  return {
284
347
  provider: provider,
285
- id: rsp.viewer.login,
348
+ // `id` is the provider's own id, as it is for every other provider, and `username` the handle
349
+ // filters and viewer matching key on. Falls back to the login only when GitHub omits the
350
+ // database id, which leaves the two equal rather than leaving `id` empty.
351
+ id: rsp.viewer.databaseId != null ? String(rsp.viewer.databaseId) : rsp.viewer.login,
286
352
  name: rsp.viewer.name ?? undefined,
287
353
  email: rsp.viewer.email ?? undefined,
288
354
  // If we are GitHub Enterprise, we may need to convert the avatar URL since it might require authentication
@@ -579,6 +645,7 @@ export class GitHubApi {
579
645
  repository(name: $repo, owner: $owner) {
580
646
  pullRequest(number: $number) {
581
647
  ${gqlPullRequestLiteFragment}
648
+ ${gqlPullRequestStackFragmentFor(options)}
582
649
  }
583
650
  }
584
651
  }`;
@@ -614,6 +681,7 @@ export class GitHubApi {
614
681
  associatedPullRequests(first: $limit, orderBy: {field: UPDATED_AT, direction: DESC}, states: $include) {
615
682
  nodes {
616
683
  ${gqlPullRequestLiteFragment}
684
+ ${gqlPullRequestStackFragmentFor(options)}
617
685
  }
618
686
  }
619
687
  }
@@ -659,6 +727,7 @@ export class GitHubApi {
659
727
  associatedPullRequests(first: 2, orderBy: {field: UPDATED_AT, direction: DESC}) {
660
728
  nodes {
661
729
  ${gqlPullRequestLiteFragment}
730
+ ${gqlPullRequestStackFragmentFor(options)}
662
731
  }
663
732
  }
664
733
  }
@@ -1974,6 +2043,17 @@ export class GitHubApi {
1974
2043
  return promise;
1975
2044
  }
1976
2045
  async request(provider, token, route, options, scope, cancellation) {
2046
+ return (await this.requestCore(provider, token, route, options, scope, cancellation));
2047
+ }
2048
+ /**
2049
+ * REST call for routes `@octokit/types` doesn't describe yet — currently the stacked-pull-request
2050
+ * merge APIs, which are in public preview and absent from the generated endpoint map. Prefer
2051
+ * `request` for anything typed.
2052
+ */
2053
+ async requestPreview(provider, token, route, options, scope, cancellation) {
2054
+ return (await this.requestCore(provider, token, route, options, scope, cancellation));
2055
+ }
2056
+ async requestCore(provider, token, route, options, scope, cancellation) {
1977
2057
  const { accessToken } = token;
1978
2058
  try {
1979
2059
  let signal;
@@ -1986,7 +2066,7 @@ export class GitHubApi {
1986
2066
  // Retry transient gateway/network failures on idempotent reads only
1987
2067
  const method = route.split(' ', 1)[0].toUpperCase();
1988
2068
  const retryable = method === 'GET' || method === 'HEAD';
1989
- return (await this.requestWithRetries(() => this.config.wrapForForcedInsecureSSL(provider?.getIgnoreSSLErrors() ?? false, () => this.getDefaults(accessToken, request)(route, options)), retryable, signal, scope));
2069
+ return await this.requestWithRetries(() => this.config.wrapForForcedInsecureSSL(provider?.getIgnoreSSLErrors() ?? false, () => this.getDefaults(accessToken, request)(route, options)), retryable, signal, scope);
1990
2070
  }
1991
2071
  catch (ex) {
1992
2072
  if (ex instanceof RequestError || ex.name === 'AbortError') {
@@ -2161,14 +2241,21 @@ export class GitHubApi {
2161
2241
  * One page of the current user's pull requests, filtered by state and optionally by an explicit
2162
2242
  * relationship qualifier. Backs the PR sweeps, which drain it page by page.
2163
2243
  *
2164
- * Ordering is part of the contract, not an option: always `sort:updated` (most recently updated first),
2165
- * matching {@link searchPullRequestsPage}. A caller that stops before `hasMore` clears every sweep with a
2244
+ * Ordering is part of the contract, not an option: always `sort:updated` (most recently updated first), which is
2245
+ * {@link searchPullRequestsPage}'s DEFAULT rather than its only orderthat read takes a `criteria.sort`, this
2246
+ * one does not, because a sweep's recency window is what its page budget is defined against. A caller that stops
2247
+ * before `hasMore` clears — every sweep with a
2166
2248
  * page budget — therefore retains a well-defined recency window instead of an arbitrary slice of GitHub's
2167
2249
  * relevance ranking.
2168
2250
  */
2169
2251
  async searchMyPullRequestsPage(provider, token, options, cancellation) {
2170
2252
  const scope = getScopedLogger();
2171
- const limit = Math.min(100, this.config.getLaunchpadQueryLimit?.() ?? 100);
2253
+ // The page follows the projection rather than being a separate decision: the full fragment is what GitHub
2254
+ // rejects at 100 nodes (see `defaultPullRequestSearchPageSize`), so every read that selects it pages at the
2255
+ // reduced size, and only the lite shape asks for the maximum. A caller that wants a whole list pages for it
2256
+ // — see `searchMyPullRequests`.
2257
+ const configuredLimit = this.config.getLaunchpadQueryLimit?.() ?? maxPullRequestSearchPageSize;
2258
+ const limit = Math.min(options?.summary === true ? maxPullRequestSearchPageSize : defaultPullRequestSearchPageSize, configuredLimit);
2172
2259
  try {
2173
2260
  const query = `query searchMyPullRequests(
2174
2261
  $search: String!
@@ -2184,6 +2271,7 @@ export class GitHubApi {
2184
2271
  nodes {
2185
2272
  ...on PullRequest {
2186
2273
  ${options?.summary ? gqlPullRequestLiteFragment : gqlPullRequestFragment}
2274
+ ${gqlPullRequestStackFragmentFor(options)}
2187
2275
  }
2188
2276
  }
2189
2277
  }
@@ -2247,8 +2335,36 @@ export class GitHubApi {
2247
2335
  throw this.handleException(ex, provider, scope, options?.silent);
2248
2336
  }
2249
2337
  }
2338
+ /**
2339
+ * The whole list rather than a page: this read has no cursor to hand back (its `IntegrationResult<T[]>` return
2340
+ * has no paging channel at all), so it drains up to {@link maxMyPullRequestSearchPages} pages itself.
2341
+ *
2342
+ * Draining instead of taking one page is what lets the full projection page at the reduced size everywhere
2343
+ * (see the `limit` in {@link searchMyPullRequestsPage}): a single page would otherwise have to ask for 100
2344
+ * nodes of the selection GitHub rejects at that size, purely because this caller cannot resume. Ordering is
2345
+ * `sort:updated`, so the pages compose into a defined window rather than a shifting relevance ranking, and the
2346
+ * drain stops as soon as GitHub reports no next page.
2347
+ */
2250
2348
  async searchMyPullRequests(provider, token, options, cancellation) {
2251
- return (await this.searchMyPullRequestsPage(provider, token, options, cancellation)).values;
2349
+ const values = [];
2350
+ // The searches behind one page can overlap (a PR can be authored by and review-requested from the same
2351
+ // user), and a later page can repeat a row an earlier one already served if the PR was updated mid-drain.
2352
+ const seen = new Set();
2353
+ let cursor;
2354
+ for (let page = 0; page < maxMyPullRequestSearchPages; page++) {
2355
+ const result = await this.searchMyPullRequestsPage(provider, token, { ...options, cursor: cursor }, cancellation);
2356
+ for (const pr of result.values) {
2357
+ if (seen.has(pr.url))
2358
+ continue;
2359
+ seen.add(pr.url);
2360
+ values.push(pr);
2361
+ }
2362
+ // A missing or repeated cursor with `hasMore` would loop on the same page forever.
2363
+ if (!result.hasMore || result.cursor == null || result.cursor === cursor)
2364
+ break;
2365
+ cursor = result.cursor;
2366
+ }
2367
+ return values;
2252
2368
  }
2253
2369
  /**
2254
2370
  * The current user's issues: authored ∪ assigned ∪ mentioned, each its own aliased search behind one composite
@@ -2431,6 +2547,64 @@ export class GitHubApi {
2431
2547
  throw this.handleException(ex, provider, scope);
2432
2548
  }
2433
2549
  }
2550
+ /**
2551
+ * The PR twin of {@link countIssues}: counts pull requests for several scopes in ONE request via aliased
2552
+ * `search` fields selecting only `issueCount` with `first: 0`. Same positional/undefined contract as the issue
2553
+ * count.
2554
+ *
2555
+ * The one difference is states. {@link toGitHubPullRequestSearchFacets} fans a scope's states out into one
2556
+ * `search` each, so this reports the count the SAME way {@link searchPullRequestsPage} reports its total — the
2557
+ * LARGEST facet's `issueCount`, not their sum: the result ceiling applies per search, so the max is what
2558
+ * `exceedsProviderLimit` compares against, and summing would claim a total the read never surfaces. Relationships
2559
+ * are OR-ed and can't be a single count; the facade refuses a multi-relationship scope, so at most one is here.
2560
+ */
2561
+ async countPullRequests(provider, token, scopes, options, cancellation) {
2562
+ const scope = getScopedLogger();
2563
+ if (scopes.length === 0)
2564
+ return [];
2565
+ // Each scope expands to one query string per state facet (all sharing its single relationship, which the
2566
+ // facade guarantees). A scope's count is the MAX across its facets — mirroring searchPullRequestsPage's
2567
+ // totalCount — so the aliases stay grouped by scope and are reduced after the response.
2568
+ const scopeQueries = scopes.map(s => {
2569
+ const scopeQualifiers = toGitHubIssueSearchScopeQualifiers(s.org, s.repos);
2570
+ return toGitHubPullRequestSearchFacets(s.criteria).map(f => [...scopeQualifiers, ...f.qualifiers].join(' '));
2571
+ });
2572
+ // Aliases are positional and generated (`s${scope}f${facet}`): a caller's key is arbitrary text and would
2573
+ // break the document, so results are reduced back to one count per scope by index.
2574
+ const aliased = scopeQueries.flatMap((queries, si) => queries.map((query, fi) => ({ alias: `s${si}f${fi}`, query: query })));
2575
+ const params = aliased.map(a => `$${a.alias}: String!`).join('\n\t\t\t\t');
2576
+ // `first: 0` is what makes this cheap — `issueCount` alone, no nodes over the wire.
2577
+ const fields = aliased
2578
+ .map(a => `${a.alias}: search(query: $${a.alias}, type: ISSUE, first: 0) { issueCount }`)
2579
+ .join('\n\t\t\t\t');
2580
+ const query = `query countPullRequests(
2581
+ ${params}
2582
+ ) {
2583
+ ${fields}
2584
+ }`;
2585
+ const variables = { baseUrl: options?.baseUrl };
2586
+ for (const a of aliased) {
2587
+ variables[a.alias] = a.query;
2588
+ }
2589
+ try {
2590
+ const rsp = await this.graphql(provider, token, query, variables, scope, cancellation);
2591
+ if (rsp == null)
2592
+ return scopes.map(() => undefined);
2593
+ return scopeQueries.map((queries, si) => {
2594
+ let max;
2595
+ for (let fi = 0; fi < queries.length; fi++) {
2596
+ const count = rsp[`s${si}f${fi}`]?.issueCount;
2597
+ if (count != null) {
2598
+ max = max == null ? count : Math.max(max, count);
2599
+ }
2600
+ }
2601
+ return max;
2602
+ });
2603
+ }
2604
+ catch (ex) {
2605
+ throw this.handleException(ex, provider, scope);
2606
+ }
2607
+ }
2434
2608
  /**
2435
2609
  * The aliased-search engine behind every GitHub issue search: one GraphQL request carrying N independently
2436
2610
  * cursored `search` fields, `@include`-gated so an exhausted or unrequested one costs nothing.
@@ -2646,8 +2820,11 @@ export class GitHubApi {
2646
2820
  * every active relationship × state facet, so one HTTP request serves one page even when the logical search is
2647
2821
  * a union. The cursor preserves each facet's continuation plus the positional page.
2648
2822
  *
2649
- * Ordering is always most-recently-updated-first, and user text is sanitized before it reaches the provider
2650
- * query. See {@link toGitHubPullRequestSearchFacets}.
2823
+ * Ordering is `criteria.sort`, defaulting to most-recently-updated-first the order this read served before it
2824
+ * was expressible. It is requested of the provider AND re-applied to the merged page, because the page is a
2825
+ * union of facets and no per-facet server order describes it. The sort is part of the cursor fingerprint, so
2826
+ * changing it invalidates a threaded cursor exactly as changing the text or the scope does. User text is
2827
+ * sanitized before it reaches the provider query. See {@link toGitHubPullRequestSearchFacets}.
2651
2828
  */
2652
2829
  async searchPullRequestsPage(provider, token, options, cancellation) {
2653
2830
  const scope = getScopedLogger();
@@ -2723,6 +2900,7 @@ export class GitHubApi {
2723
2900
  nodes {
2724
2901
  ... on PullRequest {
2725
2902
  ${gqlPullRequestFragment}
2903
+ ${gqlPullRequestStackFragmentFor(options)}
2726
2904
  }
2727
2905
  }
2728
2906
  }`);
@@ -2758,7 +2936,15 @@ export class GitHubApi {
2758
2936
  }
2759
2937
  }
2760
2938
  }
2761
- pullRequests.sort((a, b) => b.updatedDate.getTime() - a.updatedDate.getTime());
2939
+ // The PR path re-sorts the merged page rather than trusting the per-facet server order — GitHub's
2940
+ // server-side PR sort has been unreliable (the per-branch path re-sorts for the same reason), and the
2941
+ // union of several facets is unordered regardless. The key was validated against
2942
+ // `githubPullRequestSearchCapabilities.sorts` upstream, so its comparator is always defined for a PR
2943
+ // shape; the guard only guards the unreachable case rather than inventing an order for it.
2944
+ const comparator = getPullRequestComparator(options?.criteria?.sort ?? defaultPullRequestSort);
2945
+ if (comparator != null) {
2946
+ pullRequests.sort(comparator);
2947
+ }
2762
2948
  const values = [
2763
2949
  ...uniqueBy(pullRequests, pr => pr.url, (original, _current) => original),
2764
2950
  ];
@@ -2826,6 +3012,7 @@ export class GitHubApi {
2826
3012
  nodes {
2827
3013
  ...on PullRequest {
2828
3014
  ${gqlPullRequestFragment}
3015
+ ${gqlPullRequestStackFragmentFor(options)}
2829
3016
  }
2830
3017
  }
2831
3018
  }
@@ -2868,6 +3055,98 @@ export class GitHubApi {
2868
3055
  throw this.handleException(ex, provider, scope);
2869
3056
  }
2870
3057
  }
3058
+ /**
3059
+ * Every stack in the repository, each with its members bottom to top.
3060
+ *
3061
+ * One request regardless of how many pull requests are involved — which is what makes it the right
3062
+ * shape for list surfaces, whose pull requests arrive through the shared providers API and so carry no
3063
+ * stack membership of their own. Callers join the result by pull request number.
3064
+ *
3065
+ * A `404` means the repository isn't enrolled in the stacked-pull-requests preview; that's reported as
3066
+ * `undefined` rather than an error, since "no stacks" and "not available" both mean nothing to show.
3067
+ */
3068
+ async getRepositoryStacks(provider, token, owner, repo, options, cancellation) {
3069
+ const scope = getScopedLogger();
3070
+ try {
3071
+ const rsp = await this.requestPreview(provider, token, 'GET /repos/{owner}/{repo}/stacks', { owner: owner, repo: repo, baseUrl: options?.baseUrl }, scope, cancellation);
3072
+ return rsp.data;
3073
+ }
3074
+ catch (ex) {
3075
+ if (isCancellationError(ex))
3076
+ throw ex;
3077
+ Logger.warn(scope, `Unable to list stacks for ${owner}/${repo}: ${ex}`);
3078
+ return undefined;
3079
+ }
3080
+ }
3081
+ /**
3082
+ * Merges a stacked pull request, and with it every layer below it.
3083
+ *
3084
+ * Stacks cannot go through `mergePullRequest` — GitHub rejects stacked pull requests on the legacy
3085
+ * synchronous merge endpoints and mutations. The replacement is asynchronous: submit, then poll a
3086
+ * ticket until it reaches a terminal state.
3087
+ */
3088
+ async mergeStackedPullRequest(provider, token, owner, repo, pullNumber, expectedSourceSha, options, cancellation) {
3089
+ const scope = getScopedLogger();
3090
+ try {
3091
+ let uuid;
3092
+ try {
3093
+ const submitted = await this.requestPreview(provider, token, 'PUT /repos/{owner}/{repo}/pulls/{pull_number}/merge-async', {
3094
+ owner: owner,
3095
+ repo: repo,
3096
+ pull_number: pullNumber,
3097
+ sha: expectedSourceSha,
3098
+ merge_method: options?.mergeMethod,
3099
+ baseUrl: options?.baseUrl,
3100
+ }, scope, cancellation);
3101
+ // Already merged or rejected outright — nothing to poll for. `enqueued` lands via the merge
3102
+ // queue, which can take several merge groups to settle, so it's transitional like `pending`.
3103
+ if (submitted.data.status !== 'pending' && submitted.data.status !== 'enqueued') {
3104
+ if (submitted.data.status === 'failed') {
3105
+ Logger.warn(scope, `Stacked merge refused: ${submitted.data.details?.message ?? 'no reason given'}`);
3106
+ }
3107
+ return submitted.data.status === 'merged';
3108
+ }
3109
+ uuid = submitted.data.details?.uuid;
3110
+ }
3111
+ catch (ex) {
3112
+ // A merge request is already in flight (a retry, or a double-click) — adopt its ticket and
3113
+ // poll that instead of reporting a failure for a merge that is actually running.
3114
+ uuid = getAsyncMergeUuidFromConflict(ex);
3115
+ if (uuid == null)
3116
+ throw ex;
3117
+ }
3118
+ if (uuid == null)
3119
+ return false;
3120
+ // The stack merges server-side one layer at a time, so this can take a while. Poll on a
3121
+ // fixed interval and give up rather than hang forever if the ticket never settles.
3122
+ for (let attempt = 0; attempt < maxAsyncMergePolls; attempt++) {
3123
+ if (cancellation?.aborted)
3124
+ throw new CancellationError();
3125
+ await new Promise(resolve => setTimeout(resolve, asyncMergePollIntervalMs));
3126
+ const polled = await this.requestPreview(provider, token, 'GET /repos/{owner}/{repo}/pulls/{pull_number}/merge-async/{uuid}', {
3127
+ owner: owner,
3128
+ repo: repo,
3129
+ pull_number: pullNumber,
3130
+ uuid: uuid,
3131
+ baseUrl: options?.baseUrl,
3132
+ }, scope, cancellation);
3133
+ if (polled.data.status === 'pending' || polled.data.status === 'enqueued')
3134
+ continue;
3135
+ if (polled.data.status === 'failed') {
3136
+ Logger.warn(scope, `Stacked merge failed: ${polled.data.details?.message ?? 'no reason given'}`);
3137
+ }
3138
+ return polled.data.status === 'merged';
3139
+ }
3140
+ Logger.warn(scope, `Timed out waiting for stacked merge of ${owner}/${repo}#${pullNumber}`);
3141
+ return false;
3142
+ }
3143
+ catch (ex) {
3144
+ if (isCancellationError(ex))
3145
+ throw ex;
3146
+ Logger.error(ex, scope);
3147
+ throw this.handleException(ex, provider, scope);
3148
+ }
3149
+ }
2871
3150
  async mergePullRequest(provider, token, nodeId, expectedSourceSha, options, cancellation) {
2872
3151
  const scope = getScopedLogger();
2873
3152
  let githubMergeStrategy;
@@ -2903,7 +3182,7 @@ export class GitHubApi {
2903
3182
  mergeMethod: githubMergeStrategy,
2904
3183
  baseUrl: options?.baseUrl,
2905
3184
  }, scope, cancellation);
2906
- return rsp?.pullRequest?.id === nodeId;
3185
+ return rsp?.mergePullRequest?.pullRequest?.id === nodeId;
2907
3186
  }
2908
3187
  catch (ex) {
2909
3188
  throw this.handleException(ex, provider, scope);
@@ -3205,12 +3484,37 @@ __decorate([
3205
3484
  __decorate([
3206
3485
  trace({ args: (provider, token) => ({ provider: provider.name, token: `<token:${token.microHash}>` }) })
3207
3486
  ], GitHubApi.prototype, "countIssues", null);
3487
+ __decorate([
3488
+ trace({ args: (provider, token) => ({ provider: provider.name, token: `<token:${token.microHash}>` }) })
3489
+ ], GitHubApi.prototype, "countPullRequests", null);
3208
3490
  __decorate([
3209
3491
  trace({ args: (provider, token) => ({ provider: provider.name, token: `<token:${token.microHash}>` }) })
3210
3492
  ], GitHubApi.prototype, "searchPullRequestsPage", null);
3211
3493
  __decorate([
3212
3494
  trace({ args: (provider, token) => ({ provider: provider.name, token: `<token:${token.microHash}>` }) })
3213
3495
  ], GitHubApi.prototype, "searchPullRequests", null);
3496
+ __decorate([
3497
+ trace({
3498
+ args: (provider, token, owner, repo) => ({
3499
+ provider: provider.name,
3500
+ token: `<token:${token.microHash}>`,
3501
+ owner: owner,
3502
+ repo: repo,
3503
+ }),
3504
+ })
3505
+ ], GitHubApi.prototype, "getRepositoryStacks", null);
3506
+ __decorate([
3507
+ trace({
3508
+ args: (provider, token, owner, repo, pullNumber, expectedSourceSha) => ({
3509
+ provider: provider.name,
3510
+ token: `<token:${token.microHash}>`,
3511
+ owner: owner,
3512
+ repo: repo,
3513
+ pullNumber: pullNumber,
3514
+ expectedSourceSha: expectedSourceSha,
3515
+ }),
3516
+ })
3517
+ ], GitHubApi.prototype, "mergeStackedPullRequest", null);
3214
3518
  __decorate([
3215
3519
  trace({
3216
3520
  args: (provider, token, nodeId, expectedSourceSha) => ({