@gitkraken/core-gitlens 0.5.113 → 0.5.115

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 (349) hide show
  1. package/CHANGELOG.md +42 -1
  2. package/dist/git/cache.d.ts +4 -0
  3. package/dist/git/cache.d.ts.map +1 -1
  4. package/dist/git/cache.js +33 -0
  5. package/dist/git/cache.js.map +1 -1
  6. package/dist/git/context.d.ts +10 -0
  7. package/dist/git/context.d.ts.map +1 -1
  8. package/dist/git/context.js.map +1 -1
  9. package/dist/git/errors.d.ts +6 -3
  10. package/dist/git/errors.d.ts.map +1 -1
  11. package/dist/git/errors.js +9 -1
  12. package/dist/git/errors.js.map +1 -1
  13. package/dist/git/features.d.ts +1 -1
  14. package/dist/git/features.d.ts.map +1 -1
  15. package/dist/git/features.js +38 -0
  16. package/dist/git/features.js.map +1 -1
  17. package/dist/git/gitHealth.d.ts +153 -0
  18. package/dist/git/gitHealth.d.ts.map +1 -0
  19. package/dist/git/gitHealth.js +353 -0
  20. package/dist/git/gitHealth.js.map +1 -0
  21. package/dist/git/models/search.d.ts +6 -3
  22. package/dist/git/models/search.d.ts.map +1 -1
  23. package/dist/git/models/search.js +5 -1
  24. package/dist/git/models/search.js.map +1 -1
  25. package/dist/git/parsers/diffParser.d.ts +8 -2
  26. package/dist/git/parsers/diffParser.d.ts.map +1 -1
  27. package/dist/git/parsers/diffParser.js +27 -4
  28. package/dist/git/parsers/diffParser.js.map +1 -1
  29. package/dist/git/providers/config.d.ts +36 -3
  30. package/dist/git/providers/config.d.ts.map +1 -1
  31. package/dist/git/providers/graph.d.ts +9 -0
  32. package/dist/git/providers/graph.d.ts.map +1 -1
  33. package/dist/git/providers/maintenance.d.ts +222 -0
  34. package/dist/git/providers/maintenance.d.ts.map +1 -0
  35. package/dist/git/providers/maintenance.js +20 -0
  36. package/dist/git/providers/maintenance.js.map +1 -0
  37. package/dist/git/providers/operations.d.ts +10 -0
  38. package/dist/git/providers/operations.d.ts.map +1 -1
  39. package/dist/git/providers/pausedOperations.d.ts +3 -0
  40. package/dist/git/providers/pausedOperations.d.ts.map +1 -1
  41. package/dist/git/providers/provider.d.ts +2 -0
  42. package/dist/git/providers/provider.d.ts.map +1 -1
  43. package/dist/git/providers/tags.d.ts +3 -0
  44. package/dist/git/providers/tags.d.ts.map +1 -1
  45. package/dist/git/repositoryService.d.ts +1 -0
  46. package/dist/git/repositoryService.d.ts.map +1 -1
  47. package/dist/git/repositoryService.js.map +1 -1
  48. package/dist/git/run.types.d.ts +8 -0
  49. package/dist/git/run.types.d.ts.map +1 -1
  50. package/dist/git/service.js +3 -0
  51. package/dist/git/service.js.map +1 -1
  52. package/dist/git/utils/search.utils.d.ts.map +1 -1
  53. package/dist/git/utils/search.utils.js +112 -5
  54. package/dist/git/utils/search.utils.js.map +1 -1
  55. package/dist/git/watching/watchService.d.ts +3 -0
  56. package/dist/git/watching/watchService.d.ts.map +1 -1
  57. package/dist/git/watching/watchService.js +8 -0
  58. package/dist/git/watching/watchService.js.map +1 -1
  59. package/dist/git-cli/cliGitProvider.d.ts +11 -0
  60. package/dist/git-cli/cliGitProvider.d.ts.map +1 -1
  61. package/dist/git-cli/cliGitProvider.js +12 -0
  62. package/dist/git-cli/cliGitProvider.js.map +1 -1
  63. package/dist/git-cli/exec/git.d.ts +23 -1
  64. package/dist/git-cli/exec/git.d.ts.map +1 -1
  65. package/dist/git-cli/exec/git.js +83 -8
  66. package/dist/git-cli/exec/git.js.map +1 -1
  67. package/dist/git-cli/exec/gitQueue.d.ts +2 -0
  68. package/dist/git-cli/exec/gitQueue.d.ts.map +1 -1
  69. package/dist/git-cli/exec/gitQueue.js +19 -17
  70. package/dist/git-cli/exec/gitQueue.js.map +1 -1
  71. package/dist/git-cli/parsers/logParser.d.ts.map +1 -1
  72. package/dist/git-cli/parsers/logParser.js +4 -1
  73. package/dist/git-cli/parsers/logParser.js.map +1 -1
  74. package/dist/git-cli/providers/blame.d.ts.map +1 -1
  75. package/dist/git-cli/providers/blame.js +4 -7
  76. package/dist/git-cli/providers/blame.js.map +1 -1
  77. package/dist/git-cli/providers/branches.d.ts.map +1 -1
  78. package/dist/git-cli/providers/branches.js +13 -3
  79. package/dist/git-cli/providers/branches.js.map +1 -1
  80. package/dist/git-cli/providers/commits.d.ts.map +1 -1
  81. package/dist/git-cli/providers/commits.js +34 -3
  82. package/dist/git-cli/providers/commits.js.map +1 -1
  83. package/dist/git-cli/providers/config.d.ts +27 -0
  84. package/dist/git-cli/providers/config.d.ts.map +1 -1
  85. package/dist/git-cli/providers/config.js +31 -6
  86. package/dist/git-cli/providers/config.js.map +1 -1
  87. package/dist/git-cli/providers/graph.d.ts +8 -0
  88. package/dist/git-cli/providers/graph.d.ts.map +1 -1
  89. package/dist/git-cli/providers/graph.js +85 -6
  90. package/dist/git-cli/providers/graph.js.map +1 -1
  91. package/dist/git-cli/providers/maintenance.d.ts +306 -0
  92. package/dist/git-cli/providers/maintenance.d.ts.map +1 -0
  93. package/dist/git-cli/providers/maintenance.js +2129 -0
  94. package/dist/git-cli/providers/maintenance.js.map +1 -0
  95. package/dist/git-cli/providers/operations.d.ts +1 -0
  96. package/dist/git-cli/providers/operations.d.ts.map +1 -1
  97. package/dist/git-cli/providers/operations.js +8 -0
  98. package/dist/git-cli/providers/operations.js.map +1 -1
  99. package/dist/git-cli/providers/pausedOperations.d.ts +1 -0
  100. package/dist/git-cli/providers/pausedOperations.d.ts.map +1 -1
  101. package/dist/git-cli/providers/pausedOperations.js +1 -1
  102. package/dist/git-cli/providers/pausedOperations.js.map +1 -1
  103. package/dist/git-cli/providers/tags.d.ts +3 -0
  104. package/dist/git-cli/providers/tags.d.ts.map +1 -1
  105. package/dist/git-cli/providers/tags.js +23 -1
  106. package/dist/git-cli/providers/tags.js.map +1 -1
  107. package/dist/plus/agents/agentCapabilities.d.ts +77 -0
  108. package/dist/plus/agents/agentCapabilities.d.ts.map +1 -0
  109. package/dist/plus/agents/agentCapabilities.js +197 -0
  110. package/dist/plus/agents/agentCapabilities.js.map +1 -0
  111. package/dist/plus/agents/providers/claudeCodeTranscript.d.ts +77 -13
  112. package/dist/plus/agents/providers/claudeCodeTranscript.d.ts.map +1 -1
  113. package/dist/plus/agents/providers/claudeCodeTranscript.js +263 -55
  114. package/dist/plus/agents/providers/claudeCodeTranscript.js.map +1 -1
  115. package/dist/plus/agents/providers/{claudeCodeProvider.d.ts → gkAgentProvider.d.ts} +52 -19
  116. package/dist/plus/agents/providers/gkAgentProvider.d.ts.map +1 -0
  117. package/dist/plus/agents/providers/{claudeCodeProvider.js → gkAgentProvider.js} +935 -262
  118. package/dist/plus/agents/providers/gkAgentProvider.js.map +1 -0
  119. package/dist/plus/agents/types.d.ts +113 -35
  120. package/dist/plus/agents/types.d.ts.map +1 -1
  121. package/dist/plus/agents/types.js +7 -4
  122. package/dist/plus/agents/types.js.map +1 -1
  123. package/dist/plus/ai/models/promptTemplates.d.ts +1 -1
  124. package/dist/plus/ai/models/promptTemplates.d.ts.map +1 -1
  125. package/dist/plus/ai/prompts.d.ts +4 -0
  126. package/dist/plus/ai/prompts.d.ts.map +1 -1
  127. package/dist/plus/ai/prompts.js +59 -4
  128. package/dist/plus/ai/prompts.js.map +1 -1
  129. package/dist/plus/git-github/api/github.d.ts +44 -1
  130. package/dist/plus/git-github/api/github.d.ts.map +1 -1
  131. package/dist/plus/git-github/api/github.js +355 -62
  132. package/dist/plus/git-github/api/github.js.map +1 -1
  133. package/dist/plus/git-github/api/issueSearchQuery.d.ts +13 -0
  134. package/dist/plus/git-github/api/issueSearchQuery.d.ts.map +1 -1
  135. package/dist/plus/git-github/api/issueSearchQuery.js +41 -0
  136. package/dist/plus/git-github/api/issueSearchQuery.js.map +1 -1
  137. package/dist/plus/git-github/providers/github/blame.d.ts.map +1 -1
  138. package/dist/plus/git-github/providers/github/blame.js +2 -1
  139. package/dist/plus/git-github/providers/github/blame.js.map +1 -1
  140. package/dist/plus/integrations/collectionMetadata.d.ts +2 -0
  141. package/dist/plus/integrations/collectionMetadata.d.ts.map +1 -1
  142. package/dist/plus/integrations/collectionMetadata.js +17 -1
  143. package/dist/plus/integrations/collectionMetadata.js.map +1 -1
  144. package/dist/plus/integrations/context.d.ts +4 -1
  145. package/dist/plus/integrations/context.d.ts.map +1 -1
  146. package/dist/plus/integrations/index.d.ts +1 -0
  147. package/dist/plus/integrations/index.d.ts.map +1 -1
  148. package/dist/plus/integrations/integrationService.d.ts +20 -1
  149. package/dist/plus/integrations/integrationService.d.ts.map +1 -1
  150. package/dist/plus/integrations/integrationService.js +12 -4
  151. package/dist/plus/integrations/integrationService.js.map +1 -1
  152. package/dist/plus/integrations/manager.d.ts +48 -0
  153. package/dist/plus/integrations/manager.d.ts.map +1 -1
  154. package/dist/plus/integrations/models/gitHostIntegration.d.ts +53 -26
  155. package/dist/plus/integrations/models/gitHostIntegration.d.ts.map +1 -1
  156. package/dist/plus/integrations/models/gitHostIntegration.js +123 -47
  157. package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
  158. package/dist/plus/integrations/models/integration.d.ts +10 -1
  159. package/dist/plus/integrations/models/integration.d.ts.map +1 -1
  160. package/dist/plus/integrations/models/integration.js +52 -19
  161. package/dist/plus/integrations/models/integration.js.map +1 -1
  162. package/dist/plus/integrations/models/issueCache.d.ts +16 -0
  163. package/dist/plus/integrations/models/issueCache.d.ts.map +1 -0
  164. package/dist/plus/integrations/models/issueCache.js +9 -0
  165. package/dist/plus/integrations/models/issueCache.js.map +1 -0
  166. package/dist/plus/integrations/models/issueReads.d.ts +13 -0
  167. package/dist/plus/integrations/models/issueReads.d.ts.map +1 -1
  168. package/dist/plus/integrations/models/issuesIntegration.d.ts +11 -13
  169. package/dist/plus/integrations/models/issuesIntegration.d.ts.map +1 -1
  170. package/dist/plus/integrations/models/issuesIntegration.js +15 -1
  171. package/dist/plus/integrations/models/issuesIntegration.js.map +1 -1
  172. package/dist/plus/integrations/providers/azureDevOps.d.ts +3 -5
  173. package/dist/plus/integrations/providers/azureDevOps.d.ts.map +1 -1
  174. package/dist/plus/integrations/providers/azureDevOps.js +9 -8
  175. package/dist/plus/integrations/providers/azureDevOps.js.map +1 -1
  176. package/dist/plus/integrations/providers/bitbucket-server.d.ts +3 -5
  177. package/dist/plus/integrations/providers/bitbucket-server.d.ts.map +1 -1
  178. package/dist/plus/integrations/providers/bitbucket-server.js +2 -2
  179. package/dist/plus/integrations/providers/bitbucket-server.js.map +1 -1
  180. package/dist/plus/integrations/providers/bitbucket.d.ts +3 -5
  181. package/dist/plus/integrations/providers/bitbucket.d.ts.map +1 -1
  182. package/dist/plus/integrations/providers/bitbucket.js +2 -1
  183. package/dist/plus/integrations/providers/bitbucket.js.map +1 -1
  184. package/dist/plus/integrations/providers/github.d.ts +12 -5
  185. package/dist/plus/integrations/providers/github.d.ts.map +1 -1
  186. package/dist/plus/integrations/providers/github.js +10 -3
  187. package/dist/plus/integrations/providers/github.js.map +1 -1
  188. package/dist/plus/integrations/providers/gitlab.d.ts +3 -5
  189. package/dist/plus/integrations/providers/gitlab.d.ts.map +1 -1
  190. package/dist/plus/integrations/providers/gitlab.js +2 -2
  191. package/dist/plus/integrations/providers/gitlab.js.map +1 -1
  192. package/dist/plus/integrations/providers/jira.d.ts +3 -7
  193. package/dist/plus/integrations/providers/jira.d.ts.map +1 -1
  194. package/dist/plus/integrations/providers/jira.js +35 -22
  195. package/dist/plus/integrations/providers/jira.js.map +1 -1
  196. package/dist/plus/integrations/providers/jiraIssueByKey.d.ts +7 -0
  197. package/dist/plus/integrations/providers/jiraIssueByKey.d.ts.map +1 -0
  198. package/dist/plus/integrations/providers/jiraIssueByKey.js +102 -0
  199. package/dist/plus/integrations/providers/jiraIssueByKey.js.map +1 -0
  200. package/dist/plus/integrations/providers/linear.d.ts +3 -7
  201. package/dist/plus/integrations/providers/linear.d.ts.map +1 -1
  202. package/dist/plus/integrations/providers/linear.js +23 -22
  203. package/dist/plus/integrations/providers/linear.js.map +1 -1
  204. package/dist/plus/integrations/providers/models.d.ts +3 -1
  205. package/dist/plus/integrations/providers/models.d.ts.map +1 -1
  206. package/dist/plus/integrations/providers/models.js +10 -4
  207. package/dist/plus/integrations/providers/models.js.map +1 -1
  208. package/dist/plus/integrations/providers/providerErrors.d.ts +7 -0
  209. package/dist/plus/integrations/providers/providerErrors.d.ts.map +1 -0
  210. package/dist/plus/integrations/providers/providerErrors.js +91 -0
  211. package/dist/plus/integrations/providers/providerErrors.js.map +1 -0
  212. package/dist/plus/integrations/providers/providersApi.d.ts +3 -2
  213. package/dist/plus/integrations/providers/providersApi.d.ts.map +1 -1
  214. package/dist/plus/integrations/providers/providersApi.js +18 -52
  215. package/dist/plus/integrations/providers/providersApi.js.map +1 -1
  216. package/dist/plus/integrations/providers/trello.d.ts +2 -7
  217. package/dist/plus/integrations/providers/trello.d.ts.map +1 -1
  218. package/dist/plus/integrations/providers/trello.js +3 -1
  219. package/dist/plus/integrations/providers/trello.js.map +1 -1
  220. package/dist/plus/integrations/providers/utils/providerPaging.d.ts +2 -0
  221. package/dist/plus/integrations/providers/utils/providerPaging.d.ts.map +1 -1
  222. package/dist/plus/integrations/providers/utils/providerPaging.js +12 -7
  223. package/dist/plus/integrations/providers/utils/providerPaging.js.map +1 -1
  224. package/dist/plus/integrations/reads/broaden.d.ts +47 -10
  225. package/dist/plus/integrations/reads/broaden.d.ts.map +1 -1
  226. package/dist/plus/integrations/reads/broaden.js +144 -33
  227. package/dist/plus/integrations/reads/broaden.js.map +1 -1
  228. package/dist/plus/integrations/reads/filters.d.ts +18 -0
  229. package/dist/plus/integrations/reads/filters.d.ts.map +1 -1
  230. package/dist/plus/integrations/reads/filters.js +37 -1
  231. package/dist/plus/integrations/reads/filters.js.map +1 -1
  232. package/dist/plus/integrations/reads/issueBatch.d.ts +51 -0
  233. package/dist/plus/integrations/reads/issueBatch.d.ts.map +1 -0
  234. package/dist/plus/integrations/reads/issueBatch.js +91 -0
  235. package/dist/plus/integrations/reads/issueBatch.js.map +1 -0
  236. package/dist/plus/integrations/reads/issueTracker.d.ts.map +1 -1
  237. package/dist/plus/integrations/reads/issueTracker.js +23 -17
  238. package/dist/plus/integrations/reads/issueTracker.js.map +1 -1
  239. package/dist/plus/integrations/reads/sweeps.d.ts.map +1 -1
  240. package/dist/plus/integrations/reads/sweeps.js +5 -3
  241. package/dist/plus/integrations/reads/sweeps.js.map +1 -1
  242. package/dist/plus/integrations/reads/trackerIssue.d.ts +21 -0
  243. package/dist/plus/integrations/reads/trackerIssue.d.ts.map +1 -0
  244. package/dist/plus/integrations/reads/trackerIssue.js +51 -0
  245. package/dist/plus/integrations/reads/trackerIssue.js.map +1 -0
  246. package/dist/plus/integrations/reads/warnings.d.ts +2 -15
  247. package/dist/plus/integrations/reads/warnings.d.ts.map +1 -1
  248. package/dist/plus/integrations/reads/warnings.js +19 -1
  249. package/dist/plus/integrations/reads/warnings.js.map +1 -1
  250. package/dist/plus/integrations/results.d.ts +4 -20
  251. package/dist/plus/integrations/results.d.ts.map +1 -1
  252. package/dist/plus/integrations/results.js.map +1 -1
  253. package/dist/utils/promise.d.ts +2 -0
  254. package/dist/utils/promise.d.ts.map +1 -1
  255. package/dist/utils/promise.js +11 -0
  256. package/dist/utils/promise.js.map +1 -1
  257. package/dist/utils/promiseCache.d.ts +19 -0
  258. package/dist/utils/promiseCache.d.ts.map +1 -1
  259. package/dist/utils/promiseCache.js +30 -0
  260. package/dist/utils/promiseCache.js.map +1 -1
  261. package/dist/utils/resourceUsage.d.ts +5 -0
  262. package/dist/utils/resourceUsage.d.ts.map +1 -0
  263. package/dist/utils/resourceUsage.js +2 -0
  264. package/dist/utils/resourceUsage.js.map +1 -0
  265. package/dist/utils/string.d.ts +12 -0
  266. package/dist/utils/string.d.ts.map +1 -1
  267. package/dist/utils/string.js +36 -1
  268. package/dist/utils/string.js.map +1 -1
  269. package/docs/integrations.md +48 -33
  270. package/docs/kepler-read-api-parity.md +25 -4
  271. package/package.json +12 -4
  272. package/src/git/cache.ts +36 -0
  273. package/src/git/context.ts +11 -0
  274. package/src/git/errors.ts +13 -1
  275. package/src/git/features.ts +51 -0
  276. package/src/git/gitHealth.ts +522 -0
  277. package/src/git/models/search.ts +19 -4
  278. package/src/git/parsers/diffParser.ts +27 -4
  279. package/src/git/providers/config.ts +42 -1
  280. package/src/git/providers/graph.ts +12 -0
  281. package/src/git/providers/maintenance.ts +224 -0
  282. package/src/git/providers/operations.ts +10 -0
  283. package/src/git/providers/pausedOperations.ts +3 -0
  284. package/src/git/providers/provider.ts +2 -0
  285. package/src/git/providers/tags.ts +1 -0
  286. package/src/git/repositoryService.ts +1 -0
  287. package/src/git/run.types.ts +8 -0
  288. package/src/git/service.ts +3 -0
  289. package/src/git/utils/search.utils.ts +129 -5
  290. package/src/git/watching/watchService.ts +10 -0
  291. package/src/git-cli/cliGitProvider.ts +25 -0
  292. package/src/git-cli/exec/git.ts +120 -6
  293. package/src/git-cli/exec/gitQueue.ts +19 -17
  294. package/src/git-cli/parsers/logParser.ts +4 -1
  295. package/src/git-cli/providers/blame.ts +3 -8
  296. package/src/git-cli/providers/branches.ts +28 -8
  297. package/src/git-cli/providers/commits.ts +34 -2
  298. package/src/git-cli/providers/config.ts +38 -6
  299. package/src/git-cli/providers/graph.ts +107 -7
  300. package/src/git-cli/providers/maintenance.ts +2599 -0
  301. package/src/git-cli/providers/operations.ts +11 -0
  302. package/src/git-cli/providers/pausedOperations.ts +7 -2
  303. package/src/git-cli/providers/tags.ts +36 -1
  304. package/src/plus/agents/agentCapabilities.ts +286 -0
  305. package/src/plus/agents/providers/claudeCodeTranscript.ts +313 -58
  306. package/src/plus/agents/providers/{claudeCodeProvider.ts → gkAgentProvider.ts} +1123 -277
  307. package/src/plus/agents/types.ts +137 -40
  308. package/src/plus/ai/models/promptTemplates.ts +1 -1
  309. package/src/plus/ai/prompts.ts +62 -4
  310. package/src/plus/git-github/api/github.ts +404 -82
  311. package/src/plus/git-github/api/issueSearchQuery.ts +49 -1
  312. package/src/plus/git-github/providers/github/blame.ts +2 -1
  313. package/src/plus/integrations/collectionMetadata.ts +23 -1
  314. package/src/plus/integrations/context.ts +1 -1
  315. package/src/plus/integrations/index.ts +1 -0
  316. package/src/plus/integrations/integrationService.ts +29 -4
  317. package/src/plus/integrations/manager.ts +48 -0
  318. package/src/plus/integrations/models/gitHostIntegration.ts +165 -129
  319. package/src/plus/integrations/models/integration.ts +57 -22
  320. package/src/plus/integrations/models/issueCache.ts +29 -0
  321. package/src/plus/integrations/models/issueReads.ts +15 -0
  322. package/src/plus/integrations/models/issuesIntegration.ts +38 -8
  323. package/src/plus/integrations/providers/azureDevOps.ts +16 -13
  324. package/src/plus/integrations/providers/bitbucket-server.ts +4 -6
  325. package/src/plus/integrations/providers/bitbucket.ts +3 -4
  326. package/src/plus/integrations/providers/github.ts +23 -7
  327. package/src/plus/integrations/providers/gitlab.ts +4 -6
  328. package/src/plus/integrations/providers/jira.ts +52 -26
  329. package/src/plus/integrations/providers/jiraIssueByKey.ts +155 -0
  330. package/src/plus/integrations/providers/linear.ts +38 -25
  331. package/src/plus/integrations/providers/models.ts +17 -5
  332. package/src/plus/integrations/providers/providerErrors.ts +115 -0
  333. package/src/plus/integrations/providers/providersApi.ts +26 -68
  334. package/src/plus/integrations/providers/trello.ts +5 -4
  335. package/src/plus/integrations/providers/utils/providerPaging.ts +14 -7
  336. package/src/plus/integrations/reads/broaden.ts +282 -70
  337. package/src/plus/integrations/reads/filters.ts +39 -1
  338. package/src/plus/integrations/reads/issueBatch.ts +197 -0
  339. package/src/plus/integrations/reads/issueTracker.ts +26 -24
  340. package/src/plus/integrations/reads/sweeps.ts +19 -12
  341. package/src/plus/integrations/reads/trackerIssue.ts +105 -0
  342. package/src/plus/integrations/reads/warnings.ts +23 -17
  343. package/src/plus/integrations/results.ts +4 -20
  344. package/src/utils/promise.ts +15 -0
  345. package/src/utils/promiseCache.ts +43 -0
  346. package/src/utils/resourceUsage.ts +5 -0
  347. package/src/utils/string.ts +38 -1
  348. package/dist/plus/agents/providers/claudeCodeProvider.d.ts.map +0 -1
  349. package/dist/plus/agents/providers/claudeCodeProvider.js.map +0 -1
