@gitkraken/core-gitlens 0.5.110 → 0.5.112

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 (362) hide show
  1. package/CHANGELOG.md +19 -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 +38 -2
  18. package/dist/git/models/pullRequest.d.ts.map +1 -1
  19. package/dist/git/models/pullRequest.js +12 -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 +14 -1
  52. package/dist/git/utils/pullRequest.utils.d.ts.map +1 -1
  53. package/dist/git/utils/pullRequest.utils.js +31 -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 +55 -0
  203. package/dist/plus/git-github/api/github.d.ts.map +1 -1
  204. package/dist/plus/git-github/api/github.js +177 -4
  205. package/dist/plus/git-github/api/github.js.map +1 -1
  206. package/dist/plus/git-github/models.d.ts +16 -0
  207. package/dist/plus/git-github/models.d.ts.map +1 -1
  208. package/dist/plus/git-github/models.js +29 -3
  209. package/dist/plus/git-github/models.js.map +1 -1
  210. package/dist/plus/git-github/providers/github/status.d.ts +1 -0
  211. package/dist/plus/git-github/providers/github/status.d.ts.map +1 -1
  212. package/dist/plus/git-github/providers/github/status.js.map +1 -1
  213. package/dist/plus/integrations/context.d.ts +4 -0
  214. package/dist/plus/integrations/context.d.ts.map +1 -1
  215. package/dist/plus/integrations/index.d.ts.map +1 -1
  216. package/dist/plus/integrations/index.js +2 -0
  217. package/dist/plus/integrations/index.js.map +1 -1
  218. package/dist/plus/integrations/models/gitHostIntegration.d.ts +6 -3
  219. package/dist/plus/integrations/models/gitHostIntegration.d.ts.map +1 -1
  220. package/dist/plus/integrations/models/gitHostIntegration.js +12 -2
  221. package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
  222. package/dist/plus/integrations/models/integration.d.ts +3 -1
  223. package/dist/plus/integrations/models/integration.d.ts.map +1 -1
  224. package/dist/plus/integrations/models/integration.js +2 -2
  225. package/dist/plus/integrations/models/integration.js.map +1 -1
  226. package/dist/plus/integrations/providers/accounts.d.ts.map +1 -1
  227. package/dist/plus/integrations/providers/accounts.js +4 -0
  228. package/dist/plus/integrations/providers/accounts.js.map +1 -1
  229. package/dist/plus/integrations/providers/azure/models.d.ts.map +1 -1
  230. package/dist/plus/integrations/providers/azure/models.js +3 -0
  231. package/dist/plus/integrations/providers/azure/models.js.map +1 -1
  232. package/dist/plus/integrations/providers/bitbucket/models.d.ts.map +1 -1
  233. package/dist/plus/integrations/providers/bitbucket/models.js +1 -0
  234. package/dist/plus/integrations/providers/bitbucket/models.js.map +1 -1
  235. package/dist/plus/integrations/providers/github.d.ts +14 -2
  236. package/dist/plus/integrations/providers/github.d.ts.map +1 -1
  237. package/dist/plus/integrations/providers/github.js +55 -3
  238. package/dist/plus/integrations/providers/github.js.map +1 -1
  239. package/dist/plus/integrations/providers/gitlab.d.ts.map +1 -1
  240. package/dist/plus/integrations/providers/gitlab.js.map +1 -1
  241. package/dist/plus/integrations/providers/models.d.ts.map +1 -1
  242. package/dist/plus/integrations/providers/models.js +30 -4
  243. package/dist/plus/integrations/providers/models.js.map +1 -1
  244. package/dist/plus/integrations/reads/broaden.d.ts.map +1 -1
  245. package/dist/plus/integrations/reads/broaden.js +6 -1
  246. package/dist/plus/integrations/reads/broaden.js.map +1 -1
  247. package/dist/plus/integrations/reads/drains.d.ts.map +1 -1
  248. package/dist/plus/integrations/reads/drains.js +7 -4
  249. package/dist/plus/integrations/reads/drains.js.map +1 -1
  250. package/dist/plus/integrations/reads/hierarchy.d.ts.map +1 -1
  251. package/dist/plus/integrations/reads/hierarchy.js +3 -1
  252. package/dist/plus/integrations/reads/hierarchy.js.map +1 -1
  253. package/dist/plus/integrations/reads/issueTracker.d.ts.map +1 -1
  254. package/dist/plus/integrations/reads/issueTracker.js +8 -3
  255. package/dist/plus/integrations/reads/issueTracker.js.map +1 -1
  256. package/dist/plus/integrations/reads/issues.d.ts.map +1 -1
  257. package/dist/plus/integrations/reads/issues.js +9 -4
  258. package/dist/plus/integrations/reads/issues.js.map +1 -1
  259. package/dist/plus/integrations/reads/pullRequests.d.ts.map +1 -1
  260. package/dist/plus/integrations/reads/pullRequests.js +9 -4
  261. package/dist/plus/integrations/reads/pullRequests.js.map +1 -1
  262. package/dist/utils/env/browser/base64.d.ts +1 -1
  263. package/dist/utils/env/browser/base64.d.ts.map +1 -1
  264. package/dist/utils/env/node/base64.d.ts +1 -1
  265. package/dist/utils/env/node/base64.d.ts.map +1 -1
  266. package/dist/utils/env/node/base64.js +2 -0
  267. package/dist/utils/env/node/base64.js.map +1 -1
  268. package/dist/utils/keys/chord.d.ts +52 -0
  269. package/dist/utils/keys/chord.d.ts.map +1 -0
  270. package/dist/utils/keys/chord.js +135 -0
  271. package/dist/utils/keys/chord.js.map +1 -0
  272. package/dist/utils/keys/keybinding.d.ts +53 -0
  273. package/dist/utils/keys/keybinding.d.ts.map +1 -0
  274. package/dist/utils/keys/keybinding.js +58 -0
  275. package/dist/utils/keys/keybinding.js.map +1 -0
  276. package/dist/utils/path.d.ts +11 -0
  277. package/dist/utils/path.d.ts.map +1 -1
  278. package/dist/utils/path.js +13 -0
  279. package/dist/utils/path.js.map +1 -1
  280. package/package.json +13 -5
  281. package/src/git/cache.ts +383 -47
  282. package/src/git/context.ts +11 -0
  283. package/src/git/models/fileStatus.ts +1 -0
  284. package/src/git/models/issue.ts +4 -0
  285. package/src/git/models/mergeConflicts.ts +3 -2
  286. package/src/git/models/pullRequest.ts +33 -1
  287. package/src/git/models/repository.ts +58 -17
  288. package/src/git/models/statusFile.ts +3 -0
  289. package/src/git/providers/branches.ts +6 -0
  290. package/src/git/providers/commits.ts +11 -0
  291. package/src/git/providers/config.ts +18 -0
  292. package/src/git/providers/operations.ts +1 -0
  293. package/src/git/providers/pausedOperations.ts +2 -0
  294. package/src/git/providers/status.ts +1 -0
  295. package/src/git/utils/config.utils.ts +8 -0
  296. package/src/git/utils/issue.utils.ts +2 -0
  297. package/src/git/utils/pausedOperationStatus.utils.ts +28 -0
  298. package/src/git/utils/pullRequest.utils.ts +36 -0
  299. package/src/git/watching/changeEvent.ts +6 -1
  300. package/src/git/watching/classifyChange.ts +15 -1
  301. package/src/git/watching/watchService.ts +20 -3
  302. package/src/git/watching/watchSession.ts +41 -6
  303. package/src/git/watching/watcherPatterns.ts +1 -1
  304. package/src/git-cli/exec/git.ts +13 -3
  305. package/src/git-cli/providers/branches.ts +384 -132
  306. package/src/git-cli/providers/commits.ts +106 -15
  307. package/src/git-cli/providers/config.ts +229 -8
  308. package/src/git-cli/providers/contributors.ts +5 -1
  309. package/src/git-cli/providers/graph.ts +26 -13
  310. package/src/git-cli/providers/operations.ts +45 -20
  311. package/src/git-cli/providers/pausedOperations.ts +109 -17
  312. package/src/git-cli/providers/refs.ts +33 -3
  313. package/src/git-cli/providers/status.ts +25 -4
  314. package/src/git-cli/providers/worktrees.ts +5 -0
  315. package/src/git-cli/service.ts +0 -1
  316. package/src/plus/agents/providers/claudeCodeProvider.ts +1130 -87
  317. package/src/plus/agents/providers/claudeCodeTranscript.ts +95 -9
  318. package/src/plus/agents/types.ts +46 -2
  319. package/src/plus/ai/errors.ts +30 -0
  320. package/src/plus/ai/models/model.ts +56 -6
  321. package/src/plus/ai/models/promptTemplates.ts +1 -1
  322. package/src/plus/ai/models/provider.ts +69 -2
  323. package/src/plus/ai/prompts.ts +186 -61
  324. package/src/plus/ai/providers/anthropicProvider.ts +155 -47
  325. package/src/plus/ai/providers/deepSeekProvider.ts +11 -21
  326. package/src/plus/ai/providers/geminiProvider.ts +19 -0
  327. package/src/plus/ai/providers/gitkrakenProvider.ts +126 -3
  328. package/src/plus/ai/providers/huggingFaceProvider.ts +6 -0
  329. package/src/plus/ai/providers/mistralProvider.ts +102 -19
  330. package/src/plus/ai/providers/ollamaProvider.ts +55 -4
  331. package/src/plus/ai/providers/openAICompatibleProvider.ts +5 -0
  332. package/src/plus/ai/providers/openAICompatibleProviderBase.ts +360 -17
  333. package/src/plus/ai/providers/openRouterProvider.ts +17 -0
  334. package/src/plus/ai/providers/openaiProvider.ts +1 -0
  335. package/src/plus/ai/providers/responseFormatCache.ts +39 -0
  336. package/src/plus/ai/providers/xaiProvider.ts +10 -1
  337. package/src/plus/ai/utils/ai.utils.ts +14 -0
  338. package/src/plus/ai/utils/results.utils.ts +255 -31
  339. package/src/plus/git-github/api/github.ts +291 -7
  340. package/src/plus/git-github/models.ts +48 -2
  341. package/src/plus/git-github/providers/github/status.ts +1 -0
  342. package/src/plus/integrations/context.ts +4 -0
  343. package/src/plus/integrations/index.ts +2 -0
  344. package/src/plus/integrations/models/gitHostIntegration.ts +25 -2
  345. package/src/plus/integrations/models/integration.ts +23 -13
  346. package/src/plus/integrations/providers/accounts.ts +4 -0
  347. package/src/plus/integrations/providers/azure/models.ts +3 -0
  348. package/src/plus/integrations/providers/bitbucket/models.ts +1 -0
  349. package/src/plus/integrations/providers/github.ts +85 -1
  350. package/src/plus/integrations/providers/gitlab.ts +2 -10
  351. package/src/plus/integrations/providers/models.ts +36 -4
  352. package/src/plus/integrations/reads/broaden.ts +6 -1
  353. package/src/plus/integrations/reads/drains.ts +7 -4
  354. package/src/plus/integrations/reads/hierarchy.ts +3 -1
  355. package/src/plus/integrations/reads/issueTracker.ts +9 -3
  356. package/src/plus/integrations/reads/issues.ts +9 -4
  357. package/src/plus/integrations/reads/pullRequests.ts +9 -4
  358. package/src/utils/env/browser/base64.ts +1 -1
  359. package/src/utils/env/node/base64.ts +3 -1
  360. package/src/utils/keys/chord.ts +184 -0
  361. package/src/utils/keys/keybinding.ts +116 -0
  362. package/src/utils/path.ts +14 -0
