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