@@ -13,6 +13,7 @@ import type {
13
13
  import type { RepositoryMetadata } from '../../../git/models/repositoryMetadata.js';
14
14
  import type { ResourceDescriptor } from '../../../git/models/resourceDescriptor.js';
15
15
  import type { PullRequestUrlIdentity } from '../../../git/utils/pullRequest.utils.js';
16
+ import { ensureArray } from '../../../utils/array.js';
16
17
  import { isCancellationError } from '../../../utils/cancellation.js';
17
18
  import { gate } from '../../../utils/decorators/gate.js';
18
19
  import { trace } from '../../../utils/decorators/log.js';
@@ -22,7 +23,11 @@ import { getScopedLogger } from '../../../utils/logger.scoped.js';
22
23
  import type { PagedResult } from '../../../utils/paging.js';
23
24
  import type { ProviderAuthenticationSession } from '../authentication/models.js';
24
25
  import { toTokenWithInfo } from '../authentication/models.js';
25
- import { throwIfCallerContractError, toCollectionScopeFailure } from '../collectionMetadata.js';
26
+ import {
27
+ throwIfCallerContractError,
28
+ toCollectionFailureError,
29
+ toCollectionScopeFailure,
30
+ } from '../collectionMetadata.js';
26
31
  import type { IntegrationIds } from '../constants.js';
27
32
  import { GitCloudHostIntegrationId, GitSelfManagedHostIntegrationId } from '../constants.js';
28
33
  import { toError } from '../errors.js';
@@ -50,7 +55,7 @@ import {
50
55
  toProviderPullRequestStates,
51
56
  } from '../providers/models.js';
52
57
  import type { ProvidersApi } from '../providers/providersApi.js';
53
- import { mergeCollectionMetadata } from '../providers/utils/providerPaging.js';
58
+ import { mergeCollectionMetadata, throwIfAllSettledFailed } from '../providers/utils/providerPaging.js';
54
59
  import type {
55
60
  IntegrationResult,
56
61
  IntegrationType,
@@ -113,10 +118,24 @@ function getSelfManagedApiBaseUrl(
113
118
  }
114
119
  }
115
120
 
121
+ /** Read options for {@link GitHostIntegration.searchMyPullRequests} and the provider hook behind it. */
116
122
  export type SearchMyPullRequestsOptions = {
123
+ /** Suppresses the user-facing notification when the read fails. */
124
+ silent?: boolean;
125
+ /**
126
+ * PR states to include (open/closed/merged/all). Providers that cannot express it in a single query
127
+ * filter the normalized results; omitted preserves the historical open-only behavior.
128
+ */
129
+ state?: PullRequestStateFilter;
117
130
  includeReviewRequested?: boolean;
118
131
  };
119
132
 
133
+ /** Read options for {@link GitHostIntegration.searchPullRequests} and the provider hook behind it. */
134
+ export type SearchPullRequestsOptions = {
135
+ /** PR states to include; omitted preserves the provider's default. */
136
+ include?: PullRequestState[];
137
+ };
138
+
120
139
  type MyPullRequestsForReposOptions = {
121
140
  filters?: PullRequestFilter[];
122
141
  cursor?: string;
@@ -747,10 +766,17 @@ export abstract class GitHostIntegration<
747
766
  const customUrl =
748
767
  options?.customUrl ?? getSelfManagedApiBaseUrl(providerId, session.domain || this.domain, session.protocol);
749
768
 
750
- const api = await this.getProvidersApi();
769
+ let api: ProvidersApi;
770
+ try {
771
+ api = await this.getProvidersApi();
772
+ } catch (ex) {
773
+ this.handleProviderException('getIssuesForRepos', ex, { scope: scope, connectionId: connectionId });
774
+ return { error: toError(ex), duration: performance.now() - start };
775
+ }
776
+ const repoIdsInput = api.isRepoIdsInput(reposOrRepoIds);
751
777
  if (
752
778
  providerId !== GitCloudHostIntegrationId.GitLab &&
753
- (api.isRepoIdsInput(reposOrRepoIds) ||
779
+ (repoIdsInput ||
754
780
  (isAzureDevOpsProvider(providerId) &&
755
781
  !reposOrRepoIds.every(repo => repo.project != null && repo.namespace != null)))
756
782
  ) {
@@ -791,7 +817,10 @@ export abstract class GitHostIntegration<
791
817
  try {
792
818
  userAccount = await this.getFilterAccount(api, session, customUrl, organization);
793
819
  } catch (ex) {
794
- Logger.error(ex, 'getIssuesForRepos');
820
+ this.handleProviderException('getIssuesForRepos', ex, {
821
+ scope: scope,
822
+ connectionId: connectionId,
823
+ });
795
824
  return { error: toError(ex), duration: performance.now() - start };
796
825
  }
797
826
 
@@ -861,6 +890,7 @@ export abstract class GitHostIntegration<
861
890
  return { projectInput: projectInput, results: results };
862
891
  }),
863
892
  );
893
+ throwIfAllSettledFailed(settled);
864
894
 
865
895
  for (let i = 0; i < settled.length; i++) {
866
896
  const outcome = settled[i];
@@ -904,6 +934,7 @@ export abstract class GitHostIntegration<
904
934
  cursor.page = options.page;
905
935
  }
906
936
 
937
+ this.resetRequestExceptionCount('getIssuesForRepos');
907
938
  return {
908
939
  value: {
909
940
  values: data,
@@ -921,7 +952,10 @@ export abstract class GitHostIntegration<
921
952
  duration: performance.now() - start,
922
953
  };
923
954
  } catch (ex) {
924
- Logger.error(ex, 'getIssuesForRepos');
955
+ this.handleProviderException('getIssuesForRepos', ex, {
956
+ scope: scope,
957
+ connectionId: connectionId,
958
+ });
925
959
  return { error: toError(ex), duration: performance.now() - start };
926
960
  }
927
961
  }
