@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
@@ -1,6 +1,10 @@
1
- import type { PullRequestSearchCriteria, PullRequestStateFilter } from '../../../git/models/pullRequest.js';
2
- import { PullRequestFilter } from '../../../git/models/pullRequest.js';
3
- import { sanitizeGitHubSearchText } from './issueSearchQuery.js';
1
+ import type {
2
+ PullRequestSearchCriteria,
3
+ PullRequestSorting,
4
+ PullRequestStateFilter,
5
+ } from '../../../git/models/pullRequest.js';
6
+ import { defaultPullRequestSort, PullRequestFilter } from '../../../git/models/pullRequest.js';
7
+ import { sanitizeGitHubQualifierValue, sanitizeGitHubSearchText } from './issueSearchQuery.js';
4
8
 
5
9
  export type GitHubPullRequestSearchFacet = {
6
10
  /** Stable GraphQL alias and composite-cursor key. */
@@ -8,10 +12,20 @@ export type GitHubPullRequestSearchFacet = {
8
12
  qualifiers: string[];
9
13
  };
10
14
 
11
- const relationshipQualifier: Record<PullRequestFilter, string> = {
15
+ /**
16
+ * The GitHub search qualifier each relationship translates to. Exhaustive over `PullRequestFilter` so a new
17
+ * member can't be silently unmapped.
18
+ *
19
+ * Exported because the account-wide read builds its own facets from the same vocabulary (see
20
+ * `GitHubIntegrationBase.getProviderMyPullRequestsForUser`). Kept as ONE declaration rather than a copy per
21
+ * caller: the exhaustive `Record` makes a missing key a compile error, but nothing would catch two copies
22
+ * disagreeing on a qualifier STRING, and a wrong qualifier is a read that quietly answers a different question.
23
+ */
24
+ export const gitHubPullRequestRelationshipQualifiers: Record<PullRequestFilter, string> = {
12
25
  [PullRequestFilter.Author]: 'author:@me',
13
26
  [PullRequestFilter.Assignee]: 'assignee:@me',
14
27
  [PullRequestFilter.ReviewRequested]: 'review-requested:@me',
28
+ [PullRequestFilter.Reviewed]: 'reviewed-by:@me',
15
29
  [PullRequestFilter.Mention]: 'mentions:@me',
16
30
  };
17
31
 
@@ -19,6 +33,7 @@ const relationshipAlias: Record<PullRequestFilter, string> = {
19
33
  [PullRequestFilter.Author]: 'author',
20
34
  [PullRequestFilter.Assignee]: 'assignee',
21
35
  [PullRequestFilter.ReviewRequested]: 'reviewRequested',
36
+ [PullRequestFilter.Reviewed]: 'reviewed',
22
37
  [PullRequestFilter.Mention]: 'mention',
23
38
  };
24
39
 
@@ -29,6 +44,30 @@ const stateAlias: Record<PullRequestStateFilter, string> = {
29
44
  all: 'All',
30
45
  };
31
46
 
47
+ /**
48
+ * How each orderable key becomes a GitHub `sort:` qualifier.
49
+ *
50
+ * A literal `Record` over the union rather than a derived transform, for the same reason the relationship tables
51
+ * are: adding a sort field without deciding its qualifier fails the build instead of quietly emitting a search
52
+ * with no ordering constraint — the one failure mode the ordering contract exists to prevent, and the one a
53
+ * caller cannot detect from the result.
54
+ *
55
+ * `updated:desc` maps to the bare `sort:updated`, not `sort:updated-desc`. The two are the same query to GitHub,
56
+ * but the bare form is what this read has always emitted, so keeping it makes the default byte-identical to
57
+ * today's query — matching `toGitHubIssueSortQualifier`. Do not "normalize" it.
58
+ */
59
+ export const gitHubPullRequestSortQualifiers: Partial<Record<PullRequestSorting, string>> = {
60
+ 'created:asc': 'sort:created-asc',
61
+ 'created:desc': 'sort:created-desc',
62
+ 'updated:asc': 'sort:updated-asc',
63
+ 'updated:desc': 'sort:updated',
64
+ };
65
+
66
+ /** The `sort:` qualifier for a key, or `undefined` when there is no key or GitHub can't express it. */
67
+ export function toGitHubPullRequestSortQualifier(sort: PullRequestSorting | undefined): string | undefined {
68
+ return sort != null ? gitHubPullRequestSortQualifiers[sort] : undefined;
69
+ }
70
+
32
71
  function stateQualifiers(state: PullRequestStateFilter): string[] {
33
72
  switch (state) {
34
73
  case 'closed':
@@ -62,18 +101,53 @@ export function toGitHubPullRequestSearchFacets(
62
101
  : ['open'];
63
102
  const states: PullRequestStateFilter[] = requestedStates.includes('all') ? ['all'] : requestedStates;
64
103
  const text = criteria?.text != null ? sanitizeGitHubSearchText(criteria.text) : '';
104
+ // Ordering is part of the contract, not an option: without an explicit `sort:` GitHub answers in relevance
105
+ // order, so which rows land inside the result ceiling would shift with its ranking even when nothing changed
106
+ // upstream. A key GitHub can't express is REFUSED here, not approximated with a fallback order — a silent
107
+ // `sort:updated` substitute would emit one order in the query while the merged-page comparator applied another
108
+ // (or none for an unknown field), which is exactly the "the N most recent are what you get" promise the ceiling
109
+ // contract cannot keep under a guessed order. Unreachable through the facade — every key is validated against
110
+ // `githubPullRequestSearchCapabilities.sorts` first — so this guards the direct callers of this exported builder
111
+ // and of `GitHubApi.searchPullRequestsPage`.
112
+ //
113
+ // Deliberately STRICTER than the issue path, which drops an inexpressible qualifier and searches on
114
+ // (`toGitHubIssueSearchQualifiers` pushes `toGitHubIssueSortQualifier`'s result only when it is non-null). The
115
+ // two reads differ in what that costs: an issue search is served by whichever facets the provider ordered, while
116
+ // this one hands its merged page to `getPullRequestComparator`, so a dropped qualifier here means the query and
117
+ // the comparator disagree about the order the ceiling was applied under. Refusing is the only answer that
118
+ // cannot lie about which rows were reachable.
119
+ const sort = criteria?.sort ?? defaultPullRequestSort;
120
+ const sortQualifier = toGitHubPullRequestSortQualifier(sort);
121
+ if (sortQualifier == null) {
122
+ throw new Error(`GitHub cannot order a pull request search by '${sort}'`);
123
+ }
124
+
125
+ // Facet-independent, unlike the relationship/state qualifiers below — build once and share.
126
+ const dateQualifiers: string[] = [];
127
+ const pushDate = (value: string | undefined, toQualifier: (sanitized: string) => string): void => {
128
+ if (value == null) return;
129
+
130
+ const sanitized = sanitizeGitHubQualifierValue(value);
131
+ if (sanitized.length > 0) {
132
+ dateQualifiers.push(toQualifier(sanitized));
133
+ }
134
+ };
135
+ pushDate(criteria?.updatedAfter, v => `updated:>=${v}`);
136
+ pushDate(criteria?.createdAfter, v => `created:>=${v}`);
65
137
 
66
138
  return relationships.flatMap(relationship =>
67
139
  states.map(state => ({
68
140
  alias: `${relationship != null ? relationshipAlias[relationship] : 'scope'}${stateAlias[state]}`,
69
141
  qualifiers: [
70
142
  'is:pr',
71
- ...(relationship != null ? [relationshipQualifier[relationship]] : []),
143
+ ...(relationship != null ? [gitHubPullRequestRelationshipQualifiers[relationship]] : []),
72
144
  ...stateQualifiers(state),
145
+ // `!= null`, not truthy: `draft:false` narrows to ready-for-review PRs just as `draft:true` narrows to drafts.
146
+ ...(criteria?.draft != null ? [`draft:${criteria.draft}`] : []),
73
147
  ...(criteria?.includeArchived === true ? [] : ['archived:false']),
74
148
  ...(text.length > 0 ? [text] : []),
75
- // Contract, not an option: a capped result is the N most recently updated only under this order.
76
- 'sort:updated',
149
+ ...dateQualifiers,
150
+ sortQualifier,
77
151
  ],
78
152
  })),
79
153
  );
@@ -2,7 +2,7 @@ import type { Endpoints } from '@octokit/types';
2
2
  import { GitFileIndexStatus } from '../../git/models/fileStatus.js';
3
3
  import type { IssueLabel } from '../../git/models/issue.js';
4
4
  import { Issue, RepositoryAccessLevel } from '../../git/models/issue.js';
5
- import type { PullRequestMember, PullRequestState } from '../../git/models/pullRequest.js';
5
+ import type { PullRequestMember, PullRequestStackInfo, PullRequestState } from '../../git/models/pullRequest.js';
6
6
  import {
7
7
  PullRequest,
8
8
  PullRequestMergeableState,
@@ -165,6 +165,20 @@ export interface GitHubPullRequestLite extends Omit<GitHubIssueOrPullRequest, '_
165
165
  url: string;
166
166
  viewerPermission: GitHubViewerPermission;
167
167
  };
168
+
169
+ /** Only selected against github.com — GitHub Enterprise Server schemas lag and reject the field. */
170
+ stack?: GitHubPullRequestStack | null;
171
+ /** Only selected against github.com — see `stack`. */
172
+ stackEntry?: { position: number } | null;
173
+ }
174
+
175
+ /** GitHub's stacked-pull-request object. Read-only; all stack mutations are REST-only. */
176
+ export interface GitHubPullRequestStack {
177
+ id: string;
178
+ number: number;
179
+ size: number;
180
+ /** The branch the bottom of the stack targets — the stack's trunk. */
181
+ baseRefName: string;
168
182
  }
169
183
 
170
184
  export interface GitHubIssue extends Omit<GitHubIssueOrPullRequest, '__typename'> {
@@ -194,21 +208,32 @@ export type GitHubPullRequestMergeableState = 'MERGEABLE' | 'CONFLICTING' | 'UNK
194
208
  export type GitHubPullRequestStatusCheckRollupState = 'SUCCESS' | 'FAILURE' | 'PENDING' | 'EXPECTED' | 'ERROR';
195
209
  export type GitHubPullRequestReviewState = 'APPROVED' | 'CHANGES_REQUESTED' | 'COMMENTED' | 'DISMISSED' | 'PENDING';
196
210
 
211
+ type GitHubPullRequestReview = {
212
+ id: string;
213
+ author: GitHubMember | null;
214
+ state: GitHubPullRequestReviewState;
215
+ commit?: { oid: string } | null;
216
+ };
217
+
197
218
  export interface GitHubPullRequest extends GitHubPullRequestLite {
198
219
  additions: number;
199
220
  assignees: {
200
221
  nodes: GitHubMember[];
201
222
  };
223
+ changedFiles: number;
202
224
  checksUrl: string;
203
225
  deletions: number;
204
226
  mergeable: GitHubPullRequestMergeableState;
205
227
  reviewDecision: GitHubPullRequestReviewDecision;
206
228
  latestReviews: {
207
- nodes: {
208
- author: GitHubMember | null;
209
- state: GitHubPullRequestReviewState;
210
- }[];
229
+ nodes: GitHubPullRequestReview[];
211
230
  };
231
+ /**
232
+ * The current user's own latest review. `latestReviews` is capped, so on a heavily-reviewed pull request
233
+ * the viewer's own review can fall outside that window — which is exactly the row a "needs my review"
234
+ * surface is asking about.
235
+ */
236
+ viewerLatestReview: GitHubPullRequestReview | null;
212
237
  reviewRequests: {
213
238
  nodes: {
214
239
  asCodeOwner: boolean;
@@ -216,6 +241,7 @@ export interface GitHubPullRequest extends GitHubPullRequestLite {
216
241
  }[];
217
242
  };
218
243
  commits: {
244
+ totalCount: number;
219
245
  nodes: {
220
246
  commit: {
221
247
  statusCheckRollup: {
@@ -240,7 +266,13 @@ export type GitHubViewerPermission =
240
266
  function fromGitHubMemberOrGhost(member: GitHubMember | null | undefined): PullRequestMember {
241
267
  if (member == null) return { id: 'ghost', name: 'ghost' };
242
268
 
243
- return { id: member.login, name: member.login, avatarUrl: member.avatarUrl, url: member.url };
269
+ return {
270
+ id: member.login,
271
+ name: member.login,
272
+ username: member.login,
273
+ avatarUrl: member.avatarUrl,
274
+ url: member.url,
275
+ };
244
276
  }
245
277
 
246
278
  export function fromGitHubPullRequestLite(pr: GitHubPullRequestLite, provider: Provider): PullRequest {
@@ -289,6 +321,7 @@ export function fromGitHubPullRequestLite(pr: GitHubPullRequestLite, provider: P
289
321
  isCrossRepository: pr.isCrossRepository,
290
322
  },
291
323
  pr.isDraft,
324
+ // The lite fragment selects nothing between `isDraft` and `stack`.
292
325
  undefined, // additions
293
326
  undefined, // deletions
294
327
  undefined, // commentsCount
@@ -300,10 +333,26 @@ export function fromGitHubPullRequestLite(pr: GitHubPullRequestLite, provider: P
300
333
  undefined, // statusCheckRollupState
301
334
  undefined, // project
302
335
  undefined, // version
336
+ undefined, // commitCount
337
+ fromGitHubPullRequestStack(pr),
338
+ undefined, // filesChanged
303
339
  pr.body ?? undefined,
304
340
  );
305
341
  }
306
342
 
343
+ /** Both fields are absent on GitHub Enterprise Server (never selected) and `null` when unstacked. */
344
+ function fromGitHubPullRequestStack(pr: GitHubPullRequestLite): PullRequestStackInfo | undefined {
345
+ if (pr.stack == null || pr.stackEntry == null) return undefined;
346
+
347
+ return {
348
+ id: pr.stack.id,
349
+ number: pr.stack.number,
350
+ size: pr.stack.size,
351
+ position: pr.stackEntry.position,
352
+ baseRef: pr.stack.baseRefName,
353
+ };
354
+ }
355
+
307
356
  export function fromGitHubIssueOrPullRequestState(state: GitHubPullRequestState): PullRequestState {
308
357
  return state === 'MERGED' ? 'merged' : state === 'CLOSED' ? 'closed' : 'opened';
309
358
  }
@@ -401,6 +450,19 @@ export function fromGitHubPullRequestStatusCheckRollupState(
401
450
  }
402
451
 
403
452
  export function fromGitHubPullRequest(pr: GitHubPullRequest, provider: Provider): PullRequest {
453
+ // `latestReviews` is capped, so keep the viewer's own review even when it falls outside that window, deduped
454
+ // by review id since the two selections overlap. Unsubmitted drafts are dropped from the union rather than
455
+ // from the viewer's side alone: `PENDING` is in GitHub's review-state enum on both selections, and the field
456
+ // this feeds is documented as reviews already SUBMITTED — a draft there tells a "needs my review" consumer
457
+ // the review is done, and a reviewer with a submitted review plus a draft would get two conflicting rows.
458
+ const viewerLatestReview = pr.viewerLatestReview;
459
+ const latestReviews = [
460
+ ...pr.latestReviews.nodes,
461
+ ...(viewerLatestReview != null && !pr.latestReviews.nodes.some(r => r.id === viewerLatestReview.id)
462
+ ? [viewerLatestReview]
463
+ : []),
464
+ ].filter(review => review.state !== 'PENDING');
465
+
404
466
  return new PullRequest(
405
467
  provider,
406
468
  fromGitHubMemberOrGhost(pr.author),
@@ -459,6 +521,7 @@ export function fromGitHubPullRequest(pr: GitHubPullRequest, provider: Provider)
459
521
  reviewer: {
460
522
  id: r.requestedReviewer.login,
461
523
  name: r.requestedReviewer.login,
524
+ username: r.requestedReviewer.login,
462
525
  avatarUrl: r.requestedReviewer.avatarUrl,
463
526
  url: r.requestedReviewer.url,
464
527
  },
@@ -467,19 +530,24 @@ export function fromGitHubPullRequest(pr: GitHubPullRequest, provider: Provider)
467
530
  : undefined,
468
531
  )
469
532
  .filter(<T>(r?: T): r is T => Boolean(r)),
470
- pr.latestReviews.nodes.map(r => ({
533
+ latestReviews.map(r => ({
471
534
  reviewer: fromGitHubMemberOrGhost(r.author),
472
535
  state: fromGitHubPullRequestReviewState(r.state),
536
+ commitOid: r.commit?.oid,
473
537
  })),
474
538
  pr.assignees.nodes.map(r => ({
475
539
  id: r.login,
476
540
  name: r.login,
541
+ username: r.login,
477
542
  avatarUrl: r.avatarUrl,
478
543
  url: r.url,
479
544
  })),
480
545
  fromGitHubPullRequestStatusCheckRollupState(pr.commits.nodes?.[0]?.commit.statusCheckRollup?.state),
481
546
  undefined, // project
482
547
  undefined, // version
548
+ pr.commits.totalCount,
549
+ fromGitHubPullRequestStack(pr),
550
+ pr.changedFiles,
483
551
  pr.body ?? undefined,
484
552
  );
485
553
  }
@@ -505,12 +573,14 @@ export function fromGitHubIssue(value: GitHubIssue, provider: Provider): Issue {
505
573
  : {
506
574
  id: value.author.login,
507
575
  name: value.author.login,
576
+ username: value.author.login,
508
577
  avatarUrl: value.author.avatarUrl,
509
578
  url: value.author.url,
510
579
  },
511
580
  value.assignees.nodes.map(assignee => ({
512
581
  id: assignee.login,
513
582
  name: assignee.login,
583
+ username: assignee.login,
514
584
  avatarUrl: assignee.avatarUrl,
515
585
  url: assignee.url,
516
586
  })),
@@ -44,6 +44,7 @@ export class StatusGitSubProvider implements GitStatusSubProvider {
44
44
  unstaged?: boolean;
45
45
  untracked?: boolean;
46
46
  throwOnError?: boolean;
47
+ priority?: GitCommandPriority;
47
48
  },
48
49
  _cancellation?: AbortSignal,
49
50
  ): Promise<boolean> {
@@ -155,6 +155,10 @@ export interface IntegrationCacheProvider {
155
155
  cacheable: Cacheable<Account>,
156
156
  options?: CacheExpiryOptions & { connectionId?: string; etag?: string },
157
157
  ): CacheResult<Account>;
158
+ /** Evicts every cached pull request. A merge invalidates more than the merged pull request alone —
159
+ * a stacked merge lands every layer below it and retargets every layer above — and no caller can
160
+ * name that full set. */
161
+ deletePullRequests(): void;
158
162
  }
159
163
 
160
164
  /**
@@ -73,6 +73,8 @@ const uncachedIntegrationCacheProvider: IntegrationCacheProvider = {
73
73
  getIssueOrPullRequest: (_id, _type, _resource, _integration, loader) => loadUncached(loader),
74
74
  getIssue: (_id, _resource, _integration, loader) => loadUncached(loader),
75
75
  getCurrentAccount: (_integration, loader) => loadUncached(loader),
76
+ // Nothing is cached, so there is nothing to evict.
77
+ deletePullRequests: () => {},
76
78
  };
77
79
 
78
80
  function toIntegrationCacheProvider(cache: IntegrationManagerCacheProvider | undefined): IntegrationCacheProvider {
@@ -77,8 +77,13 @@ import { providersMetadata } from './providers/models.js';
77
77
  import type { ProvidersApi } from './providers/providersApi.js';
78
78
  import { broadenIssues } from './reads/broaden.js';
79
79
  import type { RepositoryResolutionContext } from './reads/context.js';
80
- import type { IssueCountResult, IssueCountScope } from './reads/counts.js';
81
- import { countIssues } from './reads/counts.js';
80
+ import type {
81
+ IssueCountResult,
82
+ IssueCountScope,
83
+ PullRequestCountResult,
84
+ PullRequestCountScope,
85
+ } from './reads/counts.js';
86
+ import { countIssues, countPullRequests } from './reads/counts.js';
82
87
  import type { SupportedFilters } from './reads/filters.js';
83
88
  import { getSupportedFilters } from './reads/filters.js';
84
89
  import { listOrgs, listProjects, listRepos } from './reads/hierarchy.js';
@@ -1147,6 +1152,24 @@ export class IntegrationService implements Disposable, RepositoryResolutionConte
1147
1152
  return countIssues(this, options);
1148
1153
  }
1149
1154
 
1155
+ /**
1156
+ * How many pull requests match each scope, without fetching any — the PR twin of {@link countIssues}. See
1157
+ * {@link IntegrationManager.countPullRequests} for the cost model, the per-scope isolation rules, and why
1158
+ * `count: undefined` must not be rendered as zero.
1159
+ */
1160
+ async countPullRequests(options: {
1161
+ providerId: IntegrationIds;
1162
+ scopes: readonly PullRequestCountScope[];
1163
+ connectionId?: string;
1164
+ /**
1165
+ * Explicit self-managed host domain. Used only when the requested connection has no configured domain;
1166
+ * it must come from the trusted authentication configuration, not repository or remote data.
1167
+ */
1168
+ domain?: string;
1169
+ }): Promise<ProviderResult<PullRequestCountResult>> {
1170
+ return countPullRequests(this, options);
1171
+ }
1172
+
1150
1173
  /**
1151
1174
  * Reads the user's issues from an issue-tracker provider (Jira/Linear/Trello), whose issues live under
1152
1175
  * resource → project (not repos), so they can't go through {@link listIssuesPage} (git-host, repo-scoped).
@@ -9,7 +9,12 @@ import type { ConfiguredIntegrationsChangeEvent } from './authentication/configu
9
9
  import type { ConfiguredIntegrationDescriptor } from './authentication/models.js';
10
10
  import type { IntegrationIds } from './constants.js';
11
11
  import type { IssueFilter, IssueSorting, PullRequestFilter } from './providerFilters.js';
12
- import type { IssueCountResult, IssueCountScope } from './reads/counts.js';
12
+ import type {
13
+ IssueCountResult,
14
+ IssueCountScope,
15
+ PullRequestCountResult,
16
+ PullRequestCountScope,
17
+ } from './reads/counts.js';
13
18
  import type { SupportedFilters } from './reads/filters.js';
14
19
  import type {
15
20
  ConnectionStateChangeEvent,
@@ -156,6 +161,22 @@ type PullRequestSweepCommonOptions = {
156
161
  * This extends the provider-native result; it is not a narrowing filter.
157
162
  */
158
163
  includeReviewRequested?: boolean;
164
+ /**
165
+ * Account-wide only: fetch the full PR projection (review decision, review requests, latest reviews)
166
+ * instead of the default summary/lite one. Opt-in because it enlarges every account-wide page; callers
167
+ * that classify by review state (e.g. a "needs my review" surface) set it, others keep the lean read.
168
+ *
169
+ * GitHub/GHE only today — no other provider's account-wide read has a projection switch, so they return
170
+ * their native shape regardless. A cross-provider sweep therefore gets reviews from GitHub targets and
171
+ * whatever the others natively carry; it is a breadth request, not a guarantee, so it does not refuse
172
+ * (unlike `filters`, where dropping a member would change the requested set).
173
+ *
174
+ * Projection only: it cannot change which pull requests come back. Every GitHub account-wide read goes through
175
+ * the same search whether or not it is set, so the Launchpad ignored-repository and organization qualifiers
176
+ * (and the per-facet result ceiling) apply the same either way. What it costs is the reduced page size, and a
177
+ * document whose weight scales with the number of relationship × state facets in flight.
178
+ */
179
+ includeReviews?: boolean;
159
180
  forceSync?: boolean;
160
181
  maxPages?: number;
161
182
  /**
@@ -355,10 +376,17 @@ export interface IntegrationManager {
355
376
  * GitHub's mismatched `involves:@me`. Omit relationships only with a repository/organization scope to search
356
377
  * every PR there.
357
378
  *
358
- * Results are always ordered most-recently-updated-first. If the provider's result ceiling is reached, the
359
- * request still succeeds and carries a warning omission with `totalCount`, `limit`, and `recovery: 'none'`.
360
- * `totalCount` is the largest provider-reported pre-ceiling facet count, not the reachable or returned row
361
- * count; this mirrors the per-search ceiling's own unit.
379
+ * **Ordering is `criteria.sort`**, most-recently-updated-first when omitted. It is validated like every other
380
+ * criterion a key not in `getSupportedFilters().pullRequestSearch.sorts` refuses the whole read rather than
381
+ * falling back, because at a bounded result window another order reaches another subset. The page is a union of
382
+ * the provider's relationship × state facets, so it is re-ordered as a whole rather than served as concatenated
383
+ * per-facet runs. Changing the sort invalidates a threaded cursor (it is part of the cursor's fingerprint,
384
+ * alongside the text and the scope); drop the cursor when you change the order.
385
+ *
386
+ * If the provider's result ceiling is reached, the request still succeeds and carries a warning omission with
387
+ * `totalCount`, `limit`, `sort`, and `recovery: 'none'`. `totalCount` is the largest provider-reported
388
+ * pre-ceiling facet count, not the reachable or returned row count; this mirrors the per-search ceiling's own
389
+ * unit.
362
390
  *
363
391
  * Check `getSupportedFilters().pullRequestSearch` before calling. A provider that reports no relationships
364
392
  * refuses the read rather than returning a page that never honored the criteria or scope.
@@ -518,6 +546,23 @@ export interface IntegrationManager {
518
546
  /** Self-managed host domain fallback; see {@link ProviderSweepTarget.domain}. */
519
547
  domain?: string;
520
548
  }): Promise<ProviderResult<IssueCountResult>>;
549
+ /**
550
+ * How many pull requests match each scope, fetching none of them — the PR twin of {@link countIssues}, behind a
551
+ * "this will fetch ~N pull requests" preview and a live count next to an unapplied filter. Same cost model,
552
+ * per-scope isolation, `key`-echo, and `count: undefined` ≠ zero rule as the issue count; GitHub/GHE only.
553
+ *
554
+ * The one PR-specific difference: a scope's `states` are counted as independent searches, so the reported count
555
+ * is the LARGEST of them (the same total {@link searchPullRequestsPage} surfaces), not their sum. Several states
556
+ * in one scope are therefore fine; only several relationships are refused — one relationship per scope, see
557
+ * {@link PullRequestCountScope}.
558
+ */
559
+ countPullRequests(options: {
560
+ providerId: IntegrationIds;
561
+ scopes: readonly PullRequestCountScope[];
562
+ connectionId?: string;
563
+ /** Self-managed host domain fallback; see {@link ProviderSweepTarget.domain}. */
564
+ domain?: string;
565
+ }): Promise<ProviderResult<PullRequestCountResult>>;
521
566
  /** Issue trackers are cloud-only, so this read takes no `domain`. */
522
567
  listIssueTrackerIssuesPage(options: {
523
568
  providerId: IntegrationIds;
@@ -7,11 +7,13 @@ import type {
7
7
  PullRequest,
8
8
  PullRequestMergeMethod,
9
9
  PullRequestSearchCriteria,
10
+ PullRequestStackInfo,
10
11
  PullRequestStateFilter,
11
12
  } from '../../../git/models/pullRequest.js';
12
13
  import type { RepositoryMetadata } from '../../../git/models/repositoryMetadata.js';
13
14
  import type { ResourceDescriptor } from '../../../git/models/resourceDescriptor.js';
14
15
  import type { PullRequestUrlIdentity } from '../../../git/utils/pullRequest.utils.js';
16
+ import { isCancellationError } from '../../../utils/cancellation.js';
15
17
  import { gate } from '../../../utils/decorators/gate.js';
16
18
  import { trace } from '../../../utils/decorators/log.js';
17
19
  import { first } from '../../../utils/iterable.js';
@@ -267,6 +269,14 @@ export abstract class GitHostIntegration<
267
269
  connectionId?: string;
268
270
  }): Promise<ProviderRepository | undefined>;
269
271
 
272
+ /** Stack membership for every stacked pull request in the repository, keyed by pull request number.
273
+ * Only hosts with a stacks concept implement this (currently GitHub). */
274
+ getStacksByPullRequestNumber?(
275
+ owner: string,
276
+ repo: string,
277
+ cancellation?: AbortSignal,
278
+ ): Promise<Map<number, PullRequestStackInfo> | undefined>;
279
+
270
280
  protected abstract getProviderDefaultBranch(
271
281
  { accessToken }: ProviderAuthenticationSession,
272
282
  repo: T,
@@ -514,7 +524,11 @@ export abstract class GitHostIntegration<
514
524
  options?: { cursor?: string },
515
525
  ): Promise<ProviderHierarchyResult<ProviderRepository> | undefined>;
516
526
 
517
- async mergePullRequest(pr: PullRequest, options?: { mergeMethod?: PullRequestMergeMethod }): Promise<boolean> {
527
+ async mergePullRequest(
528
+ pr: PullRequest,
529
+ options?: { mergeMethod?: PullRequestMergeMethod },
530
+ cancellation?: AbortSignal,
531
+ ): Promise<boolean> {
518
532
  const scope = getScopedLogger();
519
533
 
520
534
  const connected = this.maybeConnected ?? (await this.isConnected());
@@ -523,12 +537,20 @@ export abstract class GitHostIntegration<
523
537
  await this.refreshSessionIfExpired(scope);
524
538
 
525
539
  try {
526
- const result = await this.mergeProviderPullRequest(this._session!, pr, options);
540
+ const result = await this.mergeProviderPullRequest(this._session!, pr, options, cancellation);
527
541
  this.resetRequestExceptionCount('mergePullRequest');
528
542
  return result;
529
543
  } catch (ex) {
544
+ if (isCancellationError(ex)) return false;
545
+
530
546
  this.handleProviderException('mergePullRequest', ex, { scope: scope });
531
547
  return false;
548
+ } finally {
549
+ // A merge attempt just changed the state of more than this pull request on the server (a
550
+ // stacked merge lands every layer below and retargets every layer above) whether it succeeded
551
+ // or failed partway through — so cached pull requests can't be trusted either way. Without
552
+ // this, ref pills and branch enrichment keep serving the pre-merge object until its expiry.
553
+ this.ctx.cache.deletePullRequests();
532
554
  }
533
555
  }
534
556
 
@@ -536,6 +558,7 @@ export abstract class GitHostIntegration<
536
558
  session: ProviderAuthenticationSession,
537
559
  pr: PullRequest,
538
560
  options?: { mergeMethod?: PullRequestMergeMethod },
561
+ cancellation?: AbortSignal,
539
562
  ): Promise<boolean>;
540
563
 
541
564
  @trace()
@@ -1755,6 +1778,35 @@ export abstract class GitHostIntegration<
1755
1778
  cancellation?: AbortSignal,
1756
1779
  ): Promise<(number | undefined)[] | undefined>;
1757
1780
 
1781
+ /** The PR twin of {@link countIssuesResult}: counts each scope's pull requests, transferring none. */
1782
+ async countPullRequestsResult(
1783
+ scopes: readonly { repos?: ProviderRepoInput[]; org?: string; criteria?: PullRequestSearchCriteria }[],
1784
+ cancellation?: AbortSignal,
1785
+ connectionId?: string,
1786
+ ): Promise<IntegrationResult<(number | undefined)[] | undefined>> {
1787
+ const scope = getScopedLogger();
1788
+ // `connectionId` targets a specific account (multi-account); omitted reads the primary.
1789
+ const session = await this.resolveReadSession(connectionId, scope);
1790
+ if (session == null) return undefined;
1791
+
1792
+ const start = performance.now();
1793
+ try {
1794
+ const counts = await this.countProviderPullRequests?.(session, scopes, cancellation);
1795
+ this.resetRequestExceptionCount('countPullRequests');
1796
+ return { value: counts, duration: performance.now() - start };
1797
+ } catch (ex) {
1798
+ this.handleProviderException('countPullRequests', ex, { scope: scope, connectionId: connectionId });
1799
+ return { error: toError(ex), duration: performance.now() - start };
1800
+ }
1801
+ }
1802
+
1803
+ /** OPTIONAL, like {@link countProviderIssues}: only a provider that can count without fetching implements it. */
1804
+ protected countProviderPullRequests?(
1805
+ session: ProviderAuthenticationSession,
1806
+ scopes: readonly { repos?: ProviderRepoInput[]; org?: string; criteria?: PullRequestSearchCriteria }[],
1807
+ cancellation?: AbortSignal,
1808
+ ): Promise<(number | undefined)[] | undefined>;
1809
+
1758
1810
  getPullRequestIdentityFromMaybeUrl(search: string): PullRequestUrlIdentity | undefined {
1759
1811
  return this.getProviderPullRequestIdentityFromMaybeUrl?.(search);
1760
1812
  }
@@ -81,6 +81,7 @@ type SyncReqUsecase = Exclude<
81
81
  | 'getResourcesForUser'
82
82
  | 'getSshSigningKeysForEmails'
83
83
  | 'countIssues'
84
+ | 'countPullRequests'
84
85
  | 'mergePullRequest'
85
86
  | 'searchIssuesPage'
86
87
  | 'searchPullRequestsPage'
@@ -928,7 +929,11 @@ export abstract class IntegrationBase<
928
929
  }
929
930
 
930
931
  @trace()
931
- async getPullRequest(resource: T, id: string): Promise<PullRequest | undefined> {
932
+ async getPullRequest(
933
+ resource: T,
934
+ id: string,
935
+ options?: { expiryOverride?: boolean | number },
936
+ ): Promise<PullRequest | undefined> {
932
937
  const scope = getScopedLogger();
933
938
 
934
939
  const connected = this.maybeConnected ?? (await this.isConnected());
@@ -936,18 +941,24 @@ export abstract class IntegrationBase<
936
941
 
937
942
  await this.refreshSessionIfExpired(scope);
938
943
 
939
- const pr = await this.ctx.cache.getPullRequest(id, resource, this, () => ({
940
- value: (async () => {
941
- try {
942
- const result = await this.getProviderPullRequest?.(this._session!, resource, id);
943
- this.resetRequestExceptionCount('getPullRequest');
944
- return result;
945
- } catch (ex) {
946
- this.handleProviderException('getPullRequest', ex, { scope: scope });
947
- return undefined;
948
- }
949
- })(),
950
- }));
944
+ const pr = await this.ctx.cache.getPullRequest(
945
+ id,
946
+ resource,
947
+ this,
948
+ () => ({
949
+ value: (async () => {
950
+ try {
951
+ const result = await this.getProviderPullRequest?.(this._session!, resource, id);
952
+ this.resetRequestExceptionCount('getPullRequest');
953
+ return result;
954
+ } catch (ex) {
955
+ this.handleProviderException('getPullRequest', ex, { scope: scope });
956
+ return undefined;
957
+ }
958
+ })(),
959
+ }),
960
+ { expiryOverride: options?.expiryOverride },
961
+ );
951
962
  return pr;
952
963
  }
953
964
 
@@ -28,4 +28,9 @@ export type {
28
28
  * same dependency-direction reason as the issue-search model above: provider API clients translate them below
29
29
  * this package and cannot import this facade.
30
30
  */
31
- export type { PullRequestSearchCapabilities, PullRequestSearchCriteria } from '../../git/models/pullRequest.js';
31
+ export type {
32
+ PullRequestSearchCapabilities,
33
+ PullRequestSearchCriteria,
34
+ PullRequestSortField,
35
+ PullRequestSorting,
36
+ } from '../../git/models/pullRequest.js';