@gitkraken/core-gitlens 0.3.0 → 0.4.0

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 (378) hide show
  1. package/CHANGELOG.md +20 -1
  2. package/README.md +13 -10
  3. package/dist/git/cache.d.ts +12 -6
  4. package/dist/git/cache.d.ts.map +1 -1
  5. package/dist/git/cache.js +40 -39
  6. package/dist/git/cache.js.map +1 -1
  7. package/dist/git/context.d.ts +23 -3
  8. package/dist/git/context.d.ts.map +1 -1
  9. package/dist/git/context.js.map +1 -1
  10. package/dist/git/features.d.ts +1 -1
  11. package/dist/git/features.d.ts.map +1 -1
  12. package/dist/git/features.js +1 -0
  13. package/dist/git/features.js.map +1 -1
  14. package/dist/git/models/graph.d.ts +96 -0
  15. package/dist/git/models/graph.d.ts.map +1 -1
  16. package/dist/git/models/graph.js +24 -1
  17. package/dist/git/models/graph.js.map +1 -1
  18. package/dist/git/models/remoteProvider.d.ts +1 -0
  19. package/dist/git/models/remoteProvider.d.ts.map +1 -1
  20. package/dist/git/models/remoteProvider.js.map +1 -1
  21. package/dist/git/models/repository.d.ts +21 -12
  22. package/dist/git/models/repository.d.ts.map +1 -1
  23. package/dist/git/models/repository.js +70 -84
  24. package/dist/git/models/repository.js.map +1 -1
  25. package/dist/git/models/statusFile.d.ts +9 -0
  26. package/dist/git/models/statusFile.d.ts.map +1 -1
  27. package/dist/git/models/statusFile.js +11 -0
  28. package/dist/git/models/statusFile.js.map +1 -1
  29. package/dist/git/providers/commits.d.ts +4 -0
  30. package/dist/git/providers/commits.d.ts.map +1 -1
  31. package/dist/git/providers/config.d.ts +1 -3
  32. package/dist/git/providers/config.d.ts.map +1 -1
  33. package/dist/git/providers/operations.d.ts +40 -13
  34. package/dist/git/providers/operations.d.ts.map +1 -1
  35. package/dist/git/providers/worktrees.d.ts +2 -0
  36. package/dist/git/providers/worktrees.d.ts.map +1 -1
  37. package/dist/git/remotes/custom.d.ts +2 -0
  38. package/dist/git/remotes/custom.d.ts.map +1 -1
  39. package/dist/git/remotes/custom.js +20 -0
  40. package/dist/git/remotes/custom.js.map +1 -1
  41. package/dist/git/utils/conflictResolution.utils.d.ts +32 -0
  42. package/dist/git/utils/conflictResolution.utils.d.ts.map +1 -1
  43. package/dist/git/utils/conflictResolution.utils.js +95 -0
  44. package/dist/git/utils/conflictResolution.utils.js.map +1 -1
  45. package/dist/git/utils/contributor.utils.d.ts +3 -0
  46. package/dist/git/utils/contributor.utils.d.ts.map +1 -1
  47. package/dist/git/utils/contributor.utils.js +22 -0
  48. package/dist/git/utils/contributor.utils.js.map +1 -1
  49. package/dist/git/utils/reachability.utils.d.ts +37 -0
  50. package/dist/git/utils/reachability.utils.d.ts.map +1 -0
  51. package/dist/git/utils/reachability.utils.js +96 -0
  52. package/dist/git/utils/reachability.utils.js.map +1 -0
  53. package/dist/git/watching/watchService.d.ts +4 -2
  54. package/dist/git/watching/watchService.d.ts.map +1 -1
  55. package/dist/git/watching/watchService.js +8 -3
  56. package/dist/git/watching/watchService.js.map +1 -1
  57. package/dist/git/watching/watchSession.d.ts +14 -12
  58. package/dist/git/watching/watchSession.d.ts.map +1 -1
  59. package/dist/git/watching/watchSession.js +56 -55
  60. package/dist/git/watching/watchSession.js.map +1 -1
  61. package/dist/git-cli/providers/branches.d.ts.map +1 -1
  62. package/dist/git-cli/providers/branches.js +1 -0
  63. package/dist/git-cli/providers/branches.js.map +1 -1
  64. package/dist/git-cli/providers/commits.d.ts +1 -0
  65. package/dist/git-cli/providers/commits.d.ts.map +1 -1
  66. package/dist/git-cli/providers/commits.js +12 -0
  67. package/dist/git-cli/providers/commits.js.map +1 -1
  68. package/dist/git-cli/providers/config.d.ts +8 -4
  69. package/dist/git-cli/providers/config.d.ts.map +1 -1
  70. package/dist/git-cli/providers/config.js +62 -39
  71. package/dist/git-cli/providers/config.js.map +1 -1
  72. package/dist/git-cli/providers/diff.d.ts.map +1 -1
  73. package/dist/git-cli/providers/diff.js +1 -1
  74. package/dist/git-cli/providers/diff.js.map +1 -1
  75. package/dist/git-cli/providers/graph.d.ts.map +1 -1
  76. package/dist/git-cli/providers/graph.js +132 -14
  77. package/dist/git-cli/providers/graph.js.map +1 -1
  78. package/dist/git-cli/providers/operations.d.ts +7 -5
  79. package/dist/git-cli/providers/operations.d.ts.map +1 -1
  80. package/dist/git-cli/providers/operations.js +118 -95
  81. package/dist/git-cli/providers/operations.js.map +1 -1
  82. package/dist/git-cli/providers/stash.d.ts.map +1 -1
  83. package/dist/git-cli/providers/stash.js +20 -2
  84. package/dist/git-cli/providers/stash.js.map +1 -1
  85. package/dist/git-cli/providers/status.d.ts.map +1 -1
  86. package/dist/git-cli/providers/status.js +5 -2
  87. package/dist/git-cli/providers/status.js.map +1 -1
  88. package/dist/git-cli/providers/worktrees.d.ts +2 -0
  89. package/dist/git-cli/providers/worktrees.d.ts.map +1 -1
  90. package/dist/git-cli/providers/worktrees.js +3 -0
  91. package/dist/git-cli/providers/worktrees.js.map +1 -1
  92. package/dist/ipc/discovery.d.ts +22 -0
  93. package/dist/ipc/discovery.d.ts.map +1 -1
  94. package/dist/ipc/discovery.js +111 -2
  95. package/dist/ipc/discovery.js.map +1 -1
  96. package/dist/plus/agents/providers/claudeCodeProvider.d.ts +73 -20
  97. package/dist/plus/agents/providers/claudeCodeProvider.d.ts.map +1 -1
  98. package/dist/plus/agents/providers/claudeCodeProvider.js +394 -88
  99. package/dist/plus/agents/providers/claudeCodeProvider.js.map +1 -1
  100. package/dist/plus/agents/types.d.ts +62 -11
  101. package/dist/plus/agents/types.d.ts.map +1 -1
  102. package/dist/plus/ai/models/model.d.ts +1 -1
  103. package/dist/plus/ai/models/model.d.ts.map +1 -1
  104. package/dist/plus/ai/models/model.js.map +1 -1
  105. package/dist/plus/ai/models/provider.d.ts +3 -0
  106. package/dist/plus/ai/models/provider.d.ts.map +1 -1
  107. package/dist/plus/ai/providers/gitkrakenProvider.d.ts +1 -1
  108. package/dist/plus/ai/providers/gitkrakenProvider.d.ts.map +1 -1
  109. package/dist/plus/ai/providers/gitkrakenProvider.js +4 -1
  110. package/dist/plus/ai/providers/gitkrakenProvider.js.map +1 -1
  111. package/dist/plus/ai/providers/openAICompatibleProviderBase.d.ts +4 -3
  112. package/dist/plus/ai/providers/openAICompatibleProviderBase.d.ts.map +1 -1
  113. package/dist/plus/ai/providers/openAICompatibleProviderBase.js +9 -6
  114. package/dist/plus/ai/providers/openAICompatibleProviderBase.js.map +1 -1
  115. package/dist/plus/ai/utils/ai.utils.d.ts.map +1 -1
  116. package/dist/plus/ai/utils/ai.utils.js +6 -4
  117. package/dist/plus/ai/utils/ai.utils.js.map +1 -1
  118. package/dist/plus/git-github/api/github.d.ts +8 -13
  119. package/dist/plus/git-github/api/github.d.ts.map +1 -1
  120. package/dist/plus/git-github/api/github.js +96 -14
  121. package/dist/plus/git-github/api/github.js.map +1 -1
  122. package/dist/plus/git-github/providers/github/refs.js +1 -1
  123. package/dist/plus/integrations/authentication/cloudIntegrationService.d.ts +11 -0
  124. package/dist/plus/integrations/authentication/cloudIntegrationService.d.ts.map +1 -0
  125. package/dist/plus/integrations/authentication/cloudIntegrationService.js +90 -0
  126. package/dist/plus/integrations/authentication/cloudIntegrationService.js.map +1 -0
  127. package/dist/plus/integrations/authentication/configuredIntegrationService.d.ts +67 -0
  128. package/dist/plus/integrations/authentication/configuredIntegrationService.d.ts.map +1 -0
  129. package/dist/plus/integrations/authentication/configuredIntegrationService.js +295 -0
  130. package/dist/plus/integrations/authentication/configuredIntegrationService.js.map +1 -0
  131. package/dist/plus/integrations/authentication/integrationAuthenticationProvider.d.ts +92 -0
  132. package/dist/plus/integrations/authentication/integrationAuthenticationProvider.d.ts.map +1 -0
  133. package/dist/plus/integrations/authentication/integrationAuthenticationProvider.js +185 -0
  134. package/dist/plus/integrations/authentication/integrationAuthenticationProvider.js.map +1 -0
  135. package/dist/plus/integrations/authentication/integrationAuthenticationService.d.ts +62 -0
  136. package/dist/plus/integrations/authentication/integrationAuthenticationService.d.ts.map +1 -0
  137. package/dist/plus/integrations/authentication/integrationAuthenticationService.js +122 -0
  138. package/dist/plus/integrations/authentication/integrationAuthenticationService.js.map +1 -0
  139. package/dist/plus/integrations/authentication/manualTokenProvider.d.ts +15 -0
  140. package/dist/plus/integrations/authentication/manualTokenProvider.d.ts.map +1 -0
  141. package/dist/plus/integrations/authentication/manualTokenProvider.js +49 -0
  142. package/dist/plus/integrations/authentication/manualTokenProvider.js.map +1 -0
  143. package/dist/plus/integrations/authentication/models.d.ts +87 -0
  144. package/dist/plus/integrations/authentication/models.d.ts.map +1 -0
  145. package/dist/plus/integrations/authentication/models.js +64 -0
  146. package/dist/plus/integrations/authentication/models.js.map +1 -0
  147. package/dist/plus/integrations/constants.d.ts +47 -0
  148. package/dist/plus/integrations/constants.d.ts.map +1 -0
  149. package/dist/plus/integrations/constants.js +128 -0
  150. package/dist/plus/integrations/constants.js.map +1 -0
  151. package/dist/plus/integrations/context.d.ts +354 -0
  152. package/dist/plus/integrations/context.d.ts.map +1 -0
  153. package/dist/plus/integrations/context.js +2 -0
  154. package/dist/plus/integrations/context.js.map +1 -0
  155. package/dist/plus/integrations/errors.d.ts +14 -0
  156. package/dist/plus/integrations/errors.d.ts.map +1 -0
  157. package/dist/plus/integrations/errors.js +19 -0
  158. package/dist/plus/integrations/errors.js.map +1 -0
  159. package/dist/plus/integrations/index.d.ts +32 -0
  160. package/dist/plus/integrations/index.d.ts.map +1 -0
  161. package/dist/plus/integrations/index.js +62 -0
  162. package/dist/plus/integrations/index.js.map +1 -0
  163. package/dist/plus/integrations/integrationService.d.ts +98 -0
  164. package/dist/plus/integrations/integrationService.d.ts.map +1 -0
  165. package/dist/plus/integrations/integrationService.js +627 -0
  166. package/dist/plus/integrations/integrationService.js.map +1 -0
  167. package/dist/plus/integrations/models/gitHostIntegration.d.ts +82 -0
  168. package/dist/plus/integrations/models/gitHostIntegration.d.ts.map +1 -0
  169. package/dist/plus/integrations/models/gitHostIntegration.js +522 -0
  170. package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -0
  171. package/dist/plus/integrations/models/integration.d.ts +127 -0
  172. package/dist/plus/integrations/models/integration.d.ts.map +1 -0
  173. package/dist/plus/integrations/models/integration.js +456 -0
  174. package/dist/plus/integrations/models/integration.js.map +1 -0
  175. package/dist/plus/integrations/models/issuesIntegration.d.ts +28 -0
  176. package/dist/plus/integrations/models/issuesIntegration.d.ts.map +1 -0
  177. package/dist/plus/integrations/models/issuesIntegration.js +101 -0
  178. package/dist/plus/integrations/models/issuesIntegration.js.map +1 -0
  179. package/dist/plus/integrations/providers/apiClients.d.ts +25 -0
  180. package/dist/plus/integrations/providers/apiClients.d.ts.map +1 -0
  181. package/dist/plus/integrations/providers/apiClients.js +39 -0
  182. package/dist/plus/integrations/providers/apiClients.js.map +1 -0
  183. package/dist/plus/integrations/providers/azure/azure.d.ts +47 -0
  184. package/dist/plus/integrations/providers/azure/azure.d.ts.map +1 -0
  185. package/dist/plus/integrations/providers/azure/azure.js +444 -0
  186. package/dist/plus/integrations/providers/azure/azure.js.map +1 -0
  187. package/dist/plus/integrations/providers/azure/models.d.ts +286 -0
  188. package/dist/plus/integrations/providers/azure/models.d.ts.map +1 -0
  189. package/dist/plus/integrations/providers/azure/models.js +203 -0
  190. package/dist/plus/integrations/providers/azure/models.js.map +1 -0
  191. package/dist/plus/integrations/providers/azureDevOps.d.ts +95 -0
  192. package/dist/plus/integrations/providers/azureDevOps.d.ts.map +1 -0
  193. package/dist/plus/integrations/providers/azureDevOps.js +432 -0
  194. package/dist/plus/integrations/providers/azureDevOps.js.map +1 -0
  195. package/dist/plus/integrations/providers/bitbucket/bitbucket.d.ts +42 -0
  196. package/dist/plus/integrations/providers/bitbucket/bitbucket.d.ts.map +1 -0
  197. package/dist/plus/integrations/providers/bitbucket/bitbucket.js +513 -0
  198. package/dist/plus/integrations/providers/bitbucket/bitbucket.js.map +1 -0
  199. package/dist/plus/integrations/providers/bitbucket/models.d.ts +222 -0
  200. package/dist/plus/integrations/providers/bitbucket/models.d.ts.map +1 -0
  201. package/dist/plus/integrations/providers/bitbucket/models.js +158 -0
  202. package/dist/plus/integrations/providers/bitbucket/models.js.map +1 -0
  203. package/dist/plus/integrations/providers/bitbucket-server/models.d.ts +120 -0
  204. package/dist/plus/integrations/providers/bitbucket-server/models.d.ts.map +1 -0
  205. package/dist/plus/integrations/providers/bitbucket-server/models.js +111 -0
  206. package/dist/plus/integrations/providers/bitbucket-server/models.js.map +1 -0
  207. package/dist/plus/integrations/providers/bitbucket-server.d.ts +60 -0
  208. package/dist/plus/integrations/providers/bitbucket-server.d.ts.map +1 -0
  209. package/dist/plus/integrations/providers/bitbucket-server.js +138 -0
  210. package/dist/plus/integrations/providers/bitbucket-server.js.map +1 -0
  211. package/dist/plus/integrations/providers/bitbucket.d.ts +50 -0
  212. package/dist/plus/integrations/providers/bitbucket.d.ts.map +1 -0
  213. package/dist/plus/integrations/providers/bitbucket.js +181 -0
  214. package/dist/plus/integrations/providers/bitbucket.js.map +1 -0
  215. package/dist/plus/integrations/providers/github/github.d.ts +5 -0
  216. package/dist/plus/integrations/providers/github/github.d.ts.map +1 -0
  217. package/dist/plus/integrations/providers/github/github.js +47 -0
  218. package/dist/plus/integrations/providers/github/github.js.map +1 -0
  219. package/dist/plus/integrations/providers/github/github.utils.d.ts +11 -0
  220. package/dist/plus/integrations/providers/github/github.utils.d.ts.map +1 -0
  221. package/dist/plus/integrations/providers/github/github.utils.js +6 -0
  222. package/dist/plus/integrations/providers/github/github.utils.js.map +1 -0
  223. package/dist/plus/integrations/providers/github/models.d.ts +3 -0
  224. package/dist/plus/integrations/providers/github/models.d.ts.map +1 -0
  225. package/dist/plus/integrations/providers/github/models.js +2 -0
  226. package/dist/plus/integrations/providers/github/models.js.map +1 -0
  227. package/dist/plus/integrations/providers/github.d.ts +73 -0
  228. package/dist/plus/integrations/providers/github.d.ts.map +1 -0
  229. package/dist/plus/integrations/providers/github.js +160 -0
  230. package/dist/plus/integrations/providers/github.js.map +1 -0
  231. package/dist/plus/integrations/providers/gitlab/gitlab.d.ts +63 -0
  232. package/dist/plus/integrations/providers/gitlab/gitlab.d.ts.map +1 -0
  233. package/dist/plus/integrations/providers/gitlab/gitlab.js +828 -0
  234. package/dist/plus/integrations/providers/gitlab/gitlab.js.map +1 -0
  235. package/dist/plus/integrations/providers/gitlab/gitlab.utils.d.ts +21 -0
  236. package/dist/plus/integrations/providers/gitlab/gitlab.utils.d.ts.map +1 -0
  237. package/dist/plus/integrations/providers/gitlab/gitlab.utils.js +45 -0
  238. package/dist/plus/integrations/providers/gitlab/gitlab.utils.js.map +1 -0
  239. package/dist/plus/integrations/providers/gitlab/models.d.ts +128 -0
  240. package/dist/plus/integrations/providers/gitlab/models.d.ts.map +1 -0
  241. package/dist/plus/integrations/providers/gitlab/models.js +96 -0
  242. package/dist/plus/integrations/providers/gitlab/models.js.map +1 -0
  243. package/dist/plus/integrations/providers/gitlab.d.ts +79 -0
  244. package/dist/plus/integrations/providers/gitlab.d.ts.map +1 -0
  245. package/dist/plus/integrations/providers/gitlab.js +253 -0
  246. package/dist/plus/integrations/providers/gitlab.js.map +1 -0
  247. package/dist/plus/integrations/providers/jira.d.ts +46 -0
  248. package/dist/plus/integrations/providers/jira.d.ts.map +1 -0
  249. package/dist/plus/integrations/providers/jira.js +255 -0
  250. package/dist/plus/integrations/providers/jira.js.map +1 -0
  251. package/dist/plus/integrations/providers/linear.d.ts +47 -0
  252. package/dist/plus/integrations/providers/linear.d.ts.map +1 -0
  253. package/dist/plus/integrations/providers/linear.js +198 -0
  254. package/dist/plus/integrations/providers/linear.js.map +1 -0
  255. package/dist/plus/integrations/providers/models.d.ts +433 -0
  256. package/dist/plus/integrations/providers/models.d.ts.map +1 -0
  257. package/dist/plus/integrations/providers/models.js +602 -0
  258. package/dist/plus/integrations/providers/models.js.map +1 -0
  259. package/dist/plus/integrations/providers/providersApi.d.ts +129 -0
  260. package/dist/plus/integrations/providers/providersApi.d.ts.map +1 -0
  261. package/dist/plus/integrations/providers/providersApi.js +602 -0
  262. package/dist/plus/integrations/providers/providersApi.js.map +1 -0
  263. package/dist/plus/integrations/providers/utils.d.ts +54 -0
  264. package/dist/plus/integrations/providers/utils.d.ts.map +1 -0
  265. package/dist/plus/integrations/providers/utils.js +262 -0
  266. package/dist/plus/integrations/providers/utils.js.map +1 -0
  267. package/dist/plus/integrations/telemetry.d.ts +26 -0
  268. package/dist/plus/integrations/telemetry.d.ts.map +1 -0
  269. package/dist/plus/integrations/telemetry.js +11 -0
  270. package/dist/plus/integrations/telemetry.js.map +1 -0
  271. package/dist/plus/integrations/utils/integration.utils.d.ts +14 -0
  272. package/dist/plus/integrations/utils/integration.utils.d.ts.map +1 -0
  273. package/dist/plus/integrations/utils/integration.utils.js +111 -0
  274. package/dist/plus/integrations/utils/integration.utils.js.map +1 -0
  275. package/dist/utils/date.d.ts.map +1 -1
  276. package/dist/utils/date.js +6 -0
  277. package/dist/utils/date.js.map +1 -1
  278. package/dist/utils/debounce.js +1 -1
  279. package/dist/utils/disposable.d.ts +15 -2
  280. package/dist/utils/disposable.d.ts.map +1 -1
  281. package/dist/utils/disposable.js.map +1 -1
  282. package/dist/utils/iterable.d.ts +7 -1
  283. package/dist/utils/iterable.d.ts.map +1 -1
  284. package/dist/utils/iterable.js +12 -4
  285. package/dist/utils/iterable.js.map +1 -1
  286. package/dist/utils/object.d.ts +22 -1
  287. package/dist/utils/object.d.ts.map +1 -1
  288. package/dist/utils/object.js +56 -3
  289. package/dist/utils/object.js.map +1 -1
  290. package/dist/utils/paging.js +14 -15
  291. package/dist/utils/paging.js.map +1 -1
  292. package/dist/utils/promiseCache.d.ts.map +1 -1
  293. package/dist/utils/promiseCache.js +12 -4
  294. package/dist/utils/promiseCache.js.map +1 -1
  295. package/dist/utils/string.js +1 -1
  296. package/package.json +43 -2
  297. package/src/git/cache.ts +58 -70
  298. package/src/git/context.ts +25 -3
  299. package/src/git/features.ts +2 -0
  300. package/src/git/models/graph.ts +97 -0
  301. package/src/git/models/remoteProvider.ts +1 -0
  302. package/src/git/models/repository.ts +84 -93
  303. package/src/git/models/statusFile.ts +12 -0
  304. package/src/git/providers/commits.ts +4 -0
  305. package/src/git/providers/config.ts +1 -5
  306. package/src/git/providers/operations.ts +42 -22
  307. package/src/git/providers/worktrees.ts +14 -2
  308. package/src/git/remotes/custom.ts +23 -0
  309. package/src/git/utils/conflictResolution.utils.ts +126 -0
  310. package/src/git/utils/contributor.utils.ts +24 -0
  311. package/src/git/utils/reachability.utils.ts +109 -0
  312. package/src/git/watching/watchService.ts +9 -4
  313. package/src/git/watching/watchSession.ts +61 -55
  314. package/src/git-cli/providers/branches.ts +1 -0
  315. package/src/git-cli/providers/commits.ts +24 -0
  316. package/src/git-cli/providers/config.ts +63 -49
  317. package/src/git-cli/providers/diff.ts +2 -1
  318. package/src/git-cli/providers/graph.ts +145 -14
  319. package/src/git-cli/providers/operations.ts +138 -130
  320. package/src/git-cli/providers/stash.ts +20 -2
  321. package/src/git-cli/providers/status.ts +11 -3
  322. package/src/git-cli/providers/worktrees.ts +17 -2
  323. package/src/ipc/discovery.ts +132 -2
  324. package/src/plus/agents/providers/claudeCodeProvider.ts +430 -90
  325. package/src/plus/agents/types.ts +59 -11
  326. package/src/plus/ai/models/model.ts +1 -0
  327. package/src/plus/ai/models/provider.ts +7 -1
  328. package/src/plus/ai/providers/gitkrakenProvider.ts +4 -0
  329. package/src/plus/ai/providers/openAICompatibleProviderBase.ts +21 -4
  330. package/src/plus/ai/utils/ai.utils.ts +6 -4
  331. package/src/plus/git-github/api/github.ts +131 -31
  332. package/src/plus/git-github/providers/github/refs.ts +1 -1
  333. package/src/plus/integrations/authentication/cloudIntegrationService.ts +120 -0
  334. package/src/plus/integrations/authentication/configuredIntegrationService.ts +414 -0
  335. package/src/plus/integrations/authentication/integrationAuthenticationProvider.ts +289 -0
  336. package/src/plus/integrations/authentication/integrationAuthenticationService.ts +144 -0
  337. package/src/plus/integrations/authentication/manualTokenProvider.ts +72 -0
  338. package/src/plus/integrations/authentication/models.ts +168 -0
  339. package/src/plus/integrations/constants.ts +169 -0
  340. package/src/plus/integrations/context.ts +383 -0
  341. package/src/plus/integrations/errors.ts +35 -0
  342. package/src/plus/integrations/index.ts +119 -0
  343. package/src/plus/integrations/integrationService.ts +924 -0
  344. package/src/plus/integrations/models/gitHostIntegration.ts +738 -0
  345. package/src/plus/integrations/models/integration.ts +657 -0
  346. package/src/plus/integrations/models/issuesIntegration.ts +124 -0
  347. package/src/plus/integrations/providers/apiClients.ts +72 -0
  348. package/src/plus/integrations/providers/azure/azure.ts +691 -0
  349. package/src/plus/integrations/providers/azure/models.ts +605 -0
  350. package/src/plus/integrations/providers/azureDevOps.ts +677 -0
  351. package/src/plus/integrations/providers/bitbucket/bitbucket.ts +774 -0
  352. package/src/plus/integrations/providers/bitbucket/models.ts +445 -0
  353. package/src/plus/integrations/providers/bitbucket-server/models.ts +252 -0
  354. package/src/plus/integrations/providers/bitbucket-server.ts +282 -0
  355. package/src/plus/integrations/providers/bitbucket.ts +350 -0
  356. package/src/plus/integrations/providers/github/github.ts +64 -0
  357. package/src/plus/integrations/providers/github/github.utils.ts +23 -0
  358. package/src/plus/integrations/providers/github/models.ts +29 -0
  359. package/src/plus/integrations/providers/github.ts +366 -0
  360. package/src/plus/integrations/providers/gitlab/gitlab.ts +1210 -0
  361. package/src/plus/integrations/providers/gitlab/gitlab.utils.ts +71 -0
  362. package/src/plus/integrations/providers/gitlab/models.ts +257 -0
  363. package/src/plus/integrations/providers/gitlab.ts +473 -0
  364. package/src/plus/integrations/providers/jira.ts +359 -0
  365. package/src/plus/integrations/providers/linear.ts +275 -0
  366. package/src/plus/integrations/providers/models.ts +1114 -0
  367. package/src/plus/integrations/providers/providersApi.ts +1126 -0
  368. package/src/plus/integrations/providers/utils.ts +359 -0
  369. package/src/plus/integrations/telemetry.ts +29 -0
  370. package/src/plus/integrations/utils/integration.utils.ts +138 -0
  371. package/src/utils/date.ts +5 -0
  372. package/src/utils/debounce.ts +1 -1
  373. package/src/utils/disposable.ts +15 -2
  374. package/src/utils/iterable.ts +14 -3
  375. package/src/utils/object.ts +55 -4
  376. package/src/utils/paging.ts +14 -14
  377. package/src/utils/promiseCache.ts +24 -16
  378. package/src/utils/string.ts +1 -1