@@ -937,7 +971,10 @@ export abstract class GitHostIntegration<
937
971
  try {
938
972
  userAccount = await this.getFilterAccount(api, session, customUrl);
939
973
  } catch (ex) {
940
- Logger.error(ex, 'getIssuesForRepos');
974
+ this.handleProviderException('getIssuesForRepos', ex, {
975
+ scope: scope,
976
+ connectionId: connectionId,
977
+ });
941
978
  return { error: toError(ex), duration: performance.now() - start };
942
979
  }
943
980
 
@@ -964,7 +1001,7 @@ export abstract class GitHostIntegration<
964
1001
  };
965
1002
  }
966
1003
 
967
- if (api.getProviderIssuesPagingMode(providerId) === PagingMode.Repo && !api.isRepoIdsInput(reposOrRepoIds)) {
1004
+ if (api.getProviderIssuesPagingMode(providerId) === PagingMode.Repo && !repoIdsInput) {
968
1005
  const cursorInfo = this.parseCursorInfo<PagedRepoInput>(options?.cursor);
969
1006
  const cursors: PagedRepoInput[] = cursorInfo.cursors ?? [];
970
1007
  let repoInputs: PagedRepoInput[] = reposOrRepoIds.map(repo => ({ repo: repo, cursor: undefined }));
@@ -1001,6 +1038,7 @@ export abstract class GitHostIntegration<
1001
1038
  return { repoInput: repoInput, results: results };
1002
1039
  }),