@@ -11,7 +11,6 @@ export type { PullRequestState };
11
11
 
12
12
  export interface PullRequestShape extends IssueOrPullRequest {
13
13
  readonly author: PullRequestMember;
14
- readonly body?: string;
15
14
  /**
16
15
  * Canonical base-repository identity returned by the provider. Some providers
17
16
  * scope pull-request ids to a repository, so consumers must not have to infer
@@ -23,6 +22,8 @@ export interface PullRequestShape extends IssueOrPullRequest {
23
22
  readonly isDraft?: boolean;
24
23
  readonly additions?: number;
25
24
  readonly deletions?: number;
25
+ readonly filesChanged?: number;
26
+ readonly body?: string;
26
27
  readonly mergeableState?: PullRequestMergeableState;
27
28
  readonly reviewDecision?: PullRequestReviewDecision;
28
29
  readonly reviewRequests?: PullRequestReviewer[];
@@ -37,6 +38,7 @@ export interface PullRequestShape extends IssueOrPullRequest {
37
38
  readonly latestReviews?: PullRequestReviewer[];
38
39
  readonly assignees?: PullRequestMember[];
39
40
  readonly project?: IssueProject;
41
+ readonly stack?: PullRequestStackInfo;
40
42
  readonly number?: number;
41
43
  readonly authoredByMe?: boolean;
42
44
  }
@@ -74,6 +76,12 @@ export class PullRequest implements PullRequestShape {
74
76
  public readonly statusCheckRollupState?: PullRequestStatusCheckRollupState,
75
77
  public readonly project?: IssueProject,
76
78
  public readonly version?: number,
79
+ /** Commits on the head that aren't on the base. Appended rather than slotted with the other counts:
80
+ * this constructor is positional and every mapper passes through it. */
81
+ public readonly commitCount?: number,
82
+ public readonly stack?: PullRequestStackInfo,
83
+ public readonly filesChanged?: number,
84
+ /** The pull request's description, as markdown. */
77
85
  public readonly body?: string,
78
86
  public readonly number?: number,
79
87
  public readonly authoredByMe?: boolean,
@@ -154,6 +162,10 @@ export interface PullRequestMember {
154
162
  * presentation.
155
163
  */
156
164
  name?: string;
165
+ /** The provider's handle for this person, when it has one — GitHub's login, Azure's `uniqueName` (a UPN,
166
+ * so an email), Bitbucket's mutable `nickname`. Display/labelling only: it is neither guaranteed present
167
+ * (GitLab's native mapper has none) nor a stable identity, so never key a match off it. */
168
+ username?: string;
157
169
  avatarUrl?: string;
158
170
  url?: string;
159
171
  }
@@ -299,6 +311,26 @@ export interface PullRequestRefs {
299
311
  isCrossRepository: boolean;
300
312
  }
301
313
 
314
+ /**
315
+ * A pull request's membership in a stack — an ordered chain of dependent pull requests where each
316
+ * targets the branch of the one below it.
317
+ *
318
+ * `baseRef` is the stack's ultimate target (its trunk) and is NOT the same as `refs.base`, which for
319
+ * anything above the bottom layer names the layer below. Use `refs.base` to diff a single layer; use
320
+ * `baseRef` to answer where the work ultimately lands.
321
+ */
322
+ export interface PullRequestStackInfo {
323
+ id: string;
324
+ /** Identifies the stack within its repository. */
325
+ number: number;
326
+ /** Total pull requests in the stack. */
327
+ size: number;
328
+ /** This pull request's layer, 1-based, where 1 is closest to `baseRef`. */
329
+ position: number;
330
+ /** The branch the bottom of the stack targets. */
331
+ baseRef: string;
332
+ }
333
+
302
334
  export interface PullRequestReviewer {
303
335
  isCodeOwner?: boolean;
304
336
  reviewer: PullRequestMember;
@@ -7,12 +7,12 @@ import type { UnifiedDisposable } from '../../utils/disposable.js';
7
7
  import { createDisposable } from '../../utils/disposable.js';
8
8
  import type { Event } from '../../utils/event.js';
9
9
  import { Emitter } from '../../utils/event.js';
10
- import { basename, normalizePath } from '../../utils/path.js';
10
+ import { some } from '../../utils/iterable.js';
11
+ import { basename, isDescendant, normalizePath } from '../../utils/path.js';
11
12
  import type { Uri } from '../../utils/uri.js';
12
- import { fileUri } from '../../utils/uri.js';
13
13
  import type { GitProviderDescriptor } from '../providers/types.js';
14
14
  import { getCommonRepositoryUri } from '../utils/repository.utils.js';
15
- import type { WatcherRepoChangeEvent } from '../watching/changeEvent.js';
15
+ import type { WatcherRepoChangeEvent, WorkingTreeChangeEvent } from '../watching/changeEvent.js';
16
16
  import type { RepositoryWatchService, WatchHandle, WatchHooks } from '../watching/watchService.js';
17
17
  import type { RepositorySubscription } from '../watching/watchSession.js';
18
18
  import { RepositoryChangeEvent } from './repositoryChangeEvent.js';
@@ -107,10 +107,44 @@ export interface RepositoryInit {
107
107
  readonly watchService: RepositoryWatchService;
108
108
  }
109
109
 
110
- export interface RepositoryWorkingTreeChangeEvent {
111
- readonly repository: Repository;
112
- /** URIs of changed files */
113
- readonly uris: ReadonlySet<Uri>;
110
+ /**
111
+ * An event describing working tree file changes.
112
+ *
113
+ * Deliberately exposes no path collection. Consumers react by refreshing, and a refresh re-reads current
114
+ * state — so the paths only ever gate whether to bother, never what the answer is. A partial set would
115
+ * read as usable while quietly licensing the one harmful outcome (concluding a file did NOT change), so
116
+ * {@link changed} is the only way to ask.
117
+ */
118
+ export class RepositoryWorkingTreeChangeEvent {
119
+ constructor(
120
+ readonly repository: Repository,
121
+ /** Absolute paths changed in this batch; partial when {@link incomplete}. */
122
+ private readonly paths: ReadonlySet<string>,
123
+ /** Whether paths were dropped, so {@link paths} can't be used to rule anything out. */
124
+ private readonly incomplete: boolean,
125
+ ) {}
126
+
127
+ /**
128
+ * Whether `uri` — or anything beneath it, when it's a folder — changed in this batch.
129
+ *
130
+ * Conservative: `true` whenever the batch is incomplete, since a miss would then prove nothing. Matches
131
+ * on paths rather than URIs so nothing has to be allocated to answer.
132
+ */
133
+ changed(uri: Uri): boolean {
134
+ if (this.incomplete) return true;
135
+
136
+ const path = uri.fsPath;
137
+ return some(this.paths, p => p === path || isDescendant(p, path));
138
+ }
139
+
140
+ toString(): string {
141
+ if (this.incomplete) return `{ repository: ${this.repository.name ?? ''}, paths: incomplete }`;
142
+
143
+ const [first] = this.paths;
144
+ return `{ repository: ${this.repository.name ?? ''}, paths(${this.paths.size}): [${first ?? ''}${
145
+ this.paths.size > 1 ? ', ...' : ''
146
+ }] }`;
147
+ }
114
148
  }
115
149
 
116
150
  export class Repository {
@@ -140,7 +174,8 @@ export class Repository {
140
174
  protected _watchHandle: WatchHandle | undefined;
141
175
  protected readonly _watchService: RepositoryWatchService;
142
176
 
143
- private _pendingWorkingTreeChange?: RepositoryWorkingTreeChangeEvent;
177
+ private _pendingWorkingTreePaths?: Set<string>;
178
+ private _pendingWorkingTreeIncomplete = false;
144
179
  private _pendingWorkingTreeFlush = false;
145
180
  private _repoChangeListener: UnifiedDisposable | undefined;
146
181
  /** Outstanding leases on the shared {@link _watchHandle} across `watch()` + `watchWorkingTree()`. */
@@ -318,7 +353,7 @@ export class Repository {
318
353
  if (acquired == null) return createDisposable(() => {});
319
354
 
320
355
  const sub = acquired.handle.session.subscribeToWorkingTree({ delayMs: delay });
321
- const listener = sub.onDidChangeWorkingTree(e => this.onWorkingTreeChanged(e.paths));
356
+ const listener = sub.onDidChangeWorkingTree(e => this.onWorkingTreeChanged(e));
322
357
 
323
358
  return createDisposable(
324
359
  () => {
@@ -409,24 +444,30 @@ export class Repository {
409
444
  * `_onDidChangeWorkingTree` emission. Without this coalescing, every WIP-dependent listener
410
445
  * (graph, file history, compare branch, etc.) would fire N times for N active subscriptions.
411
446
  */
412
- protected onWorkingTreeChanged(paths: ReadonlySet<string>): void {
447
+ /** Takes the session event whole rather than spreading it across parameters — a subclass override that
448
+ * dropped a trailing positional argument silently defeated this pipeline once already. */
449
+ protected onWorkingTreeChanged(e: WorkingTreeChangeEvent): void {
413
450
  this._updatedAt = Date.now();
414
451
 
415
- this._pendingWorkingTreeChange ??= { repository: this, uris: new Set<Uri>() };
416
- for (const p of paths) {
417
- (this._pendingWorkingTreeChange.uris as Set<Uri>).add(fileUri(p));
452
+ this._pendingWorkingTreePaths ??= new Set<string>();
453
+ for (const p of e.paths) {
454
+ this._pendingWorkingTreePaths.add(p);
418
455
  }
456
+ this._pendingWorkingTreeIncomplete ||= e.incomplete;
419
457
 
420
458
  if (this._pendingWorkingTreeFlush) return;
421
459
 
422
460
  this._pendingWorkingTreeFlush = true;
423
461
  queueMicrotask(() => {
424
462
  this._pendingWorkingTreeFlush = false;
425
- const e = this._pendingWorkingTreeChange;
426
- if (e == null) return;
463
+ const paths = this._pendingWorkingTreePaths;
464
+ if (paths == null) return;
465
+
466
+ const incomplete = this._pendingWorkingTreeIncomplete;
467
+ this._pendingWorkingTreePaths = undefined;
468
+ this._pendingWorkingTreeIncomplete = false;
427
469
 
428
- this._pendingWorkingTreeChange = undefined;
429
- this._onDidChangeWorkingTree.fire(e);
470
+ this._onDidChangeWorkingTree.fire(new RepositoryWorkingTreeChangeEvent(this, paths, incomplete));
430
471
  });
431
472
  }
432
473
 
@@ -86,6 +86,9 @@ export class GitStatusFile implements GitFile {
86
86
  case 'M':
87
87
  this.workingTreeStatus = GitFileWorkingTreeStatus.Modified;
88
88
  break;
89
+ case 'T':
90
+ this.workingTreeStatus = GitFileWorkingTreeStatus.TypeChanged;
91
+ break;
89
92
  }
90
93
  }
91
94
  }
@@ -102,6 +102,12 @@ export interface GitBranchesSubProvider {
102
102
  targetBranch: string,
103
103
  cancellation?: AbortSignal,
104
104
  ): Promise<ConflictDetectionResult>;
105
+ /** Detects conflicts when an autostash is reapplied onto the tree an integration produced */
106
+ getPotentialStashReapplyConflicts?(
107
+ repoPath: string,
108
+ ontoTreeOid: string,
109
+ cancellation?: AbortSignal,
110
+ ): Promise<ConflictDetectionResult>;
105
111
  getBaseBranchName?(
106
112
  repoPath: string,
107
113
  ref: string,
@@ -8,6 +8,7 @@ import type { GitRevisionRange } from '../models/revision.js';
8
8
  import type { SearchQuery } from '../models/search.js';
9
9
  import type { CommitSignature, SshSignedCommit } from '../models/signature.js';
10
10
  import type { GitUser } from '../models/user.js';
11
+ import type { GitCommandPriority } from '../run.types.js';
11
12
  import type { DiffRange } from './types.js';
12
13
 
13
14
  export interface LeftRightCommitCountResult {
@@ -82,6 +83,16 @@ export interface GitCommitsSubProvider {
82
83
  * Cheap early-exit probe (`rev-list --not --remotes <rev> -n 1`) — it does NOT count them. Returns
83
84
  * `undefined` when it can't be determined. */
84
85
  hasUnpublishedCommits?(repoPath: string, rev: string, cancellation?: AbortSignal): Promise<boolean | undefined>;
86
+ /** Batched form of {@link hasUnpublishedCommits}: returns the subset of `shas` with commits not reachable
87
+ * from any remote-tracking ref, in ONE walk rather than a spawn per sha. Pass tips from any worktrees of
88
+ * the same repo — the object store and `refs/remotes` are shared, so a single `repoPath` covers them all.
89
+ * Callers should skip this when the repo has no remotes (every local commit would qualify). */
90
+ filterUnpublishedShas?(
91
+ repoPath: string,
92
+ shas: readonly string[],
93
+ options?: { priority?: GitCommandPriority },
94
+ cancellation?: AbortSignal,
95
+ ): Promise<Set<string>>;
85
96
  /** Cheap author/committer date lookup for a single revision. Skips the full commit parse (no files, parents, or message) — use when only the dates are needed. Pass a full SHA so caching stays correct (commits are immutable; refs are not). */
86
97
  getCommitDates?(
87
98
  repoPath: string,
@@ -13,8 +13,16 @@ export type GitCoreConfigKeys =
13
13
  | 'gpg.ssh.program'
14
14
  | 'gpg.ssh.allowedSignersFile'
15
15
  | 'init.defaultBranch'
16
+ /** `merge.autoStash` — whether `git merge` (and so a merging `git pull`) stashes and reapplies uncommitted changes */
17
+ | 'merge.autoStash'
18
+ /** `pull.autoStash` — overrides `merge.autoStash`/`rebase.autoStash` for `git pull`, in either mode */
19
+ | 'pull.autoStash'
16
20
  /** `pull.rebase` — whether `git pull` rebases instead of merging; also accepts `merges`/`interactive` */
17
21
  | 'pull.rebase'
22
+ /** `rebase.autoStash` — whether `git rebase` (and so a rebasing `git pull`) stashes and reapplies uncommitted changes */
23
+ | 'rebase.autoStash'
24
+ /** `rebase.updateRefs` — whether `git rebase` also updates branches pointing to the rebased commits */
25
+ | 'rebase.updateRefs'
18
26
  | 'user.email'
19
27
  | 'user.name'
20
28
  | 'user.signingkey';
@@ -100,6 +108,16 @@ export interface GitConfigSubProvider {
100
108
  value: string | undefined,
101
109
  options?: { skipInvalidation?: readonly GkConfigInvalidationTarget[] },
102
110
  ): Promise<void>;
111
+ /**
112
+ * Drops every gk key stored for `ref` — call when a branch stops existing under that name. Deliberately
113
+ * includes user-owned values (`gk-merge-target-user`, `gk-disposition`, `gk-associated-issues`): the
114
+ * branch is confirmed gone, and leaving them would hand the next branch reusing that name a dead one's
115
+ * starred state and issue links. Only call where git guarantees the name is free —
116
+ * a completed delete.
117
+ */
118
+ removeGkConfigBranchSection?(repoPath: string, ref: string): Promise<void>;
119
+ /** Moves every gk key stored for `oldRef` to `newRef` — call when a branch is renamed. */
120
+ renameGkConfigBranchSection?(repoPath: string, oldRef: string, newRef: string): Promise<void>;
103
121
 
104
122
  getSigningConfig?(repoPath: string): Promise<SigningConfig>;
105
123
  getSigningConfigFlags?(config: SigningConfig): string[];
@@ -112,6 +112,7 @@ export interface GitOperationsSubProvider {
112
112
  */
113
113
  messageEditor?: string;
114
114
  onto?: string;
115
+ /** `true` → `--update-refs`, `false` → `--no-update-refs`, omitted → git config (`rebase.updateRefs`) decides. */
115
116
  updateRefs?: boolean;
116
117
  source?: unknown;
117
118
  },
@@ -10,6 +10,8 @@ export interface GitPausedOperationsSubProvider {
10
10
  continuePausedOperation(
11
11
  repoPath: string,
12
12
  options?: {
13
+ /** Records the empty commit the operation refused to create, then concludes it (cherry-pick/revert) */
14
+ allowEmpty?: boolean;
13
15
  skip?: boolean;
14
16
  /** Editor command used if the operation needs to edit a commit message (e.g. `true` to keep the original message without opening an editor) */
15
17
  messageEditor?: string;
@@ -37,6 +37,7 @@ export interface GitStatusSubProvider {
37
37
  unstaged?: boolean;
38
38
  untracked?: boolean;
39
39
  throwOnError?: boolean;
40
+ priority?: GitCommandPriority;
40
41
  },
41
42
  cancellation?: AbortSignal,
42
43
  ): Promise<boolean>;
@@ -0,0 +1,8 @@
1
+ const falseValues = new Set(['', 'false', 'no', 'off', '0']);
2
+
3
+ /** Interprets a git config value with git's boolean semantics; `undefined` in → `undefined` out (unset). */
4
+ export function parseGitBoolean(value: string | null | undefined): boolean | undefined {
5
+ if (value == null) return undefined;
6
+
7
+ return !falseValues.has(value.trim().toLowerCase());
8
+ }
@@ -134,6 +134,7 @@ export function serializeIssue(value: IssueShape): IssueShape {
134
134
  : {
135
135
  id: value.author.id,
136
136
  name: value.author.name,
137
+ username: value.author.username,
137
138
  avatarUrl: value.author.avatarUrl,
138
139
  url: value.author.url,
139
140
  },
@@ -157,6 +158,7 @@ export function serializeIssue(value: IssueShape): IssueShape {
157
158
  assignees: value.assignees.map(assignee => ({
158
159
  id: assignee.id,
159
160
  name: assignee.name,
161
+ username: assignee.username,
160
162
  avatarUrl: assignee.avatarUrl,
161
163
  url: assignee.url,
162
164
  })),
@@ -23,30 +23,58 @@ export function getConflictCurrentRef(status: GitPausedOperationStatus): GitRefe
23
23
  return status.current;
24
24
  }
25
25
 
26
+ /** `name` is the Title Case form for buttons/actions; `prose` is the sentence form ("Cherry-pick paused"). */
26
27
  export const pausedOperationStatusStringsByType = {
27
28
  'cherry-pick': {
29
+ name: 'Cherry Pick',
30
+ prose: 'Cherry-pick',
28
31
  label: 'Cherry picking',
29
32
  conflicts: 'Resolve conflicts to continue cherry picking',
30
33
  directionality: 'into',
31
34
  },
32
35
  merge: {
36
+ name: 'Merge',
37
+ prose: 'Merge',
33
38
  label: 'Merging',
34
39
  conflicts: 'Resolve conflicts to continue merging',
35
40
  directionality: 'into',
36
41
  },
37
42
  rebase: {
43
+ name: 'Rebase',
44
+ prose: 'Rebase',
38
45
  label: 'Rebasing',
39
46
  conflicts: 'Resolve conflicts to continue rebasing',
40
47
  directionality: 'onto',
41
48
  pending: 'Pending rebase of',
42
49
  },
43
50
  revert: {
51
+ name: 'Revert',
52
+ prose: 'Revert',
44
53
  label: 'Reverting',
45
54
  conflicts: 'Resolve conflicts to continue reverting',
46
55
  directionality: 'in',
47
56
  },
48
57
  } as const;
49
58
 
59
+ export type PausedOperationVariant = 'conflicts' | 'pending' | 'ready';
60
+
61
+ /** Codicon per variant — shared so the bar and the WIP badge can't drift. */
62
+ export const pausedOperationVariantIcons: Record<PausedOperationVariant, string> = {
63
+ conflicts: 'warning',
64
+ pending: 'circle-outline',
65
+ ready: 'check',
66
+ };
67
+
68
+ /** Unresolved conflicts outrank a rebase that hasn't reached its first step — neither can continue, but only conflicts are actionable. */
69
+ export function getPausedOperationVariant(
70
+ status: GitPausedOperationStatus,
71
+ hasConflicts: boolean,
72
+ ): PausedOperationVariant {
73
+ if (hasConflicts) return 'conflicts';
74
+ if (status.type === 'rebase' && status.steps.total === 0) return 'pending';
75
+ return 'ready';
76
+ }
77
+
50
78
  /**
51
79
  * Resolves the correct file paths for each side of a merge conflict diff when the file may have been renamed.
52
80
  *
@@ -6,9 +6,23 @@ import type {
6
6
  PullRequestShape,
7
7
  PullRequestSortField,
8
8
  PullRequestSorting,
9
+ PullRequestStackInfo,
9
10
  } from '../models/pullRequest.js';
10
11
  import { shortenRevision } from './revision.utils.js';
11
12
 
13
+ /** How many pull requests a merge action affects — unstacked is always 1; a stacked merge lands either
14
+ * just this layer and everything below it (`position`), or the whole stack (`wholeStack`). The one
15
+ * source every merge-confirmation and merge-action label counts from, so they can't drift apart.
16
+ * Takes only the two fields it needs (not the full {@link PullRequestStackInfo}) since callers on the
17
+ * webview side carry narrower serialized stack shapes. */
18
+ export function getStackedMergeCount(
19
+ stack: Pick<PullRequestStackInfo, 'position' | 'size'> | undefined,
20
+ options?: { wholeStack?: boolean },
21
+ ): number {
22
+ if (stack == null) return 1;
23
+ return options?.wholeStack ? stack.size : stack.position;
24
+ }
25
+
12
26
  /**
13
27
  * How each sort field is read off a {@link PullRequestShape}, for the filtered PR search, which MERGES its
14
28
  * relationship × state facets in the facade and so has to order the union itself instead of trusting the
@@ -90,6 +104,18 @@ export function getPullRequestIdentityFromMaybeUrl(search: string): PullRequestU
90
104
  return prNumber == null ? undefined : { ownerAndRepo: undefined, prNumber: prNumber, provider: undefined };
91
105
  }
92
106
 
107
+ /** A pull request's display number from its url, or `undefined` for a url naming no pull request. Anchors
108
+ * on the provider's pull request path segment (GitHub `pull`, Bitbucket `pull-requests`, GitLab
109
+ * `merge_requests`, Azure `pullrequest`) so a digit-leading owner (`github.com/1Password/x/pull/123`)
110
+ * can't win. */
111
+ export function getPullRequestNumberFromUrl(url: string): string | undefined {
112
+ // No loose fallback: `getPullRequestIdentityFromMaybeUrl` scans for any `/<digits>`, which reads a bare
113
+ // repository url like `github.com/1Password/sdk` as pull request #1. Callers that hold a real pull
114
+ // request fall back to its id instead, and the one that asks whether a pasted url names a pull request
115
+ // needs "no" for an answer.
116
+ return url.match(/(?:pull|pull-requests|merge_requests|pullrequest)\/(\d+)(?:\b|\/|$)/)?.[1];
117
+ }
118
+
93
119
  export function getRepositoryIdentityForPullRequest(
94
120
  pr: PullRequest,
95
121
  headRepo: boolean = true,
@@ -152,6 +178,7 @@ export function serializePullRequest(value: PullRequest): PullRequestShape {
152
178
  author: {
153
179
  id: value.author.id,
154
180
  name: value.author.name,
181
+ username: value.author.username,
155
182
  avatarUrl: value.author.avatarUrl,
156
183
  url: value.author.url,
157
184
  },
@@ -203,6 +230,15 @@ export function serializePullRequest(value: PullRequest): PullRequestShape {
203
230
  resourceName: value.project.resourceName,
204
231
  }
205
232
  : undefined,
233
+ stack: value.stack
234
+ ? {
235
+ id: value.stack.id,
236
+ number: value.stack.number,
237
+ size: value.stack.size,
238
+ position: value.stack.position,
239
+ baseRef: value.stack.baseRef,
240
+ }
241
+ : undefined,
206
242
  };
207
243
  return serialized;
208
244
  }
@@ -85,6 +85,11 @@ export class WatcherRepoChangeEvent {
85
85
  */
86
86
  export interface WorkingTreeChangeEvent {
87
87
  readonly repoPath: string;
88
- /** Absolute paths of changed files (post-gitignore filtering) */
88
+ /** Absolute paths of changed files (post-gitignore filtering). Partial when {@link incomplete}. */
89
89
  readonly paths: ReadonlySet<string>;
90
+ /**
91
+ * `true` when more paths changed than the accumulator retains, so {@link paths} is a partial set and a
92
+ * miss does NOT mean the file is unchanged. Consumers testing membership must treat this as a match.
93
+ */
94
+ readonly incomplete: boolean;
90
95
  }
@@ -1,7 +1,7 @@
1
1
  import type { RepositoryChange } from '../models/repository.js';
2
2
 
3
3
  const classifyRegex =
4
- /(worktrees|index|HEAD|FETCH_HEAD|ORIG_HEAD|CHERRY_PICK_HEAD|MERGE_HEAD|REBASE_HEAD|rebase-merge|rebase-apply|sequencer|REVERT_HEAD|config|gk\/config|info\/exclude|refs\/(?:heads|remotes|stash|tags))/;
4
+ /(worktrees|index|HEAD|FETCH_HEAD|ORIG_HEAD|CHERRY_PICK_HEAD|MERGE_HEAD|REBASE_HEAD|rebase-merge|rebase-apply|sequencer|REVERT_HEAD|config|gk\/config|info\/exclude|refs\/(?:heads|remotes|stash|tags)|packed-refs)/;
5
5
 
6
6
  /**
7
7
  * Maps a path relative to a `.git` directory to the corresponding
@@ -69,6 +69,13 @@ export function classifyGitDirChange(relativePath: string): RepositoryChange[] |
69
69
  case 'sequencer':
70
70
  return ['pausedOp'];
71
71
 
72
+ // `'heads'` is deliberately the ONLY thing a `refs/heads/*` event yields, including a create. It is
73
+ // tempting to read a create as "a new branch exists under this name" and use it to drop anything
74
+ // derived from the old branch's identity (its base, its merge target). That signal does not mean
75
+ // what it looks like: git rewrites an EXISTING loose ref by writing `<name>.lock` and renaming it
76
+ // over the file, which watchers report as a create of the destination — so every ordinary commit
77
+ // would look like a new branch and discard a live branch's metadata. Nothing here can distinguish
78
+ // the two; identity changes are handled where GitLens performs the operation itself.
72
79
  case 'refs/heads':
73
80
  return ['heads'];
74
81
 
@@ -81,6 +88,13 @@ export function classifyGitDirChange(relativePath: string): RepositoryChange[] |
81
88
  case 'refs/tags':
82
89
  return ['tags'];
83
90
 
91
+ // A `packed-refs` rewrite (after `git pack-refs` or `git gc`) changes ref state
92
+ // WITHOUT any `refs/**` file event — deleting a packed branch, for example, only
93
+ // rewrites this file. The file content is not inspected here, so classification
94
+ // is deliberately broad: it can add, remove, or move refs of any of these types.
95
+ case 'packed-refs':
96
+ return ['heads', 'remotes', 'tags'];
97
+
84
98
  case 'worktrees':
85
99
  return ['worktrees'];
86
100
 
@@ -11,6 +11,13 @@ import type { WatchGroupHooks } from './watchGroup.js';
11
11
  import { WatchGroup } from './watchGroup.js';
12
12
  import { RepositoryWatchSession } from './watchSession.js';
13
13
 
14
+ /**
15
+ * Cap on paths held while the gitignore filter loads. Higher than the session's own cap because these are
16
+ * pre-filter — most of a build's output is typically gitignored and would be discarded on replay, so a
17
+ * tighter bound here would mark batches incomplete when they filter down to almost nothing.
18
+ */
19
+ const maxBufferedWorkingTreePaths = 5000;
20
+
14
21
  export interface WatchServiceOptions {
15
22
  readonly watchingProvider: FileWatchingProvider;
16
23
  /** Default debounce for repo changes when subscriber doesn't specify. Default: 250ms */
@@ -308,6 +315,7 @@ export class RepositoryWatchService implements UnifiedDisposable {
308
315
  // Buffer events while the gitignore filter loads, then replay
309
316
  let filterReady = filter == null;
310
317
  let buffered: string[] | undefined = filter != null ? [] : undefined;
318
+ let bufferIncomplete = false;
311
319
 
312
320
  if (filter != null) {
313
321
  void filter
@@ -316,11 +324,12 @@ export class RepositoryWatchService implements UnifiedDisposable {
316
324
  filterReady = true;
317
325
  if (buffered?.length) {
318
326
  const paths = filterWorkingTreePaths(buffered, repoPath, filter);
319
- if (paths.length > 0) {
320
- session.pushWorkingTreeChanges(paths);
327
+ if (paths.length > 0 || bufferIncomplete) {
328
+ session.pushWorkingTreeChanges(paths, bufferIncomplete);
321
329
  }
322
330
  }
323
331
  buffered = undefined;
332
+ bufferIncomplete = false;
324
333
  })
325
334
  .catch(() => {
326
335
  filterReady = true;
@@ -351,7 +360,15 @@ export class RepositoryWatchService implements UnifiedDisposable {
351
360
  }
352
361
 
353
362
  if (!filterReady) {
354
- // Buffer until gitignore filter is ready
363
+ // Buffer until the gitignore filter is ready. Capped: `ready()` awaits a `core.excludesFile`
364
+ // read, which queues behind every other git command, so this window can stay open for a long
365
+ // time — and these paths haven't been gitignore-filtered yet, so a build's output all lands
366
+ // here. Past the cap, stop retaining and mark the batch partial rather than growing.
367
+ if (buffered != null && buffered.length >= maxBufferedWorkingTreePaths) {
368
+ bufferIncomplete = true;
369
+ return;
370
+ }
371
+
355
372
  buffered?.push(event.path);
356
373
  return;
357
374
  }