@@ -32,9 +32,9 @@ import {
32
32
  getRemoteNameFromBranchName,
33
33
  } from '../../git/utils/branch.utils.js';
34
34
  import { getChangedFilesCount } from '../../git/utils/commit.utils.js';
35
+ import { createReachabilityTableBuilder } from '../../git/utils/reachability.utils.js';
35
36
  import { isUncommitted } from '../../git/utils/revision.utils.js';
36
37
  import { getSearchQueryComparisonKey, parseSearchQueryGitCommand } from '../../git/utils/search.utils.js';
37
- import { compareReachableRefs } from '../../git/utils/sorting.js';
38
38
  import { getTagId } from '../../git/utils/tag.utils.js';
39
39
  import { isUserMatch } from '../../git/utils/user.utils.js';
40
40
  import { getWorktreeId, groupWorktreesByBranch } from '../../git/utils/worktree.utils.js';
@@ -119,9 +119,14 @@ export class GraphGitSubProvider implements GitGraphSubProvider {
119
119
  const [worktrees, worktreesByBranch] = getSettledValue(worktreesResult) ?? [[], new Map<string, GitWorktree>()];
120
120
 
121
121
  let branchIdOfMainWorktree: string | undefined;
122
+ let mainWorktree: GitWorktree | undefined;
122
123
  if (worktreesByBranch != null) {
123
- branchIdOfMainWorktree = find(worktreesByBranch, ([, wt]) => wt.isDefault)?.[0];
124
- if (branchIdOfMainWorktree != null) {
124
+ const defaultEntry = find(worktreesByBranch, ([, wt]) => wt.isDefault);
125
+ if (defaultEntry != null) {
126
+ [branchIdOfMainWorktree, mainWorktree] = defaultEntry;
127
+ // Remove the main/default worktree so the branch-row decoration shows `+checkedout`
128
+ // (not `+worktree`) for the main checkout. `mainWorktree` is retained below purely so
129
+ // Undo Commit can still reach the main worktree's HEAD from a secondary worktree's graph.
125
130
  worktreesByBranch.delete(branchIdOfMainWorktree);
126
131
  }
127
132
  }
@@ -142,9 +147,62 @@ export class GraphGitSubProvider implements GitGraphSubProvider {
142
147
  const avatars = new Map<string, string>();
143
148
  const ids = new Set<string>();
144
149
  const reachableFromHEAD = new Set<string>();
150
+ // SHAs on the first-parent chain from HEAD up to (excluding) the first merge commit — the only
151
+ // commits a plain (non-`--rebase-merges`) interactive rebase can safely rewrite. `headSha` seeds
152
+ // the chain; `rewriteableNextSha` tracks the next sha expected on it. Outer scope so they persist
153
+ // across `more()` pagination, like `reachableFromHEAD`.
154
+ const rewriteableFromHEAD = new Set<string>();
155
+ let headSha: string | undefined;
156
+ let rewriteableNextSha: string | undefined;
157
+ // Undo Commit is offered only on a worktree HEAD that is a LEAF (nothing is built on it) —
158
+ // undoing a commit other work is stacked on is unsafe. The leaf check is only needed for the
159
+ // undo-eligible tips (the active HEAD + each worktree's HEAD), so track just those shas rather
160
+ // than every commit, keeping this O(#worktrees) instead of O(#commits).
161
+ const undoableTipShas = new Set<string>();
162
+ if (headBranch?.sha != null) {
163
+ undoableTipShas.add(headBranch.sha);
164
+ }
165
+ for (const wt of worktrees) {
166
+ if (wt.sha != null) {
167
+ undoableTipShas.add(wt.sha);
168
+ }
169
+ }
170
+ // The subset of `undoableTipShas` that turn out to have a child (are an ancestor of another
171
+ // commit) — i.e. NOT leaves. Built newest-first during the walk, so by the time a tip's row is
172
+ // processed every newer commit (its only possible children) has been seen. Undo is withheld for
173
+ // shas recorded here. Stash rows are excluded (a stash sitting on a tip must not block undoing it).
174
+ const tipShasWithChildren = new Set<string>();
175
+ // SHAs reachable from HEAD's tracking upstream tip. Combined with `reachableFromHEAD`,
176
+ // this lets us mark commits as unpushed (reachable from HEAD but not from HEAD's upstream).
177
+ const reachableFromHeadUpstream = new Set<string>();
145
178
 
146
179
  // Map<sha, Map<refKey, ref>> — inner map deduplicates refs during propagation
147
180
  const reachableRefs = new Map<string, Map<string, ReachableRef>>();
181
+
182
+ // Stable, append-only reachability table built as we walk — the PRIMARY representation shipped to
183
+ // consumers. Lives in the outer scope so it accumulates across `more()` pagination; indices
184
+ // already assigned never change, since git reachability only propagates to older (later-walked)
185
+ // commits. Per-row ref arrays are NOT retained — each row keeps only its set index
186
+ // (`contexts.reachabilityIndex`), and the working `reachableRefs` entry is dropped once emitted.
187
+ // The encoder lives next to its decoder in `reachability.utils` so the wire format can't drift.
188
+ const reachabilityBuilder = createReachabilityTableBuilder();
189
+
190
+ function finalizeRowReachability(
191
+ row: GitGraphRow,
192
+ sha: string,
193
+ refs: Map<string, ReachableRef> | undefined,
194
+ ): void {
195
+ const setIndex = reachabilityBuilder.intern(refs?.values());
196
+ if (setIndex != null) {
197
+ (row.contexts ??= {}).reachabilityIndex = setIndex;
198
+ }
199
+ // Drop the transient per-row arrays so emitted rows don't retain reachability, and release the
200
+ // working entry — once a commit is emitted its children are all walked and its parents already
201
+ // seeded, so nothing reads `reachableRefs.get(sha)` again (orderings keep parents after children).
202
+ row.reachability = undefined;
203
+ reachableRefs.delete(sha);
204
+ }
205
+
148
206
  const rowStats: GitGraphRowsStats = new Map<string, GitGraphRowStats>();
149
207
  let pendingRowsStatsCount = 0;
150
208
  let iterations = 0;
@@ -224,6 +282,12 @@ export class GraphGitSubProvider implements GitGraphSubProvider {
224
282
  branchIdOfMainWorktree: branchIdOfMainWorktree,
225
283
  stashes: gitStash?.stashes,
226
284
  reachableFromHEAD: reachableFromHEAD,
285
+ rewriteableFromHEAD: rewriteableFromHEAD,
286
+ tipShasWithChildren: tipShasWithChildren,
287
+ // `undefined` when HEAD has no upstream, so the processor flags nothing as
288
+ // unpublished; otherwise the live set (mutated during the walk, read by ref).
289
+ reachableFromHeadUpstream:
290
+ headRefUpstreamName != null ? reachableFromHeadUpstream : undefined,
227
291
  avatars: avatars,
228
292
  }
229
293
  : undefined;
@@ -288,6 +352,7 @@ export class GraphGitSubProvider implements GitGraphSubProvider {
288
352
  if (tip.startsWith('HEAD')) {
289
353
  head = true;
290
354
  reachableFromHEAD.add(shaOrRemapped);
355
+ headSha ??= shaOrRemapped;
291
356
 
292
357
  if (tip !== 'HEAD') {
293
358
  tip = tip.substring(8);
@@ -302,12 +367,16 @@ export class GraphGitSubProvider implements GitGraphSubProvider {
302
367
  if (branchName === 'HEAD') continue;
303
368
 
304
369
  remoteBranchId = getBranchId(repoPath, true, tip);
370
+ const isHeadUpstream = tip === headRefUpstreamName;
371
+ if (isHeadUpstream) {
372
+ reachableFromHeadUpstream.add(shaOrRemapped);
373
+ }
305
374
  refRemoteHead = {
306
375
  id: remoteBranchId,
307
376
  name: branchName,
308
377
  owner: remote.name,
309
378
  url: remote.url,
310
- current: tip === headRefUpstreamName,
379
+ current: isHeadUpstream,
311
380
  hostingServiceType: remote.provider?.gkProviderId,
312
381
  };
313
382
  refRemoteHeads.push(refRemoteHead);
@@ -318,7 +387,16 @@ export class GraphGitSubProvider implements GitGraphSubProvider {
318
387
 
319
388
  branch = branchMap.get(tip);
320
389
  branchId = branch?.id ?? getBranchId(repoPath, false, tip);
321
- const worktree = worktreesByBranch?.get(branchId);
390
+ // `worktreesByBranch` has the main/default worktree removed (above), so recover it
391
+ // here — Undo Commit needs to reach the main worktree's HEAD even when the active
392
+ // workspace is a secondary worktree.
393
+ const worktree =
394
+ worktreesByBranch?.get(branchId) ??
395
+ (branchId === branchIdOfMainWorktree ? mainWorktree : undefined);
396
+ const worktreeRef =
397
+ worktree != null
398
+ ? { id: getWorktreeId(repoPath, worktree.name), path: worktree.path }
399
+ : undefined;
322
400
  refHead = {
323
401
  id: branchId,
324
402
  name: tip,
@@ -330,7 +408,12 @@ export class GraphGitSubProvider implements GitGraphSubProvider {
330
408
  id: getBranchId(repoPath, true, branch.upstream.name),
331
409
  }
332
410
  : undefined,
333
- worktreeId: worktree != null ? getWorktreeId(repoPath, worktree.name) : undefined,
411
+ worktree: worktreeRef,
412
+ // Mirror `worktree.id` for `@gitkraken/gitkraken-components` — its bundled renderer
413
+ // reads `head.worktreeId` to pick the WORKTREE vs HEAD ref-badge. Scope to NON-default
414
+ // worktrees so the main checkout keeps its HEAD badge even though `worktree` (above)
415
+ // is populated for it for Undo routing.
416
+ worktreeId: worktree?.isDefault === false ? worktreeRef?.id : undefined,
334
417
  };
335
418
  refHeads.push(refHead);
336
419
  if (branch?.upstream?.name != null) {
@@ -353,6 +436,27 @@ export class GraphGitSubProvider implements GitGraphSubProvider {
353
436
  }
354
437
  }
355
438
 
439
+ // First-parent rewriteable chain from HEAD: include each commit only while HEAD and
440
+ // every commit down to it has exactly one parent. Stops at (excludes) the first merge
441
+ // and the root — mirrors GitKraken's getDistinctCommitsFromHeadToFirstMergeCommit.
442
+ // Off-chain commits (a merge's other-parent ancestry, or anything below the first merge)
443
+ // are reachable-from-HEAD but NOT safely history-rewriteable by a plain interactive
444
+ // rebase. Relies on the same "commit emitted before its parents" ordering as above.
445
+ if (shaOrRemapped === headSha || shaOrRemapped === rewriteableNextSha) {
446
+ if (parents.length === 1) {
447
+ rewriteableFromHEAD.add(shaOrRemapped);
448
+ rewriteableNextSha = parents[0];
449
+ } else {
450
+ // A merge (>1 parents) or the root (0 parents) terminates the chain.
451
+ rewriteableNextSha = undefined;
452
+ }
453
+ }
454
+ if (reachableFromHeadUpstream.has(shaOrRemapped)) {
455
+ for (parent of parents) {
456
+ reachableFromHeadUpstream.add(parent);
457
+ }
458
+ }
459
+
356
460
  // Seed reachability from all ref types on this commit
357
461
  if (refHeads.length > 0 || refRemoteHeads.length > 0 || refTags.length > 0) {
358
462
  let refs = reachableRefs.get(shaOrRemapped);
@@ -406,12 +510,13 @@ export class GraphGitSubProvider implements GitGraphSubProvider {
406
510
  heads: refHeads,
407
511
  remotes: refRemoteHeads,
408
512
  tags: refTags,
409
- reachability: refs?.size
410
- ? { partial: true, refs: [...refs.values()].sort(compareReachableRefs) }
411
- : undefined,
513
+ // Transient: the row processor's `+unique` decision reads this; stripped just below.
514
+ // Unsorted (the consumer re-sorts after decoding) — order doesn't affect interning.
515
+ reachability: refs?.size ? { partial: true, refs: [...refs.values()] } : undefined,
412
516
  isCurrentUser: true,
413
517
  };
414
518
  rowProcessor?.processRow(row, graphCtx!);
519
+ finalizeRowReachability(row, shaOrRemapped, refs);
415
520
  rows.push(row);
416
521
 
417
522
  if (stash.stats != null) {
@@ -424,6 +529,17 @@ export class GraphGitSubProvider implements GitGraphSubProvider {
424
529
  } else {
425
530
  isCurrentUser = isUserMatch(currentUser, commit.author, commit.authorEmail);
426
531
 
532
+ // Mark any undo-eligible tip that THIS (non-stash) commit builds on as non-leaf, so
533
+ // its Undo Commit is withheld. Uses the full parent set (incl. merge second-parents)
534
+ // but only records shas that are actually undo tips — newer commits are walked first,
535
+ // so a tip is recorded before its own row is processed. Stash rows are intentionally
536
+ // not handled here, so a stash based on a tip doesn't block undoing that tip.
537
+ for (parent of parents) {
538
+ if (undoableTipShas.has(parent)) {
539
+ tipShasWithChildren.add(parent);
540
+ }
541
+ }
542
+
427
543
  const refs = reachableRefs.get(shaOrRemapped);
428
544
  const row: GitGraphRow = {
429
545
  sha: shaOrRemapped,
@@ -437,12 +553,13 @@ export class GraphGitSubProvider implements GitGraphSubProvider {
437
553
  heads: refHeads,
438
554
  remotes: refRemoteHeads,
439
555
  tags: refTags,
440
- reachability: refs?.size
441
- ? { partial: true, refs: [...refs.values()].sort(compareReachableRefs) }
442
- : undefined,
556
+ // Transient: the row processor's `+unique` decision reads this; stripped just below.
557
+ // Unsorted (the consumer re-sorts after decoding) — order doesn't affect interning.
558
+ reachability: refs?.size ? { partial: true, refs: [...refs.values()] } : undefined,
443
559
  isCurrentUser: isCurrentUser || undefined,
444
560
  };
445
561
  rowProcessor?.processRow(row, graphCtx!);
562
+ finalizeRowReachability(row, shaOrRemapped, refs);
446
563
  rows.push(row);
447
564
 
448
565
  if (commit.stats != null) {
@@ -460,7 +577,7 @@ export class GraphGitSubProvider implements GitGraphSubProvider {
460
577
  if (deferStats) {
461
578
  pendingRowsStatsCount++;
462
579
 
463
- // eslint-disable-next-line no-async-promise-executor
580
+ // oxlint-disable-next-line no-async-promise-executor
464
581
  const promise = new Promise<void>(async resolve => {
465
582
  try {
466
583
  const args = [...statsParser.arguments];
@@ -514,6 +631,8 @@ export class GraphGitSubProvider implements GitGraphSubProvider {
514
631
  worktrees: worktrees,
515
632
  worktreesByBranch: worktreesByBranch,
516
633
  reachableFromHEAD: reachableFromHEAD,
634
+ rewriteableFromHEAD: rewriteableFromHEAD,
635
+ reachability: reachabilityBuilder.build(),
517
636
  rows: rows,
518
637
  id: sha ?? rev,
519
638
  rowsStats: rowStats,
@@ -538,7 +657,19 @@ export class GraphGitSubProvider implements GitGraphSubProvider {
538
657
  }
539
658
  }
540
659
 
541
- return getCommitsForGraphCore.call(this, defaultLimit, selectSha, undefined, cancellation);
660
+ let graph = await getCommitsForGraphCore.call(this, defaultLimit, selectSha, undefined, cancellation);
661
+
662
+ // Spurious-empty guard: the repo has branches (so `git log --all` should yield commits) yet the
663
+ // log returned no rows. That's an inconsistent result — almost always a transient ref-read race
664
+ // while a concurrent git operation rewrites refs/packed-refs — not a genuinely empty repo.
665
+ // Returning it would flash "No commits" in the graph. Retry once (transient glitches clear within
666
+ // ms). A truly empty repo has no branches and is left untouched.
667
+ if (graph.rows.length === 0 && branches?.length && !cancellation?.aborted) {
668
+ scope?.warn(`graph returned 0 rows but repo has ${branches.length} branches; retrying`);
669
+ graph = await getCommitsForGraphCore.call(this, defaultLimit, selectSha, undefined, cancellation);
670
+ }
671
+
672
+ return graph;
542
673
  }
543
674
 
544
675
  @debug({
@@ -25,6 +25,7 @@ import { getBranchNameAndRemote, getBranchTrackingWithoutRemote } from '../../gi
25
25
  import { isBranchReference } from '../../git/utils/reference.utils.js';
26
26
  import { debug } from '../../utils/decorators/log.js';
27
27
  import { sequentialize } from '../../utils/decorators/sequentialize.js';
28
+ import { chunkByStringLength } from '../../utils/iterable.js';
28
29
  import { Logger } from '../../utils/logger.js';
29
30
  import { getScopedLogger } from '../../utils/logger.scoped.js';
30
31
  import { normalizePath, splitPath } from '../../utils/path.js';
@@ -51,124 +52,26 @@ export class OperationsGitSubProvider implements GitOperationsSubProvider {
51
52
  async checkout(
52
53
  repoPath: string,
53
54
  ref: string,
54
- options?: { createBranch?: string } | { path?: string },
55
+ options?: { createBranch?: string; noTracking?: boolean },
55
56
  runOptions?: GitOperationRunOptions,
56
57
  ): Promise<void> {
57
58
  const scope = getScopedLogger();
58
59
 
59
- try {
60
- await this.checkoutCore(repoPath, ref, options, runOptions);
61
- this.context.hooks?.cache?.onReset?.(repoPath, 'branches', 'status');
62
- this.context.hooks?.repository?.onChanged?.(repoPath, ['head', 'heads', 'index']);
63
- } catch (ex) {
64
- scope?.error(ex);
65
- throw ex;
66
- }
67
- }
68
-
69
- private async checkoutCore(
70
- repoPath: string,
71
- ref: string,
72
- { createBranch, path }: { createBranch?: string; path?: string } = {},
73
- runOptions?: GitOperationRunOptions,
74
- ): Promise<void> {
75
60
  const params = ['checkout'];
76
- if (createBranch) {
77
- params.push('-b', createBranch, ref, '--');
61
+ if (options?.createBranch) {
62
+ params.push('-b', options.createBranch);
63
+ if (options.noTracking) {
64
+ params.push('--no-track');
65
+ }
66
+ params.push(ref, '--');
78
67
  } else {
79
68
  params.push(ref, '--');
80
-
81
- if (path) {
82
- [path, repoPath] = splitPath(path, repoPath, true);
83
- params.push(path);
84
- }
85
- }
86
-
87
- try {
88
- await this.git.run({ cwd: repoPath, ...runOptions }, ...params);
89
- } catch (ex) {
90
- throw getGitCommandError(
91
- 'checkout',
92
- ex,
93
- reason =>
94
- new CheckoutError(
95
- { reason: reason ?? 'other', ref: ref, gitCommand: { repoPath: repoPath, args: params } },
96
- ex,
97
- ),
98
- );
99
- }
100
- }
101
-
102
- @debug()
103
- async checkoutConflictedPath(
104
- repoPath: string,
105
- path: string,
106
- side: 'ours' | 'theirs',
107
- runOptions?: GitOperationRunOptions,
108
- ): Promise<void> {
109
- const scope = getScopedLogger();
110
-
111
- [path, repoPath] = splitPath(path, repoPath, true);
112
- const params = ['checkout', `--${side}`, '--', path];
113
-
114
- try {
115
- await this.git.run({ cwd: repoPath, ...runOptions }, ...params);
116
- this.context.hooks?.cache?.onReset?.(repoPath, 'status');
117
- this.context.hooks?.repository?.onChanged?.(repoPath, ['index']);
118
- } catch (ex) {
119
- scope?.error(ex);
120
- throw getGitCommandError(
121
- 'checkout',
122
- ex,
123
- reason =>
124
- new CheckoutError(
125
- { reason: reason ?? 'other', ref: side, gitCommand: { repoPath: repoPath, args: params } },
126
- ex,
127
- ),
128
- );
129
- }
130
- }
131
-
132
- @debug()
133
- async checkoutConflictedPaths(
134
- repoPath: string,
135
- paths: string[],
136
- side: 'ours' | 'theirs',
137
- runOptions?: GitOperationRunOptions,
138
- ): Promise<void> {
139
- if (!paths.length) return;
140
-
141
- const scope = getScopedLogger();
142
- const normalized = paths.map(p => splitPath(p, repoPath, true)[0]);
143
-
144
- // Build batches by accumulating the length of each path + a small per-arg overhead (separator +
145
- // possible quoting), so a single long path — or just the overhead itself — can't push a batch
146
- // past the CLI length limit. Always keep at least one path per batch, even if a lone path is
147
- // longer than the limit (the OS may still accept it on some platforms).
148
- const perArgOverhead = 3;
149
- const batches: string[][] = [];
150
- let current: string[] = [];
151
- let currentLen = 0;
152
- for (const p of normalized) {
153
- const cost = p.length + perArgOverhead;
154
- if (current.length > 0 && currentLen + cost > maxGitCliLength) {
155
- batches.push(current);
156
- current = [];
157
- currentLen = 0;
158
- }
159
- current.push(p);
160
- currentLen += cost;
161
- }
162
- if (current.length) {
163
- batches.push(current);
164
69
  }
165
70
 
166
71
  try {
167
- for (const batch of batches) {
168
- await this.git.run({ cwd: repoPath, ...runOptions }, 'checkout', `--${side}`, '--', ...batch);
169
- }
170
- this.context.hooks?.cache?.onReset?.(repoPath, 'status');
171
- this.context.hooks?.repository?.onChanged?.(repoPath, ['index']);
72
+ await this.git.run({ cwd: repoPath, errors: 'throw', ...runOptions }, ...params);
73
+ this.context.hooks?.cache?.onReset?.(repoPath, 'branches', 'status');
74
+ this.context.hooks?.repository?.onChanged?.(repoPath, ['head', 'heads', 'index']);
172
75
  } catch (ex) {
173
76
  scope?.error(ex);
174
77
  throw getGitCommandError(
@@ -176,11 +79,7 @@ export class OperationsGitSubProvider implements GitOperationsSubProvider {
176
79
  ex,
177
80
  reason =>
178
81
  new CheckoutError(
179
- {
180
- reason: reason ?? 'other',
181
- ref: side,
182
- gitCommand: { repoPath: repoPath, args: ['checkout', `--${side}`, '--', ...normalized] },
183
- },
82
+ { reason: reason ?? 'other', ref: ref, gitCommand: { repoPath: repoPath, args: params } },
184
83
  ex,
185
84
  ),
186
85
  );
@@ -288,6 +187,13 @@ export class OperationsGitSubProvider implements GitOperationsSubProvider {
288
187
  if (options?.date) {
289
188
  params.push(`--date=${options.date}`);
290
189
  }
190
+ // Host-level override (e.g. VS Code's `git.enableCommitSigning`) — request signing explicitly
191
+ // via `-S`. Implicit repo-config signing (`commit.gpgsign=true`) needs no flag, and `-S`
192
+ // alongside it is harmless, so the override can only enable signing, never force it off.
193
+ const sign = this.context.config?.signing?.enabled === true;
194
+ if (sign) {
195
+ params.push('-S');
196
+ }
291
197
  // Read commit message from stdin via -F - to avoid shell escaping issues
292
198
  params.push('-F', '-');
293
199
 
@@ -298,6 +204,15 @@ export class OperationsGitSubProvider implements GitOperationsSubProvider {
298
204
  );
299
205
  this.context.hooks?.cache?.onReset?.(repoPath, 'branches', 'status');
300
206
  this.context.hooks?.repository?.onChanged?.(repoPath, ['head', 'heads', 'index']);
207
+ if (sign) {
208
+ // `-S` was passed and the commit succeeded, so signing is confirmed — fire the
209
+ // explicit-sign hook (same contract as the patch provider's `commit-tree -S` path).
210
+ let format: SigningFormat | undefined;
211
+ try {
212
+ format = (await this.provider.config.getSigningConfig?.(repoPath))?.format;
213
+ } catch {}
214
+ this.context.hooks?.commits?.onSigned?.(format ?? 'gpg', options?.source);
215
+ }
301
216
  } catch (ex) {
302
217
  scope?.error(ex);
303
218
  await this.throwIfSigningError(repoPath, params, ex, options?.source);
@@ -383,7 +298,7 @@ export class OperationsGitSubProvider implements GitOperationsSubProvider {
383
298
  }
384
299
 
385
300
  try {
386
- await this.git.run({ cwd: repoPath, ...runOptions }, ...params);
301
+ await this.git.run({ cwd: repoPath, errors: 'throw', ...runOptions }, ...params);
387
302
  } catch (ex) {
388
303
  throw getGitCommandError(
389
304
  'fetch',
@@ -530,7 +445,7 @@ export class OperationsGitSubProvider implements GitOperationsSubProvider {
530
445
  }
531
446
 
532
447
  try {
533
- await this.git.run({ cwd: repoPath, configs: gitConfigsPull, ...runOptions }, ...params);
448
+ await this.git.run({ cwd: repoPath, configs: gitConfigsPull, errors: 'throw', ...runOptions }, ...params);
534
449
  } catch (ex) {
535
450
  await this.throwIfSigningError(repoPath, params, ex, options.source);
536
451
  throw getGitCommandError(
@@ -574,12 +489,17 @@ export class OperationsGitSubProvider implements GitOperationsSubProvider {
574
489
  const branch = await this.provider.branches.getBranch(repoPath);
575
490
  if (branch == null) return;
576
491
 
577
- branchName =
578
- options?.reference != null
579
- ? `${options.reference.ref}:${
580
- options?.publish != null ? 'refs/heads/' : ''
581
- }${branch.nameWithoutRemote}`
582
- : branch.name;
492
+ if (options?.reference != null) {
493
+ branchName = `${options.reference.ref}:${
494
+ options?.publish != null ? 'refs/heads/' : ''
495
+ }${branch.nameWithoutRemote}`;
496
+ } else {
497
+ const tracking = options?.publish == null ? branch.trackingWithoutRemote : undefined;
498
+ branchName =
499
+ tracking != null && tracking !== branch.nameWithoutRemote
500
+ ? `${branch.name}:${tracking}`
501
+ : branch.name;
502
+ }
583
503
  remoteName = branch.remoteName ?? options?.publish?.remote;
584
504
  upstreamName = options?.reference == null && options?.publish != null ? branch.name : undefined;
585
505
 
@@ -599,10 +519,12 @@ export class OperationsGitSubProvider implements GitOperationsSubProvider {
599
519
 
600
520
  let forceOpts: PushForceOptions | undefined;
601
521
  if (options?.force) {
602
- forceOpts = {
603
- withLease: true,
604
- ifIncludes: true,
605
- };
522
+ // Honor the host's force-push preferences (e.g. VS Code's `git.useForcePushWithLease` /
523
+ // `git.useForcePushIfIncludes`); fall back to the safer `--force-with-lease` behavior.
524
+ const useForceWithLease = this.context.config?.push?.useForceWithLease ?? true;
525
+ forceOpts = useForceWithLease
526
+ ? { withLease: true, ifIncludes: this.context.config?.push?.useForceIfIncludes ?? true }
527
+ : { withLease: false };
606
528
  }
607
529
 
608
530
  try {
@@ -688,7 +610,7 @@ export class OperationsGitSubProvider implements GitOperationsSubProvider {
688
610
  }
689
611
 
690
612
  try {
691
- await this.git.run({ cwd: repoPath, ...runOptions }, ...params);
613
+ await this.git.run({ cwd: repoPath, errors: 'throw', ...runOptions }, ...params);
692
614
  } catch (ex) {
693
615
  const error = getGitCommandError(
694
616
  'push',
@@ -758,6 +680,8 @@ export class OperationsGitSubProvider implements GitOperationsSubProvider {
758
680
  branch?: string;
759
681
  editor?: string;
760
682
  interactive?: boolean;
683
+ programmaticEditor?: boolean;
684
+ messageEditor?: string;
761
685
  onto?: string;
762
686
  updateRefs?: boolean;
763
687
  source?: unknown;
@@ -767,7 +691,7 @@ export class OperationsGitSubProvider implements GitOperationsSubProvider {
767
691
  const scope = getScopedLogger();
768
692
 
769
693
  const args = ['rebase'];
770
- let configs: string[] | undefined;
694
+ const configs: string[] = [];
771
695
 
772
696
  if (options?.autoStash !== false) {
773
697
  args.push('--autostash');
@@ -777,10 +701,26 @@ export class OperationsGitSubProvider implements GitOperationsSubProvider {
777
701
  args.push('--interactive');
778
702
 
779
703
  if (options.editor) {
780
- configs = ['-c', `sequence.editor=${options.editor}`];
704
+ configs.push('-c', `sequence.editor=${options.editor}`);
705
+ }
706
+
707
+ // A script-based sequence editor rewrites the todo by command word + SHA, so git must emit a
708
+ // plain, natural-order todo regardless of the user's rebase config: `rebase.autosquash` would
709
+ // reorder commits and rewrite `pick`→`fixup`, and `rebase.abbreviateCommands` would emit `p`.
710
+ if (options.programmaticEditor) {
711
+ configs.push('-c', 'rebase.autosquash=false', '-c', 'rebase.abbreviateCommands=false');
781
712
  }
782
713
  }
783
714
 
715
+ // Drive per-commit message editing (the combined message a `squash` produces, or a `reword`).
716
+ // `GIT_EDITOR` (not `core.editor`) is what git's interactive-rebase backend honors for the `reword`
717
+ // amend step, so set it on the environment; also set `core.editor` config as a fallback.
718
+ let env = runOptions?.env;
719
+ if (options?.messageEditor) {
720
+ configs.push('-c', `core.editor=${options.messageEditor}`);
721
+ env = { ...env, GIT_EDITOR: options.messageEditor };
722
+ }
723
+
784
724
  if (options?.updateRefs) {
785
725
  args.push('--update-refs');
786
726
  }
@@ -798,7 +738,7 @@ export class OperationsGitSubProvider implements GitOperationsSubProvider {
798
738
  try {
799
739
  await this.git.run(
800
740
  // Avoid a timeout since rebases can take a long time (set to 0 to disable)
801
- { cwd: repoPath, errors: 'throw', configs: configs, timeout: 0, ...runOptions },
741
+ { cwd: repoPath, errors: 'throw', configs: configs, timeout: 0, ...runOptions, env: env },
802
742
  ...args,
803
743
  );
804
744
  this.context.hooks?.cache?.onReset?.(repoPath, 'branches', 'status');
@@ -859,7 +799,7 @@ export class OperationsGitSubProvider implements GitOperationsSubProvider {
859
799
  params.push(rev, '--');
860
800
 
861
801
  try {
862
- await this.git.run({ cwd: repoPath, ...runOptions }, ...params);
802
+ await this.git.run({ cwd: repoPath, errors: 'throw', ...runOptions }, ...params);
863
803
  } catch (ex) {
864
804
  throw getGitCommandError(
865
805
  'reset',
@@ -870,6 +810,74 @@ export class OperationsGitSubProvider implements GitOperationsSubProvider {
870
810
  }
871
811
  }
872
812
 
813
+ @sequentialize({ getQueueKey: rp => rp })
814
+ @debug()
815
+ async restore(
816
+ repoPath: string,
817
+ path: string | string[],
818
+ options?: { ref?: string; side?: 'ours' | 'theirs' },
819
+ runOptions?: GitOperationRunOptions,
820
+ ): Promise<void> {
821
+ const paths = Array.isArray(path) ? path : [path];
822
+ if (!paths.length) return;
823
+
824
+ const scope = getScopedLogger();
825
+ const normalized = paths.map(p => splitPath(p, repoPath, true)[0]);
826
+
827
+ // `side` and `ref` are mutually exclusive in git (--ours/--theirs apply during conflict
828
+ // resolution and take no source ref); side takes precedence if both are somehow supplied.
829
+ // Use a truthy check on `ref` so an empty string falls through to index-restore rather than
830
+ // producing a malformed `git checkout '' -- …`. Implemented via `checkout` rather than
831
+ // `git restore` for compatibility with the minimum supported git (2.7.2); `git restore`
832
+ // only landed in 2.23.
833
+ const selector = options?.side != null ? `--${options.side}` : options?.ref || undefined;
834
+ const prefix = selector != null ? ['checkout', selector, '--'] : ['checkout', '--'];
835
+
836
+ try {
837
+ if (await this.git.supports('git:checkout:pathspec-from-file')) {
838
+ // Git ≥ 2.26: stream all pathspecs via stdin (NUL-separated) in a single invocation —
839
+ // no CLI-length limit (so no batching), and robust for paths with spaces/newlines.
840
+ // Pathspecs come from the file rather than argv, so `--` isn't used.
841
+ const args = ['checkout'];
842
+ if (selector != null) {
843
+ args.push(selector);
844
+ }
845
+ args.push('--pathspec-from-file=-', '--pathspec-file-nul');
846
+ await this.git.run(
847
+ { cwd: repoPath, errors: 'throw', ...runOptions, stdin: normalized.join('\0') },
848
+ ...args,
849
+ );
850
+ } else {
851
+ // Older git: pass pathspecs as args, one git invocation per chunk (collapsing N
852
+ // path-mode checkouts into ⌈N / chunk⌉ spawns). Reserve the command prefix length and
853
+ // a per-arg overhead (separator + possible quoting) so the assembled command line
854
+ // can't exceed the OS limit even with many short paths.
855
+ const perArgOverhead = 3;
856
+ const prefixLength = prefix.reduce((sum, arg) => sum + arg.length + perArgOverhead, 0);
857
+ for (const batch of chunkByStringLength(normalized, maxGitCliLength - prefixLength, perArgOverhead)) {
858
+ await this.git.run({ cwd: repoPath, errors: 'throw', ...runOptions }, ...prefix, ...batch);
859
+ }
860
+ }
861
+ this.context.hooks?.cache?.onReset?.(repoPath, 'status');
862
+ this.context.hooks?.repository?.onChanged?.(repoPath, ['index']);
863
+ } catch (ex) {
864
+ scope?.error(ex);
865
+ throw getGitCommandError(
866
+ 'checkout',
867
+ ex,
868
+ reason =>
869
+ new CheckoutError(
870
+ {
871
+ reason: reason ?? 'other',
872
+ ref: options?.side ?? options?.ref,
873
+ gitCommand: { repoPath: repoPath, args: [...prefix, ...normalized] },
874
+ },
875
+ ex,
876
+ ),
877
+ );
878
+ }
879
+ }
880
+
873
881
  @sequentialize({ getQueueKey: rp => rp })
874
882
  @debug()
875
883
  async revert(