1003
1040
  );
1041
+ throwIfAllSettledFailed(settled);
1004
1042
 
1005
1043
  for (let i = 0; i < settled.length; i++) {
1006
1044
  const outcome = settled[i];
@@ -1038,6 +1076,7 @@ export abstract class GitHostIntegration<
1038
1076
  cursor.page = options.page;
1039
1077
  }
1040
1078
 
1079
+ this.resetRequestExceptionCount('getIssuesForRepos');
1041
1080
  return {
1042
1081
  value: {
1043
1082
  values: data,
@@ -1055,13 +1094,17 @@ export abstract class GitHostIntegration<
1055
1094
  duration: performance.now() - start,
1056
1095
  };
1057
1096
  } catch (ex) {
1058
- Logger.error(ex, 'getIssuesForRepos');
1097
+ this.handleProviderException('getIssuesForRepos', ex, {
1098
+ scope: scope,
1099
+ connectionId: connectionId,
1100
+ });
1059
1101
  return { error: toError(ex), duration: performance.now() - start };
1060
1102
  }
1061
1103
  }
1062
1104
 
1063
1105
  try {
1064
- const result = await api.getIssuesForRepos(toTokenWithInfo(providerId, session), reposOrRepoIds, {
1106
+ const tokenWithInfo = toTokenWithInfo(providerId, session);
1107
+ const result = await api.getIssuesForRepos(tokenWithInfo, reposOrRepoIds, {
1065
1108
  ...getIssuesOptions,
1066
1109
  cursor: options?.cursor,
1067
1110
  baseUrl: customUrl,
@@ -1070,9 +1113,28 @@ export abstract class GitHostIntegration<
1070
1113
  states: states,
1071
1114
  sort: options?.sort,
1072
1115
  });
1116
+ const failures = result.metadata?.failures;
1117
+ if (
1118
+ repoIdsInput &&
1119
+ reposOrRepoIds.length > 0 &&
1120
+ result.values.length === 0 &&
1121
+ failures?.length === reposOrRepoIds.length
1122
+ ) {
1123
+ const ex = toCollectionFailureError(failures[0], tokenWithInfo);
1124
+ this.handleProviderException('getIssuesForRepos', ex, {
1125
+ scope: scope,
1126
+ connectionId: connectionId,
1127
+ });
1128
+ return { error: ex, duration: performance.now() - start };
1129
+ }
1130
+
1131
+ this.resetRequestExceptionCount('getIssuesForRepos');
1073
1132
  return { value: result, duration: performance.now() - start };
1074
1133
  } catch (ex) {
1075
- Logger.error(ex, 'getIssuesForRepos');
1134
+ this.handleProviderException('getIssuesForRepos', ex, {
1135
+ scope: scope,
1136
+ connectionId: connectionId,
1137
+ });
1076
1138
  return { error: toError(ex), duration: performance.now() - start };
1077
1139
  }
1078
1140
  }
@@ -1134,7 +1196,16 @@ export abstract class GitHostIntegration<
1134
1196
  const customUrl =
1135
1197
  options?.customUrl ?? getSelfManagedApiBaseUrl(providerId, session.domain || this.domain, session.protocol);
1136
1198
 
1137
- const api = await this.getProvidersApi();
1199
+ let api: ProvidersApi;
1200
+ try {
1201
+ api = await this.getProvidersApi();
1202
+ } catch (ex) {
1203
+ this.handleProviderException('getPullRequestsForRepos', ex, {
1204
+ scope: scope,
1205
+ connectionId: connectionId,
1206
+ });
1207
+ return { error: toError(ex), duration: performance.now() - start };
1208
+ }
1138
1209
  if (
1139
1210
  providerId !== GitCloudHostIntegrationId.GitLab &&
1140
1211
  (api.isRepoIdsInput(reposOrRepoIds) ||
@@ -1182,14 +1253,20 @@ export abstract class GitHostIntegration<
1182
1253
  try {
1183
1254
  userAccount = await this.getFilterAccount(api, session, customUrl, organization);
1184
1255
  } catch (ex) {
1185
- Logger.error(ex, 'getPullRequestsForRepos');
1256
+ this.handleProviderException('getPullRequestsForRepos', ex, {
1257
+ scope: scope,
1258
+ connectionId: connectionId,
1259
+ });
1186
1260
  return { error: toError(ex), duration: performance.now() - start };
1187
1261
  }
1188
1262
  } else {
1189
1263
  try {
1190
1264
  userAccount = await this.getFilterAccount(api, session, customUrl);
1191
1265
  } catch (ex) {
1192
- Logger.error(ex, 'getPullRequestsForRepos');
1266
+ this.handleProviderException('getPullRequestsForRepos', ex, {
1267
+ scope: scope,
1268
+ connectionId: connectionId,
1269
+ });
1193
1270
  return { error: toError(ex), duration: performance.now() - start };
1194
1271
  }
1195
1272
  }
@@ -1298,6 +1375,7 @@ export abstract class GitHostIntegration<
1298
1375
  return { repoInput: repoInput, results: results };
1299
1376
  }),
1300
1377
  );
1378
+ throwIfAllSettledFailed(settled);
1301
1379
 
1302
1380
  // `allSettled` preserves order, so `settled[i]` is `repoInputs[i]`.
1303
1381
  settled.forEach((outcome, i) => {
@@ -1338,6 +1416,7 @@ export abstract class GitHostIntegration<
1338
1416
  cursor.page = options.page;
1339
1417
  }
1340
1418
 
1419
+ this.resetRequestExceptionCount('getPullRequestsForRepos');
1341
1420
  return {
1342
1421
  value: {
1343
1422
  values: data,
@@ -1355,7 +1434,10 @@ export abstract class GitHostIntegration<
1355
1434
  duration: performance.now() - start,
1356
1435
  };
1357
1436
  } catch (ex) {
1358
- Logger.error(ex, 'getPullRequestsForRepos');
1437
+ this.handleProviderException('getPullRequestsForRepos', ex, {
1438
+ scope: scope,
1439
+ connectionId: connectionId,
1440
+ });
1359
1441
  return { error: toError(ex), duration: performance.now() - start };
1360
1442
  }
1361
1443
  }
@@ -1372,80 +1454,40 @@ export abstract class GitHostIntegration<
1372
1454
  includeRemoteInfo: isAzureDevOpsProvider(providerId) ? true : undefined,
1373
1455
  fields: options?.summary ? summaryPullRequestFields : undefined,
1374
1456
  });
1457
+ this.resetRequestExceptionCount('getPullRequestsForRepos');
1375
1458
  return { value: result, duration: performance.now() - start };
1376
1459
  } catch (ex) {
1377
- Logger.error(ex, 'getPullRequestsForRepos');
1460
+ this.handleProviderException('getPullRequestsForRepos', ex, {
1461
+ scope: scope,
1462
+ connectionId: connectionId,
1463
+ });
1378
1464
  return { error: toError(ex), duration: performance.now() - start };
1379
1465
  }
1380
1466
  }
1381
1467
 
1382
- async searchMyPullRequests(
1383
- repo?: T,
1384
- cancellation?: AbortSignal,
1385
- silent?: boolean,
1386
- connectionId?: string,
1387
- state?: PullRequestStateFilter,
1388
- options?: SearchMyPullRequestsOptions,
1389
- ): Promise<IntegrationResult<PullRequest[] | undefined>>;
1390
- async searchMyPullRequests(
1391
- repos?: T[],
1392
- cancellation?: AbortSignal,
1393
- silent?: boolean,
1394
- connectionId?: string,
1395
- state?: PullRequestStateFilter,
1396
- options?: SearchMyPullRequestsOptions,
1397
- ): Promise<IntegrationResult<PullRequest[] | undefined>>;
1468
+ /** Account-wide (or repo-scoped) search for the current user's pull requests. */
1398
1469
  @trace()
1399
1470
  async searchMyPullRequests(
1400
1471
  repos?: T | T[],
1401
1472
  cancellation?: AbortSignal,
1402
- silent?: boolean,
1403
- connectionId?: string,
1404
- state?: PullRequestStateFilter,
1405
- options?: SearchMyPullRequestsOptions,
1473
+ options?: SearchMyPullRequestsOptions & { connectionId?: string },
1406
1474
  ): Promise<IntegrationResult<PullRequest[] | undefined>> {
1407
1475
  const scope = getScopedLogger();
1476
+ const { connectionId, ...searchOptions } = options ?? {};
1408
1477
  // `connectionId` targets a specific account (multi-account); omitted reads the primary.
1409
1478
  const session = await this.resolveReadSession(connectionId, scope);
1410
1479
  if (session == null) return undefined;
1411
1480
 
1412
1481
  const start = performance.now();
1413
1482
  try {
1414
- // Prefer the optional metadata-aware path for account-wide reads so partial failures (e.g. one Azure
1415
- // org rejecting) are surfaced as a soft `{ value, error }` instead of being lost. Repo-scoped reads and
1416
- // providers without that override keep using the legacy array path.
1417
- let result: IntegrationResult<PullRequest[] | undefined>;
1418
- if (this.searchProviderMyPullRequestsResult != null && repos == null) {
1419
- result = await this.searchProviderMyPullRequestsResult(
1420
- session,
1421
- repos != null ? (Array.isArray(repos) ? repos : [repos]) : undefined,
1422
- cancellation,
1423
- silent,
1424
- state,
1425
- options,
1426
- );
1427
- } else {
1428
- result = {
1429
- value: await this.searchProviderMyPullRequests(
1430
- session,
1431
- repos != null ? (Array.isArray(repos) ? repos : [repos]) : undefined,
1432
- cancellation,
1433
- silent,
1434
- state,
1435
- options,
1436
- ),
1437
- };
1438
- }
1483
+ const prs = await this.searchProviderMyPullRequests(
1484
+ session,
1485
+ ensureArray(repos),
1486
+ cancellation,
1487
+ searchOptions,
1488
+ );
1439
1489
  this.resetRequestExceptionCount('searchMyPullRequests');
1440
- // `IntegrationResult` is a strict union of value-only or error-only (and may be `undefined`). Return the
1441
- // matching branch explicitly; a missing result is treated as a successful empty read.
1442
- if (result == null) {
1443
- return { value: undefined, duration: performance.now() - start };
1444
- }
1445
- if (result.error != null) {
1446
- return { error: result.error, duration: performance.now() - start };
1447
- }
1448
- return { value: result.value, duration: performance.now() - start };
1490
+ return { value: prs, duration: performance.now() - start };
1449
1491
  } catch (ex) {
1450
1492
  this.handleProviderException('searchMyPullRequests', ex, {
1451
1493
  scope: scope,
@@ -1542,34 +1584,13 @@ export abstract class GitHostIntegration<
1542
1584
  }
1543
1585
  }
1544
1586
 
1545
- // `state` selects which PR states to include (open/closed/merged/all). Providers that cannot express it
1546
- // in a single query filter the normalized results; omitted preserves the historical open-only behavior.
1547
1587
  protected abstract searchProviderMyPullRequests(
1548
1588
  session: ProviderAuthenticationSession,
1549
1589
  repos?: T[],
1550
1590
  cancellation?: AbortSignal,
1551
- silent?: boolean,
1552
- state?: PullRequestStateFilter,
1553
1591
  options?: SearchMyPullRequestsOptions,
1554
1592
  ): Promise<PullRequest[] | undefined>;
1555
1593
 
1556
- /**
1557
- * Optional metadata-aware counterpart of {@link searchProviderMyPullRequests}. Providers whose account-wide
1558
- * "my PRs" read already produces {@link ProviderApiPagedResult} with completeness/failures can override
1559
- * this to return a soft `{ value, error }` result so `searchMyPullRequests` surfaces partial data and a
1560
- * warning instead of silently discarding the failure signal. The wrapper prefers this when present; the
1561
- * abstract {@link searchProviderMyPullRequests} remains the required fallback for repo-scoped and
1562
- * metadata-oblivious paths.
1563
- */
1564
- protected searchProviderMyPullRequestsResult?(
1565
- session: ProviderAuthenticationSession,
1566
- repos?: T[],
1567
- cancellation?: AbortSignal,
1568
- silent?: boolean,
1569
- state?: PullRequestStateFilter,
1570
- options?: SearchMyPullRequestsOptions,
1571
- ): Promise<IntegrationResult<PullRequest[] | undefined>>;
1572
-
1573
1594
  /**
1574
1595
  * Result-returning wrapper for the filtered pull-request search. Errors become the soft
1575
1596
  * `{ error }` branch so the public facade can preserve an empty account and a failed request as distinct
@@ -1618,49 +1639,16 @@ export abstract class GitHostIntegration<
1618
1639
  cancellation?: AbortSignal,
1619
1640
  ): Promise<ProviderPullRequestSearchPage | undefined>;
1620
1641
 
1621
- async searchPullRequests(
1622
- searchQuery: string,
1623
- repo?: T,
1624
- cancellation?: AbortSignal,
1625
- options?: { include?: PullRequestState[] },
1626
- ): Promise<PullRequest[] | undefined>;
1627
- async searchPullRequests(
1628
- searchQuery: string,
1629
- repos?: T[],
1630
- cancellation?: AbortSignal,
1631
- options?: { include?: PullRequestState[] },
1632
- ): Promise<PullRequest[] | undefined>;
1633
- async searchPullRequests(
1634
- searchQuery: string,
1635
- repo?: T,
1636
- cancellation?: AbortSignal,
1637
- connectionId?: string,
1638
- options?: { include?: PullRequestState[] },
1639
- ): Promise<PullRequest[] | undefined>;
1640
- async searchPullRequests(
1641
- searchQuery: string,
1642
- repos?: T[],
1643
- cancellation?: AbortSignal,
1644
- connectionId?: string,
1645
- options?: { include?: PullRequestState[] },
1646
- ): Promise<PullRequest[] | undefined>;
1642
+ /** Free-text search across pull requests, optionally narrowed to `repos`. */
1647
1643
  @trace()
1648
1644
  async searchPullRequests(
1649
1645
  searchQuery: string,
1650
1646
  repos?: T | T[],
1651
1647
  cancellation?: AbortSignal,
1652
- connectionIdOrOptions?: string | { include?: PullRequestState[] },
1653
- options?: { include?: PullRequestState[] },
1648
+ options?: SearchPullRequestsOptions & { connectionId?: string },
1654
1649
  ): Promise<PullRequest[] | undefined> {
1655
- // `connectionId` (string) can be omitted when passing `options`; split the overlapping 4th arg.
1656
- // When the 4th arg isn't the options object (a string `connectionId` or `undefined`), fall back to
1657
- // the 5th-arg `options` so an explicit `undefined` connectionId still honors state filtering.
1658
- const connectionId = typeof connectionIdOrOptions === 'string' ? connectionIdOrOptions : undefined;
1659
- const searchOptions =
1660
- connectionIdOrOptions != null && typeof connectionIdOrOptions !== 'string'
1661
- ? connectionIdOrOptions
1662
- : options;
1663
1650
  const scope = getScopedLogger();
1651
+ const { connectionId, ...searchOptions } = options ?? {};
1664
1652
  // `connectionId` targets a specific account (multi-account); omitted reads the primary.
1665
1653
  const session = await this.resolveReadSession(connectionId, scope);
1666
1654
  if (session == null) return undefined;
@@ -1669,7 +1657,7 @@ export abstract class GitHostIntegration<
1669
1657
  const prs = await this.searchProviderPullRequests?.(
1670
1658
  session,
1671
1659
  searchQuery,
1672
- repos != null ? (Array.isArray(repos) ? repos : [repos]) : undefined,
1660
+ ensureArray(repos),
1673
1661
  cancellation,
1674
1662
  searchOptions,
1675
1663
  );
@@ -1686,7 +1674,7 @@ export abstract class GitHostIntegration<
1686
1674
  searchQuery: string,
1687
1675
  repos?: T[],
1688
1676
  cancellation?: AbortSignal,
1689
- options?: { include?: PullRequestState[] },
1677
+ options?: SearchPullRequestsOptions,
1690
1678
  ): Promise<PullRequest[] | undefined>;
1691
1679
 
1692
1680
  /**
@@ -1789,6 +1777,54 @@ export abstract class GitHostIntegration<
1789
1777
  cancellation?: AbortSignal,
1790
1778
  ): Promise<(number | undefined)[] | undefined>;
1791
1779
 
1780
+ /**
1781
+ * Result-returning wrapper for the BATCH issue read: resolves several `(owner, repo, number)` coordinates in
1782
+ * one request. Recovers thrown errors into `{ error }` like the reads around it.
1783
+ *
1784
+ * Distinct from every search on this class, and deliberately so. A search answers "what matches"; this answers
1785
+ * "does this exact issue exist", which is the question a caller correlating a branch name to an issue is
1786
+ * actually asking. It has no result ceiling, no ordering and no cursor, and — the property that matters most —
1787
+ * an absent slot is a PROVEN ABSENCE rather than "not found within a page budget", so a caller can cache a
1788
+ * miss instead of re-walking for it forever.
1789
+ *
1790
+ * Results come back POSITIONALLY — one per input coordinate, in order — for the same reason
1791
+ * {@link countIssuesResult} does: a caller's key must never reach the provider query. `undefined` in a slot
1792
+ * means the issue does not exist or is not visible to this token, never that the read failed.
1793
+ */
1794
+ async getIssuesBatchResult(
1795
+ coordinates: readonly { owner: string; repo: string; number: number }[],
1796
+ cancellation?: AbortSignal,
1797
+ connectionId?: string,
1798
+ ): Promise<IntegrationResult<(IssueShape | undefined)[] | undefined>> {
1799
+ const scope = getScopedLogger();
1800
+ // `connectionId` targets a specific account (multi-account); omitted reads the primary.
1801
+ const session = await this.resolveReadSession(connectionId, scope);
1802
+ if (session == null) return undefined;
1803
+
1804
+ const start = performance.now();
1805
+ try {
1806
+ const issues = await this.getProviderIssuesBatch?.(session, coordinates, cancellation);
1807
+ this.resetRequestExceptionCount('getIssuesBatch');
1808
+ return { value: issues, duration: performance.now() - start };
1809
+ } catch (ex) {
1810
+ this.handleProviderException('getIssuesBatch', ex, { scope: scope, connectionId: connectionId });
1811
+ return { error: toError(ex), duration: performance.now() - start };
1812
+ }
1813
+ }
1814
+
1815
+ /**
1816
+ * OPTIONAL: only a provider that can resolve SEVERAL issues by coordinate in one request implements this.
1817
+ * GitHub aliases its point read into one document; the SDK exposes only a singular `getIssue` for every other
1818
+ * provider, and there is no plural variant to build on. A provider that can't answer doesn't implement it and
1819
+ * the facade refuses the read, so a caller keeps its own per-issue path rather than being handed a batch that
1820
+ * silently degraded into N requests.
1821
+ */
1822
+ protected getProviderIssuesBatch?(
1823
+ session: ProviderAuthenticationSession,
1824
+ coordinates: readonly { owner: string; repo: string; number: number }[],
1825
+ cancellation?: AbortSignal,
1826
+ ): Promise<(IssueShape | undefined)[] | undefined>;
1827
+
1792
1828
  /** The PR twin of {@link countIssuesResult}: counts each scope's pull requests, transferring none. */
1793
1829
  async countPullRequestsResult(
1794
1830
  scopes: readonly { repos?: ProviderRepoInput[]; org?: string; criteria?: PullRequestSearchCriteria }[],
@@ -11,6 +11,7 @@ import type { Disposable } from '../../../utils/disposable.js';
11
11
  import type { Event } from '../../../utils/event.js';
12
12
  import { Emitter } from '../../../utils/event.js';
13
13
  import { fnv1aHash64 } from '../../../utils/hash.js';
14
+ import { Logger } from '../../../utils/logger.js';
14
15
  import type { ScopedLogger } from '../../../utils/logger.scoped.js';
15
16
  import { getScopedLogger } from '../../../utils/logger.scoped.js';
16
17
  import type {
@@ -30,6 +31,7 @@ import type { Sources } from '../telemetry.js';
30
31
  import { areDomainsOnSameHost } from '../utils/domain.utils.js';
31
32
  import { isGitSelfManagedHostIntegrationId } from '../utils/integration.utils.js';
32
33
  import type { GitHostIntegration } from './gitHostIntegration.js';
34
+ import { getCachedIssue } from './issueCache.js';
33
35
  import type { AccountWideIssuesResult, SearchMyIssuesOptions } from './issueReads.js';
34
36
  import type { IssuesIntegration } from './issuesIntegration.js';
35
37
 
@@ -65,6 +67,7 @@ type SyncReqUsecase = Exclude<
65
67
  | 'getDefaultBranch'
66
68
  | 'getIssue'
67
69
  | 'getIssueOrPullRequest'
70
+ | 'getIssuesBatch'
68
71
  | 'getIssuesForProject'
69
72
  | 'getIssuesForRepos'
70
73
  | 'getMyPullRequestsForUser'
@@ -491,7 +494,11 @@ export abstract class IntegrationBase<
491
494
  ): void {
492
495
  if (isCancellationError(ex)) return;
493
496
 
494
- options?.scope?.error(ex);
497
+ if (options?.scope != null) {
498
+ options.scope.error(ex);
499
+ } else {
500
+ Logger.error(ex);
501
+ }
495
502
 
496
503
  // A per-connection (multi-account) read resolved its session through `resolveReadSession`'s
497
504
  // `connectionId` branch, which deliberately never touches the cached primary `_session`. So the
@@ -821,38 +828,66 @@ export abstract class IntegrationBase<
821
828
  type: undefined | IssueOrPullRequestType,
822
829
  ): Promise<IssueOrPullRequest | undefined>;
823
830
 
824
- @trace()
825
831
  async getIssue(
826
832
  resource: T,
827
833
  id: string,
828
- options?: { expiryOverride?: boolean | number },
834
+ options?: { connectionId?: string; expiryOverride?: boolean | number },
829
835
  ): Promise<Issue | undefined> {
830
- const scope = getScopedLogger();
836
+ return (await this.getIssueResult(resource, id, options))?.value;
837
+ }
831
838
 
832
- const connected = this.maybeConnected ?? (await this.isConnected());
833
- if (!connected) return undefined;
839
+ getIssueResult(
840
+ resource: T,
841
+ id: string,
842
+ options?: { connectionId?: string; expiryOverride?: boolean | number },
843
+ ): Promise<IntegrationResult<Issue | undefined>> {
844
+ return this.getIssueResultCore(resource, id, options, session => this.getProviderIssue(session, resource, id));
845
+ }
834
846
 
835
- await this.refreshSessionIfExpired(scope);
847
+ @trace()
848
+ protected async getIssueResultCore(
849
+ resource: ResourceDescriptor,
850
+ id: string,
851
+ options: { connectionId?: string; expiryOverride?: boolean | number } | undefined,
852
+ getProviderIssue: (session: ProviderAuthenticationSession) => Promise<Issue | undefined>,
853
+ ): Promise<IntegrationResult<Issue | undefined>> {
854
+ const scope = getScopedLogger();
855
+ const { connectionId: requestedConnectionId, expiryOverride } = options ?? {};
856
+ const connectionId = requestedConnectionId || undefined;
857
+ const session = await this.resolveReadSession(connectionId, scope);
858
+ if (session == null) return undefined;
836
859
 
837
- const issue = this.ctx.cache.getIssue(
838
- id,
839
- resource,
840
- this,
841
- () => ({
842
- value: (async () => {
860
+ try {
861
+ const issue = await getCachedIssue({
862
+ cache: this.ctx.cache,
863
+ id: id,
864
+ resource: resource,
865
+ integration: this,
866
+ load: async () => {
843
867
  try {
844
- const result = await this.getProviderIssue(this._session!, resource, id);
868
+ const issue = await getProviderIssue(session);
845
869
  this.resetRequestExceptionCount('getIssue');
846
- return result;
870
+ return issue;
847
871
  } catch (ex) {
848
- this.handleProviderException('getIssue', ex, { scope: scope });
849
- return undefined;
872
+ if (!isCancellationError(ex)) {
873
+ this.handleProviderException('getIssue', toError(ex), {
874
+ scope: scope,
875
+ connectionId: connectionId,
876
+ });
877
+ }
878
+ throw ex;
850
879
  }
851
- })(),
852
- }),
853
- options,
854
- );
855
- return issue;
880
+ },
881
+ cacheOptions: {
882
+ connectionId: connectionId,
883
+ expiryOverride: expiryOverride,
884
+ etag: `${this.id}:${this.maybeConnected ?? false}:${this.getSessionFingerprint(session)}`,
885
+ },
886
+ });
887
+ return { value: issue };
888
+ } catch (ex) {
889
+ return { error: toError(ex) };
890
+ }
856
891
  }
857
892
 
858
893
  protected abstract getProviderIssue(
@@ -0,0 +1,29 @@
1
+ import type { Issue } from '../../../git/models/issue.js';
2
+ import type { ResourceDescriptor } from '../../../git/models/resourceDescriptor.js';
3
+ import type { IntegrationCacheProvider } from '../context.js';
4
+
5
+ export async function getCachedIssue(options: {
6
+ cache: IntegrationCacheProvider;
7
+ id: string;
8
+ resource: ResourceDescriptor;
9
+ integration: Parameters<IntegrationCacheProvider['getIssue']>[2];
10
+ load: () => Promise<Issue | undefined>;
11
+ cacheOptions: {
12
+ connectionId: string | undefined;
13
+ expiryOverride: boolean | number | undefined;
14
+ etag: string;
15
+ };
16
+ }): Promise<Issue | undefined> {
17
+ return options.cache.getIssue(
18
+ options.id,
19
+ options.resource,
20
+ options.integration,
21
+ cacheable => ({
22
+ value: options.load().catch((ex: unknown) => {
23
+ cacheable.invalidate();
24
+ throw ex;
25
+ }),
26
+ }),
27
+ options.cacheOptions,
28
+ );
29
+ }