@gitkraken/core-gitlens 0.1.0 → 0.3.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 (451) hide show
  1. package/CHANGELOG.md +25 -1
  2. package/dist/git/cache.d.ts +49 -9
  3. package/dist/git/cache.d.ts.map +1 -1
  4. package/dist/git/cache.js +174 -14
  5. package/dist/git/cache.js.map +1 -1
  6. package/dist/git/context.d.ts +11 -2
  7. package/dist/git/context.d.ts.map +1 -1
  8. package/dist/git/context.js.map +1 -1
  9. package/dist/git/models/branch.d.ts +1 -0
  10. package/dist/git/models/branch.d.ts.map +1 -1
  11. package/dist/git/models/branch.js.map +1 -1
  12. package/dist/git/models/commit.d.ts +1 -9
  13. package/dist/git/models/commit.d.ts.map +1 -1
  14. package/dist/git/models/commit.js +4 -9
  15. package/dist/git/models/commit.js.map +1 -1
  16. package/dist/git/models/graph.d.ts +2 -4
  17. package/dist/git/models/graph.d.ts.map +1 -1
  18. package/dist/git/models/reference.d.ts +31 -0
  19. package/dist/git/models/reference.d.ts.map +1 -1
  20. package/dist/git/models/remote.d.ts.map +1 -1
  21. package/dist/git/models/remote.js.map +1 -1
  22. package/dist/git/models/repository.d.ts +20 -3
  23. package/dist/git/models/repository.d.ts.map +1 -1
  24. package/dist/git/models/repository.js +42 -5
  25. package/dist/git/models/repository.js.map +1 -1
  26. package/dist/git/models/search.d.ts +2 -2
  27. package/dist/git/models/search.d.ts.map +1 -1
  28. package/dist/git/models/worktree.d.ts +4 -1
  29. package/dist/git/models/worktree.d.ts.map +1 -1
  30. package/dist/git/models/worktree.js +2 -2
  31. package/dist/git/models/worktree.js.map +1 -1
  32. package/dist/git/parsers/diffParser.d.ts +0 -1
  33. package/dist/git/parsers/diffParser.d.ts.map +1 -1
  34. package/dist/git/parsers/diffParser.js +22 -61
  35. package/dist/git/parsers/diffParser.js.map +1 -1
  36. package/dist/git/providers/branches.d.ts +18 -4
  37. package/dist/git/providers/branches.d.ts.map +1 -1
  38. package/dist/git/providers/commits.d.ts +6 -0
  39. package/dist/git/providers/commits.d.ts.map +1 -1
  40. package/dist/git/providers/config.d.ts +6 -1
  41. package/dist/git/providers/config.d.ts.map +1 -1
  42. package/dist/git/providers/diff.d.ts +2 -0
  43. package/dist/git/providers/diff.d.ts.map +1 -1
  44. package/dist/git/providers/operations.d.ts +39 -10
  45. package/dist/git/providers/operations.d.ts.map +1 -1
  46. package/dist/git/providers/pausedOperations.d.ts +3 -1
  47. package/dist/git/providers/pausedOperations.d.ts.map +1 -1
  48. package/dist/git/providers/refs.d.ts +23 -2
  49. package/dist/git/providers/refs.d.ts.map +1 -1
  50. package/dist/git/providers/revision.d.ts +1 -1
  51. package/dist/git/providers/revision.d.ts.map +1 -1
  52. package/dist/git/providers/staging.d.ts +18 -0
  53. package/dist/git/providers/staging.d.ts.map +1 -1
  54. package/dist/git/providers/status.d.ts +4 -1
  55. package/dist/git/providers/status.d.ts.map +1 -1
  56. package/dist/git/remotes/azure-devops.d.ts.map +1 -1
  57. package/dist/git/remotes/azure-devops.js.map +1 -1
  58. package/dist/git/{exec.types.d.ts → run.types.d.ts} +22 -3
  59. package/dist/git/run.types.d.ts.map +1 -0
  60. package/dist/git/run.types.js +2 -0
  61. package/dist/git/run.types.js.map +1 -0
  62. package/dist/git/service.d.ts.map +1 -1
  63. package/dist/git/service.js.map +1 -1
  64. package/dist/git/utils/autolink.utils.d.ts.map +1 -1
  65. package/dist/git/utils/autolink.utils.js.map +1 -1
  66. package/dist/git/utils/blame.utils.d.ts.map +1 -1
  67. package/dist/git/utils/blame.utils.js.map +1 -1
  68. package/dist/git/utils/conflictResolution.utils.d.ts +6 -0
  69. package/dist/git/utils/conflictResolution.utils.d.ts.map +1 -0
  70. package/dist/git/utils/conflictResolution.utils.js +25 -0
  71. package/dist/git/utils/conflictResolution.utils.js.map +1 -0
  72. package/dist/git/utils/fileStatus.utils.d.ts +2 -1
  73. package/dist/git/utils/fileStatus.utils.d.ts.map +1 -1
  74. package/dist/git/utils/fileStatus.utils.js +4 -0
  75. package/dist/git/utils/fileStatus.utils.js.map +1 -1
  76. package/dist/git/utils/search.utils.d.ts.map +1 -1
  77. package/dist/git/utils/search.utils.js +3 -0
  78. package/dist/git/utils/search.utils.js.map +1 -1
  79. package/dist/git/utils/sorting.d.ts +14 -0
  80. package/dist/git/utils/sorting.d.ts.map +1 -1
  81. package/dist/git/utils/sorting.js +34 -0
  82. package/dist/git/utils/sorting.js.map +1 -1
  83. package/dist/git/utils/status.utils.d.ts.map +1 -1
  84. package/dist/git/utils/status.utils.js.map +1 -1
  85. package/dist/git/watching/classifyChange.d.ts.map +1 -1
  86. package/dist/git/watching/classifyChange.js +8 -0
  87. package/dist/git/watching/classifyChange.js.map +1 -1
  88. package/dist/git/watching/gitIgnoreFilter.js +1 -1
  89. package/dist/git/watching/gitIgnoreFilter.js.map +1 -1
  90. package/dist/git/watching/initWatcher.d.ts.map +1 -1
  91. package/dist/git/watching/initWatcher.js.map +1 -1
  92. package/dist/git/watching/watchGroup.d.ts.map +1 -1
  93. package/dist/git/watching/watchGroup.js.map +1 -1
  94. package/dist/git/watching/watchService.d.ts.map +1 -1
  95. package/dist/git/watching/watchService.js +24 -4
  96. package/dist/git/watching/watchService.js.map +1 -1
  97. package/dist/git/watching/watchSession.d.ts.map +1 -1
  98. package/dist/git/watching/watchSession.js.map +1 -1
  99. package/dist/git-cli/cliGitProvider.js +1 -1
  100. package/dist/git-cli/cliGitProvider.js.map +1 -1
  101. package/dist/git-cli/exec/exec.types.d.ts +1 -1
  102. package/dist/git-cli/exec/exec.types.d.ts.map +1 -1
  103. package/dist/git-cli/exec/git.d.ts +31 -6
  104. package/dist/git-cli/exec/git.d.ts.map +1 -1
  105. package/dist/git-cli/exec/git.js +70 -9
  106. package/dist/git-cli/exec/git.js.map +1 -1
  107. package/dist/git-cli/exec/gitQueue.d.ts +22 -6
  108. package/dist/git-cli/exec/gitQueue.d.ts.map +1 -1
  109. package/dist/git-cli/exec/gitQueue.js +88 -24
  110. package/dist/git-cli/exec/gitQueue.js.map +1 -1
  111. package/dist/git-cli/parsers/blameParser.d.ts.map +1 -1
  112. package/dist/git-cli/parsers/blameParser.js.map +1 -1
  113. package/dist/git-cli/parsers/logParser.d.ts +1 -0
  114. package/dist/git-cli/parsers/logParser.d.ts.map +1 -1
  115. package/dist/git-cli/parsers/logParser.js +4 -0
  116. package/dist/git-cli/parsers/logParser.js.map +1 -1
  117. package/dist/git-cli/parsers/refParser.d.ts +3 -30
  118. package/dist/git-cli/parsers/refParser.d.ts.map +1 -1
  119. package/dist/git-cli/parsers/refParser.js +30 -30
  120. package/dist/git-cli/parsers/refParser.js.map +1 -1
  121. package/dist/git-cli/providers/blame.d.ts.map +1 -1
  122. package/dist/git-cli/providers/blame.js +1 -1
  123. package/dist/git-cli/providers/blame.js.map +1 -1
  124. package/dist/git-cli/providers/branches.d.ts +17 -5
  125. package/dist/git-cli/providers/branches.d.ts.map +1 -1
  126. package/dist/git-cli/providers/branches.js +245 -162
  127. package/dist/git-cli/providers/branches.js.map +1 -1
  128. package/dist/git-cli/providers/commits.d.ts +4 -0
  129. package/dist/git-cli/providers/commits.d.ts.map +1 -1
  130. package/dist/git-cli/providers/commits.js +120 -35
  131. package/dist/git-cli/providers/commits.js.map +1 -1
  132. package/dist/git-cli/providers/config.d.ts +11 -2
  133. package/dist/git-cli/providers/config.d.ts.map +1 -1
  134. package/dist/git-cli/providers/config.js +36 -11
  135. package/dist/git-cli/providers/config.js.map +1 -1
  136. package/dist/git-cli/providers/contributors.d.ts.map +1 -1
  137. package/dist/git-cli/providers/contributors.js +7 -4
  138. package/dist/git-cli/providers/contributors.js.map +1 -1
  139. package/dist/git-cli/providers/diff.d.ts +2 -0
  140. package/dist/git-cli/providers/diff.d.ts.map +1 -1
  141. package/dist/git-cli/providers/diff.js +92 -20
  142. package/dist/git-cli/providers/diff.js.map +1 -1
  143. package/dist/git-cli/providers/graph.d.ts.map +1 -1
  144. package/dist/git-cli/providers/graph.js +49 -28
  145. package/dist/git-cli/providers/graph.js.map +1 -1
  146. package/dist/git-cli/providers/operations.d.ts +30 -11
  147. package/dist/git-cli/providers/operations.d.ts.map +1 -1
  148. package/dist/git-cli/providers/operations.js +146 -43
  149. package/dist/git-cli/providers/operations.js.map +1 -1
  150. package/dist/git-cli/providers/patch.d.ts.map +1 -1
  151. package/dist/git-cli/providers/patch.js +15 -30
  152. package/dist/git-cli/providers/patch.js.map +1 -1
  153. package/dist/git-cli/providers/pausedOperations.d.ts +3 -1
  154. package/dist/git-cli/providers/pausedOperations.d.ts.map +1 -1
  155. package/dist/git-cli/providers/pausedOperations.js +13 -7
  156. package/dist/git-cli/providers/pausedOperations.js.map +1 -1
  157. package/dist/git-cli/providers/refs.d.ts +19 -2
  158. package/dist/git-cli/providers/refs.d.ts.map +1 -1
  159. package/dist/git-cli/providers/refs.js +312 -9
  160. package/dist/git-cli/providers/refs.js.map +1 -1
  161. package/dist/git-cli/providers/remotes.js +4 -4
  162. package/dist/git-cli/providers/remotes.js.map +1 -1
  163. package/dist/git-cli/providers/revision.d.ts +1 -1
  164. package/dist/git-cli/providers/revision.d.ts.map +1 -1
  165. package/dist/git-cli/providers/revision.js +15 -11
  166. package/dist/git-cli/providers/revision.js.map +1 -1
  167. package/dist/git-cli/providers/staging.d.ts +8 -0
  168. package/dist/git-cli/providers/staging.d.ts.map +1 -1
  169. package/dist/git-cli/providers/staging.js +52 -8
  170. package/dist/git-cli/providers/staging.js.map +1 -1
  171. package/dist/git-cli/providers/stash.d.ts +0 -8
  172. package/dist/git-cli/providers/stash.d.ts.map +1 -1
  173. package/dist/git-cli/providers/stash.js +63 -119
  174. package/dist/git-cli/providers/stash.js.map +1 -1
  175. package/dist/git-cli/providers/status.d.ts +4 -1
  176. package/dist/git-cli/providers/status.d.ts.map +1 -1
  177. package/dist/git-cli/providers/status.js +10 -9
  178. package/dist/git-cli/providers/status.js.map +1 -1
  179. package/dist/git-cli/providers/tags.d.ts.map +1 -1
  180. package/dist/git-cli/providers/tags.js +13 -9
  181. package/dist/git-cli/providers/tags.js.map +1 -1
  182. package/dist/git-cli/providers/worktrees.js +3 -3
  183. package/dist/git-cli/providers/worktrees.js.map +1 -1
  184. package/dist/ipc/discovery.d.ts +27 -0
  185. package/dist/ipc/discovery.d.ts.map +1 -0
  186. package/dist/ipc/discovery.js +38 -0
  187. package/dist/ipc/discovery.js.map +1 -0
  188. package/dist/ipc/ipcServer.d.ts +20 -0
  189. package/dist/ipc/ipcServer.d.ts.map +1 -0
  190. package/dist/ipc/ipcServer.js +162 -0
  191. package/dist/ipc/ipcServer.js.map +1 -0
  192. package/dist/plus/agents/providers/claudeCodeProvider.d.ts +114 -0
  193. package/dist/plus/agents/providers/claudeCodeProvider.d.ts.map +1 -0
  194. package/dist/plus/agents/providers/claudeCodeProvider.js +1480 -0
  195. package/dist/plus/agents/providers/claudeCodeProvider.js.map +1 -0
  196. package/dist/plus/agents/providers/claudeCodeTranscript.d.ts +36 -0
  197. package/dist/plus/agents/providers/claudeCodeTranscript.d.ts.map +1 -0
  198. package/dist/plus/agents/providers/claudeCodeTranscript.js +171 -0
  199. package/dist/plus/agents/providers/claudeCodeTranscript.js.map +1 -0
  200. package/dist/plus/agents/sanitizePrompt.d.ts +15 -0
  201. package/dist/plus/agents/sanitizePrompt.d.ts.map +1 -0
  202. package/dist/plus/agents/sanitizePrompt.js +103 -0
  203. package/dist/plus/agents/sanitizePrompt.js.map +1 -0
  204. package/dist/plus/agents/stateMachine.d.ts +32 -0
  205. package/dist/plus/agents/stateMachine.d.ts.map +1 -0
  206. package/dist/plus/agents/stateMachine.js +180 -0
  207. package/dist/plus/agents/stateMachine.js.map +1 -0
  208. package/dist/plus/agents/types.d.ts +203 -0
  209. package/dist/plus/agents/types.d.ts.map +1 -0
  210. package/dist/plus/agents/types.js +49 -0
  211. package/dist/plus/agents/types.js.map +1 -0
  212. package/dist/plus/ai/constants.d.ts +2 -1
  213. package/dist/plus/ai/constants.d.ts.map +1 -1
  214. package/dist/plus/ai/constants.js +7 -0
  215. package/dist/plus/ai/constants.js.map +1 -1
  216. package/dist/plus/ai/errors.d.ts +4 -1
  217. package/dist/plus/ai/errors.d.ts.map +1 -1
  218. package/dist/plus/ai/errors.js +38 -0
  219. package/dist/plus/ai/errors.js.map +1 -1
  220. package/dist/plus/ai/models/model.d.ts +1 -1
  221. package/dist/plus/ai/models/model.d.ts.map +1 -1
  222. package/dist/plus/ai/models/model.js.map +1 -1
  223. package/dist/plus/ai/models/promptTemplates.d.ts +28 -2
  224. package/dist/plus/ai/models/promptTemplates.d.ts.map +1 -1
  225. package/dist/plus/ai/models/results.d.ts +28 -0
  226. package/dist/plus/ai/models/results.d.ts.map +1 -1
  227. package/dist/plus/ai/prompts.d.ts +4 -0
  228. package/dist/plus/ai/prompts.d.ts.map +1 -1
  229. package/dist/plus/ai/prompts.js +167 -1
  230. package/dist/plus/ai/prompts.js.map +1 -1
  231. package/dist/plus/ai/utils/ai.utils.d.ts.map +1 -1
  232. package/dist/plus/ai/utils/ai.utils.js +2 -0
  233. package/dist/plus/ai/utils/ai.utils.js.map +1 -1
  234. package/dist/plus/ai/utils/results.utils.d.ts +3 -0
  235. package/dist/plus/ai/utils/results.utils.d.ts.map +1 -1
  236. package/dist/plus/ai/utils/results.utils.js +75 -0
  237. package/dist/plus/ai/utils/results.utils.js.map +1 -1
  238. package/dist/plus/ai/utils/truncation.utils.d.ts +1 -1
  239. package/dist/plus/ai/utils/truncation.utils.d.ts.map +1 -1
  240. package/dist/plus/ai/utils/truncation.utils.js.map +1 -1
  241. package/dist/plus/git-github/api/github.d.ts +10 -1
  242. package/dist/plus/git-github/api/github.d.ts.map +1 -1
  243. package/dist/plus/git-github/api/github.js +156 -49
  244. package/dist/plus/git-github/api/github.js.map +1 -1
  245. package/dist/plus/git-github/api/types.d.ts +8 -0
  246. package/dist/plus/git-github/api/types.d.ts.map +1 -1
  247. package/dist/plus/git-github/models.d.ts +1 -1
  248. package/dist/plus/git-github/models.d.ts.map +1 -1
  249. package/dist/plus/git-github/models.js.map +1 -1
  250. package/dist/plus/git-github/providers/github/blame.d.ts.map +1 -1
  251. package/dist/plus/git-github/providers/github/blame.js.map +1 -1
  252. package/dist/plus/git-github/providers/github/branches.d.ts +5 -1
  253. package/dist/plus/git-github/providers/github/branches.d.ts.map +1 -1
  254. package/dist/plus/git-github/providers/github/branches.js +60 -22
  255. package/dist/plus/git-github/providers/github/branches.js.map +1 -1
  256. package/dist/plus/git-github/providers/github/commits.d.ts.map +1 -1
  257. package/dist/plus/git-github/providers/github/commits.js +144 -92
  258. package/dist/plus/git-github/providers/github/commits.js.map +1 -1
  259. package/dist/plus/git-github/providers/github/diff.d.ts +3 -1
  260. package/dist/plus/git-github/providers/github/diff.d.ts.map +1 -1
  261. package/dist/plus/git-github/providers/github/diff.js +23 -9
  262. package/dist/plus/git-github/providers/github/diff.js.map +1 -1
  263. package/dist/plus/git-github/providers/github/refs.d.ts +9 -1
  264. package/dist/plus/git-github/providers/github/refs.d.ts.map +1 -1
  265. package/dist/plus/git-github/providers/github/refs.js +38 -13
  266. package/dist/plus/git-github/providers/github/refs.js.map +1 -1
  267. package/dist/plus/git-github/providers/github/revision.d.ts.map +1 -1
  268. package/dist/plus/git-github/providers/github/revision.js +1 -2
  269. package/dist/plus/git-github/providers/github/revision.js.map +1 -1
  270. package/dist/plus/git-github/providers/github/status.d.ts +4 -1
  271. package/dist/plus/git-github/providers/github/status.d.ts.map +1 -1
  272. package/dist/plus/git-github/providers/github/status.js +1 -1
  273. package/dist/plus/git-github/providers/github/status.js.map +1 -1
  274. package/dist/plus/git-github/providers/github/tags.d.ts.map +1 -1
  275. package/dist/plus/git-github/providers/github/tags.js +35 -36
  276. package/dist/plus/git-github/providers/github/tags.js.map +1 -1
  277. package/dist/plus/git-github/providers/githubGitProvider.d.ts.map +1 -1
  278. package/dist/plus/git-github/providers/githubGitProvider.js.map +1 -1
  279. package/dist/utils/color.d.ts.map +1 -1
  280. package/dist/utils/color.js.map +1 -1
  281. package/dist/utils/decorators/log.js +1 -1
  282. package/dist/utils/decorators/log.js.map +1 -1
  283. package/dist/utils/decorators/sequentialize.d.ts.map +1 -1
  284. package/dist/utils/decorators/sequentialize.js +4 -2
  285. package/dist/utils/decorators/sequentialize.js.map +1 -1
  286. package/dist/utils/decorators/serializable.d.ts.map +1 -1
  287. package/dist/utils/decorators/serializable.js.map +1 -1
  288. package/dist/utils/dedupedAsyncCache.d.ts +37 -0
  289. package/dist/utils/dedupedAsyncCache.d.ts.map +1 -0
  290. package/dist/utils/dedupedAsyncCache.js +68 -0
  291. package/dist/utils/dedupedAsyncCache.js.map +1 -0
  292. package/dist/utils/diff.d.ts +2 -0
  293. package/dist/utils/diff.d.ts.map +1 -0
  294. package/dist/utils/diff.js +53 -0
  295. package/dist/utils/diff.js.map +1 -0
  296. package/dist/utils/disposable.d.ts.map +1 -1
  297. package/dist/utils/disposable.js.map +1 -1
  298. package/dist/utils/env/node/base64.js.map +1 -1
  299. package/dist/utils/env/node/exec.d.ts.map +1 -1
  300. package/dist/utils/env/node/exec.js.map +1 -1
  301. package/dist/utils/error.d.ts.map +1 -1
  302. package/dist/utils/error.js.map +1 -1
  303. package/dist/utils/formatter.d.ts.map +1 -1
  304. package/dist/utils/formatter.js +4 -10
  305. package/dist/utils/formatter.js.map +1 -1
  306. package/dist/utils/iterable.d.ts.map +1 -1
  307. package/dist/utils/iterable.js.map +1 -1
  308. package/dist/utils/logger.d.ts.map +1 -1
  309. package/dist/utils/logger.js.map +1 -1
  310. package/dist/utils/lruMap.d.ts +49 -0
  311. package/dist/utils/lruMap.d.ts.map +1 -0
  312. package/dist/utils/lruMap.js +103 -0
  313. package/dist/utils/lruMap.js.map +1 -0
  314. package/dist/utils/markdown.d.ts.map +1 -1
  315. package/dist/utils/markdown.js.map +1 -1
  316. package/dist/utils/mru.d.ts.map +1 -1
  317. package/dist/utils/mru.js.map +1 -1
  318. package/dist/utils/path.d.ts.map +1 -1
  319. package/dist/utils/path.js.map +1 -1
  320. package/dist/utils/promise.d.ts +1 -0
  321. package/dist/utils/promise.d.ts.map +1 -1
  322. package/dist/utils/promise.js +17 -0
  323. package/dist/utils/promise.js.map +1 -1
  324. package/dist/utils/promiseCache.d.ts +10 -0
  325. package/dist/utils/promiseCache.d.ts.map +1 -1
  326. package/dist/utils/promiseCache.js +22 -0
  327. package/dist/utils/promiseCache.js.map +1 -1
  328. package/dist/utils/string.d.ts.map +1 -1
  329. package/dist/utils/string.js.map +1 -1
  330. package/dist/utils/uri.d.ts.map +1 -1
  331. package/dist/utils/uri.js.map +1 -1
  332. package/dist/utils/version.d.ts +14 -0
  333. package/dist/utils/version.d.ts.map +1 -1
  334. package/dist/utils/version.js +48 -0
  335. package/dist/utils/version.js.map +1 -1
  336. package/package.json +13 -1
  337. package/src/git/cache.ts +309 -29
  338. package/src/git/context.ts +11 -2
  339. package/src/git/models/branch.ts +1 -0
  340. package/src/git/models/commit.ts +2 -17
  341. package/src/git/models/graph.ts +2 -4
  342. package/src/git/models/reference.ts +33 -0
  343. package/src/git/models/remote.ts +1 -0
  344. package/src/git/models/repository.ts +44 -6
  345. package/src/git/models/search.ts +2 -2
  346. package/src/git/models/worktree.ts +10 -2
  347. package/src/git/parsers/diffParser.ts +9 -44
  348. package/src/git/providers/branches.ts +25 -4
  349. package/src/git/providers/commits.ts +7 -0
  350. package/src/git/providers/config.ts +4 -0
  351. package/src/git/providers/diff.ts +8 -2
  352. package/src/git/providers/operations.ts +54 -3
  353. package/src/git/providers/pausedOperations.ts +1 -0
  354. package/src/git/providers/refs.ts +32 -3
  355. package/src/git/providers/revision.ts +5 -1
  356. package/src/git/providers/staging.ts +14 -0
  357. package/src/git/providers/status.ts +6 -1
  358. package/src/git/remotes/azure-devops.ts +2 -0
  359. package/src/git/{exec.types.ts → run.types.ts} +22 -2
  360. package/src/git/service.ts +1 -0
  361. package/src/git/utils/autolink.utils.ts +1 -0
  362. package/src/git/utils/blame.utils.ts +2 -0
  363. package/src/git/utils/conflictResolution.utils.ts +31 -0
  364. package/src/git/utils/fileStatus.utils.ts +7 -1
  365. package/src/git/utils/search.utils.ts +2 -0
  366. package/src/git/utils/sorting.ts +38 -0
  367. package/src/git/utils/status.utils.ts +1 -0
  368. package/src/git/watching/classifyChange.ts +9 -0
  369. package/src/git/watching/gitIgnoreFilter.ts +2 -2
  370. package/src/git/watching/initWatcher.ts +2 -0
  371. package/src/git/watching/watchGroup.ts +3 -0
  372. package/src/git/watching/watchService.ts +38 -5
  373. package/src/git/watching/watchSession.ts +10 -0
  374. package/src/git-cli/cliGitProvider.ts +1 -1
  375. package/src/git-cli/exec/exec.types.ts +2 -2
  376. package/src/git-cli/exec/git.ts +76 -23
  377. package/src/git-cli/exec/gitQueue.ts +98 -25
  378. package/src/git-cli/parsers/blameParser.ts +1 -0
  379. package/src/git-cli/parsers/logParser.ts +6 -1
  380. package/src/git-cli/parsers/refParser.ts +33 -34
  381. package/src/git-cli/providers/blame.ts +2 -1
  382. package/src/git-cli/providers/branches.ts +341 -196
  383. package/src/git-cli/providers/commits.ts +145 -46
  384. package/src/git-cli/providers/config.ts +50 -16
  385. package/src/git-cli/providers/contributors.ts +7 -12
  386. package/src/git-cli/providers/diff.ts +107 -20
  387. package/src/git-cli/providers/graph.ts +58 -29
  388. package/src/git-cli/providers/operations.ts +253 -57
  389. package/src/git-cli/providers/patch.ts +16 -37
  390. package/src/git-cli/providers/pausedOperations.ts +14 -6
  391. package/src/git-cli/providers/refs.ts +274 -11
  392. package/src/git-cli/providers/remotes.ts +4 -4
  393. package/src/git-cli/providers/revision.ts +22 -15
  394. package/src/git-cli/providers/staging.ts +51 -8
  395. package/src/git-cli/providers/stash.ts +67 -134
  396. package/src/git-cli/providers/status.ts +21 -10
  397. package/src/git-cli/providers/tags.ts +18 -19
  398. package/src/git-cli/providers/worktrees.ts +3 -3
  399. package/src/ipc/discovery.ts +56 -0
  400. package/src/ipc/ipcServer.ts +171 -0
  401. package/src/plus/agents/providers/claudeCodeProvider.ts +1782 -0
  402. package/src/plus/agents/providers/claudeCodeTranscript.ts +214 -0
  403. package/src/plus/agents/sanitizePrompt.ts +109 -0
  404. package/src/plus/agents/stateMachine.ts +197 -0
  405. package/src/plus/agents/types.ts +277 -0
  406. package/src/plus/ai/constants.ts +8 -0
  407. package/src/plus/ai/errors.ts +40 -0
  408. package/src/plus/ai/models/model.ts +1 -0
  409. package/src/plus/ai/models/promptTemplates.ts +42 -0
  410. package/src/plus/ai/models/results.ts +30 -0
  411. package/src/plus/ai/prompts.ts +171 -1
  412. package/src/plus/ai/utils/ai.utils.ts +2 -0
  413. package/src/plus/ai/utils/results.utils.ts +101 -0
  414. package/src/plus/ai/utils/truncation.utils.ts +3 -1
  415. package/src/plus/git-github/api/github.ts +199 -53
  416. package/src/plus/git-github/api/types.ts +15 -0
  417. package/src/plus/git-github/models.ts +1 -1
  418. package/src/plus/git-github/providers/github/blame.ts +2 -0
  419. package/src/plus/git-github/providers/github/branches.ts +75 -33
  420. package/src/plus/git-github/providers/github/commits.ts +231 -160
  421. package/src/plus/git-github/providers/github/diff.ts +35 -21
  422. package/src/plus/git-github/providers/github/refs.ts +57 -22
  423. package/src/plus/git-github/providers/github/revision.ts +1 -2
  424. package/src/plus/git-github/providers/github/status.ts +6 -1
  425. package/src/plus/git-github/providers/github/tags.ts +61 -62
  426. package/src/plus/git-github/providers/githubGitProvider.ts +1 -0
  427. package/src/utils/color.ts +2 -0
  428. package/src/utils/decorators/log.ts +1 -1
  429. package/src/utils/decorators/sequentialize.ts +8 -6
  430. package/src/utils/decorators/serializable.ts +1 -0
  431. package/src/utils/dedupedAsyncCache.ts +74 -0
  432. package/src/utils/diff.ts +61 -0
  433. package/src/utils/disposable.ts +2 -0
  434. package/src/utils/env/node/base64.ts +1 -1
  435. package/src/utils/env/node/exec.ts +4 -2
  436. package/src/utils/error.ts +1 -0
  437. package/src/utils/formatter.ts +4 -11
  438. package/src/utils/iterable.ts +4 -1
  439. package/src/utils/logger.ts +1 -0
  440. package/src/utils/lruMap.ts +112 -0
  441. package/src/utils/markdown.ts +1 -0
  442. package/src/utils/mru.ts +2 -0
  443. package/src/utils/path.ts +1 -0
  444. package/src/utils/promise.ts +22 -0
  445. package/src/utils/promiseCache.ts +24 -0
  446. package/src/utils/string.ts +2 -0
  447. package/src/utils/uri.ts +1 -0
  448. package/src/utils/version.ts +49 -0
  449. package/dist/git/exec.types.d.ts.map +0 -1
  450. package/dist/git/exec.types.js +0 -2
  451. package/dist/git/exec.types.js.map +0 -1
@@ -11,7 +11,7 @@ import { getSettledValue } from '../../utils/promise.js';
11
11
  import type { CliGitProviderInternal } from '../cliGitProvider.js';
12
12
  import { RunError } from '../exec/exec.errors.js';
13
13
  import type { Git } from '../exec/git.js';
14
- import { gitConfigsLog, GitError } from '../exec/git.js';
14
+ import { classifySigningError, gitConfigsLog, GitError } from '../exec/git.js';
15
15
 
16
16
  export class PatchGitSubProvider implements GitPatchSubProvider {
17
17
  constructor(
@@ -27,7 +27,7 @@ export class PatchGitSubProvider implements GitPatchSubProvider {
27
27
  if (options?.threeWay) {
28
28
  args.push('--3way');
29
29
  }
30
- await this.git.exec({ cwd: repoPath, stdin: patch }, ...args);
30
+ await this.git.run({ cwd: repoPath, stdin: patch }, ...args);
31
31
  }
32
32
 
33
33
  @debug()
@@ -113,6 +113,7 @@ export class PatchGitSubProvider implements GitPatchSubProvider {
113
113
  }
114
114
  } catch (ex) {
115
115
  if (ex instanceof ApplyPatchCommitError) throw ex;
116
+
116
117
  scope?.error(ex);
117
118
 
118
119
  if (CherryPickError.is(ex, 'wouldOverwriteChanges')) {
@@ -209,7 +210,7 @@ export class PatchGitSubProvider implements GitPatchSubProvider {
209
210
  const [signingConfigResult, applyResult] = await Promise.allSettled([
210
211
  this.provider.config.getSigningConfig?.(repoPath),
211
212
  // Apply the patch to our temp index, without touching the working directory
212
- this.git.exec(
213
+ this.git.run(
213
214
  { cwd: repoPath, configs: gitConfigsLog, env: env, stdin: patch },
214
215
  'apply',
215
216
  '--cached',
@@ -224,7 +225,7 @@ export class PatchGitSubProvider implements GitPatchSubProvider {
224
225
  _signingFormat = signingConfig?.format ?? 'gpg';
225
226
 
226
227
  // Create a new tree from our patched index
227
- let result = await this.git.exec({ cwd: repoPath, env: env }, 'write-tree');
228
+ let result = await this.git.run({ cwd: repoPath, env: env }, 'write-tree');
228
229
  const tree = result.stdout.trim();
229
230
 
230
231
  // Set the author if provided
@@ -247,7 +248,7 @@ export class PatchGitSubProvider implements GitPatchSubProvider {
247
248
  args.push('-m', message);
248
249
 
249
250
  // Create new commit from the tree
250
- result = await this.git.exec({ cwd: repoPath, env: finalEnv }, ...args);
251
+ result = await this.git.run({ cwd: repoPath, env: finalEnv }, ...args);
251
252
  const sha = result.stdout.trim();
252
253
 
253
254
  if (shouldSign) {
@@ -260,33 +261,11 @@ export class PatchGitSubProvider implements GitPatchSubProvider {
260
261
 
261
262
  // Handle signing-specific errors
262
263
  if (shouldSign && ex instanceof Error) {
263
- const errorMessage = ex.message.toLowerCase();
264
- const gitCommand: GitCommandContext = { repoPath: repoPath, args: ['commit-tree'] };
265
- let signingError: SigningError | undefined;
266
-
267
- if (errorMessage.includes('gpg failed to sign') || errorMessage.includes('error: gpg')) {
268
- signingError = new SigningError({ reason: 'passphraseFailed', gitCommand: gitCommand }, ex);
269
- } else if (
270
- errorMessage.includes('secret key not available') ||
271
- errorMessage.includes('no secret key') ||
272
- errorMessage.includes('no signing key')
273
- ) {
274
- signingError = new SigningError({ reason: 'noKey', gitCommand: gitCommand }, ex);
275
- } else if (
276
- errorMessage.includes('gpg: command not found') ||
277
- (errorMessage.includes('gpg') && errorMessage.includes('not found'))
278
- ) {
279
- signingError = new SigningError({ reason: 'gpgNotFound', gitCommand: gitCommand }, ex);
280
- } else if (errorMessage.includes('ssh-keygen') && errorMessage.includes('not found')) {
281
- signingError = new SigningError({ reason: 'sshNotFound', gitCommand: gitCommand }, ex);
282
- }
283
-
284
- if (signingError != null) {
285
- this.context.hooks?.commits?.onSigningFailed?.(
286
- signingError.details.reason ?? 'unknown',
287
- _signingFormat,
288
- options?.source,
289
- );
264
+ const reason = classifySigningError(ex);
265
+ if (reason != null) {
266
+ const gitCommand: GitCommandContext = { repoPath: repoPath, args: ['commit-tree'] };
267
+ const signingError = new SigningError({ reason: reason, gitCommand: gitCommand }, ex);
268
+ this.context.hooks?.commits?.onSigningFailed?.(reason, _signingFormat, options?.source);
290
269
  throw signingError;
291
270
  }
292
271
  }
@@ -296,19 +275,19 @@ export class PatchGitSubProvider implements GitPatchSubProvider {
296
275
  }
297
276
 
298
277
  async createEmptyInitialCommit(repoPath: string): Promise<string> {
299
- const emptyTree = await this.git.exec({ cwd: repoPath, stdin: '' }, 'hash-object', '-t', 'tree', '--stdin');
300
- const result = await this.git.exec({ cwd: repoPath }, 'commit-tree', emptyTree.stdout.trim(), '-m', 'temp');
278
+ const emptyTree = await this.git.run({ cwd: repoPath, stdin: '' }, 'hash-object', '-t', 'tree', '--stdin');
279
+ const result = await this.git.run({ cwd: repoPath }, 'commit-tree', emptyTree.stdout.trim(), '-m', 'temp');
301
280
  // create refs/heads/main and point to it
302
- await this.git.exec({ cwd: repoPath }, 'update-ref', 'refs/heads/main', result.stdout.trim());
281
+ await this.git.run({ cwd: repoPath }, 'update-ref', 'refs/heads/main', result.stdout.trim());
303
282
  // point HEAD to the branch
304
- await this.git.exec({ cwd: repoPath }, 'symbolic-ref', 'HEAD', 'refs/heads/main');
283
+ await this.git.run({ cwd: repoPath }, 'symbolic-ref', 'HEAD', 'refs/heads/main');
305
284
  return result.stdout.trim();
306
285
  }
307
286
 
308
287
  @debug({ args: repoPath => ({ repoPath: repoPath }) })
309
288
  async validatePatch(repoPath: string | undefined, contents: string): Promise<boolean> {
310
289
  try {
311
- await this.git.exec({ cwd: repoPath, configs: gitConfigsLog, stdin: contents }, 'apply', '--check', '-');
290
+ await this.git.run({ cwd: repoPath, configs: gitConfigsLog, stdin: contents }, 'apply', '--check', '-');
312
291
  return true;
313
292
  } catch (ex) {
314
293
  if (ex instanceof RunError || ex instanceof GitError) {
@@ -43,10 +43,18 @@ export class PausedOperationsGitSubProvider implements GitPausedOperationsSubPro
43
43
  @debug()
44
44
  getPausedOperationStatus(
45
45
  repoPath: string,
46
+ options?: { force?: boolean },
46
47
  cancellation?: AbortSignal,
47
48
  ): Promise<GitPausedOperationStatus | undefined> {
48
49
  const scope = getScopedLogger();
49
50
 
51
+ // Self-heal callers (WIP refresh) bypass the cache so a missed `'pausedOp'` FS-watcher
52
+ // event (CLI-driven completion, torn-down secondary-worktree watcher) can't leave the
53
+ // status stuck — the readdir-based detection is cheap enough to repeat on every tick.
54
+ if (options?.force) {
55
+ this.cache.pausedOperationStatus.delete(repoPath);
56
+ }
57
+
50
58
  const status = this.cache.pausedOperationStatus.getOrCreate(repoPath, async _cancellable => {
51
59
  const gitDir = await this.provider.config.getGitDir(repoPath);
52
60
 
@@ -109,7 +117,7 @@ export class PausedOperationsGitSubProvider implements GitPausedOperationsSubPro
109
117
  const operation = sortedOperations[0];
110
118
  switch (operation) {
111
119
  case 'cherry-pick': {
112
- const result = await this.git.exec(
120
+ const result = await this.git.run(
113
121
  { cwd: repoPath, cancellation: cancellation, errors: 'ignore' },
114
122
  'rev-parse',
115
123
  '--quiet',
@@ -145,7 +153,7 @@ export class PausedOperationsGitSubProvider implements GitPausedOperationsSubPro
145
153
  } satisfies GitCherryPickStatus;
146
154
  }
147
155
  case 'merge': {
148
- const result = await this.git.exec(
156
+ const result = await this.git.run(
149
157
  { cwd: repoPath, cancellation: cancellation, errors: 'ignore' },
150
158
  'rev-parse',
151
159
  '--quiet',
@@ -197,7 +205,7 @@ export class PausedOperationsGitSubProvider implements GitPausedOperationsSubPro
197
205
  } satisfies GitMergeStatus;
198
206
  }
199
207
  case 'revert': {
200
- const result = await this.git.exec(
208
+ const result = await this.git.run(
201
209
  { cwd: repoPath, cancellation: cancellation, errors: 'ignore' },
202
210
  'rev-parse',
203
211
  '--quiet',
@@ -249,7 +257,7 @@ export class PausedOperationsGitSubProvider implements GitPausedOperationsSubPro
249
257
  stepsMessageResult,
250
258
  isInteractiveResult,
251
259
  ] = await Promise.allSettled([
252
- this.git.exec(
260
+ this.git.run(
253
261
  { cwd: repoPath, cancellation: cancellation, errors: 'ignore' },
254
262
  'rev-parse',
255
263
  '--quiet',
@@ -479,7 +487,7 @@ export class PausedOperationsGitSubProvider implements GitPausedOperationsSubPro
479
487
  const args = [status.type, options?.quit ? '--quit' : '--abort'];
480
488
 
481
489
  try {
482
- await this.git.exec({ cwd: repoPath, errors: 'throw' }, ...args);
490
+ await this.git.run({ cwd: repoPath, errors: 'throw' }, ...args);
483
491
  this.context.hooks?.cache?.onReset?.(repoPath, 'branches', 'status');
484
492
  this.context.hooks?.repository?.onChanged?.(repoPath, ['head', 'heads', 'index']);
485
493
  } catch (ex) {
@@ -514,7 +522,7 @@ export class PausedOperationsGitSubProvider implements GitPausedOperationsSubPro
514
522
  const args = [status.type, options?.skip ? '--skip' : '--continue'];
515
523
 
516
524
  try {
517
- await this.git.exec({ cwd: repoPath, errors: 'throw' }, ...args);
525
+ await this.git.run({ cwd: repoPath, errors: 'throw' }, ...args);
518
526
  this.context.hooks?.cache?.onReset?.(repoPath, 'branches', 'status');
519
527
  this.context.hooks?.repository?.onChanged?.(repoPath, ['head', 'heads', 'index']);
520
528
  } catch (ex) {
@@ -1,19 +1,27 @@
1
1
  import type { Cache } from '../../git/cache.js';
2
2
  import type { GitServiceContext } from '../../git/context.js';
3
3
  import type { GitBranch } from '../../git/models/branch.js';
4
- import type { GitReference } from '../../git/models/reference.js';
4
+ import type { GitReference, GitRefTip, RefRecord } from '../../git/models/reference.js';
5
5
  import { deletedOrMissing } from '../../git/models/revision.js';
6
6
  import type { GitTag } from '../../git/models/tag.js';
7
7
  import type { GitRefsSubProvider } from '../../git/providers/refs.js';
8
+ import type { GitCommandPriority } from '../../git/run.types.js';
9
+ import { isRemoteHEAD } from '../../git/utils/branch.utils.js';
8
10
  import { createReference } from '../../git/utils/reference.utils.js';
9
- import { isShaWithOptionalRevisionSuffix, isUncommitted } from '../../git/utils/revision.utils.js';
10
- import { isCancellationError } from '../../utils/cancellation.js';
11
+ import { isSha, isShaWithOptionalRevisionSuffix, isUncommitted } from '../../git/utils/revision.utils.js';
12
+ import { compareRefTips } from '../../git/utils/sorting.js';
13
+ import { CancellationError, isCancellationError } from '../../utils/cancellation.js';
11
14
  import { debug, trace } from '../../utils/decorators/log.js';
15
+ import { createDisposable } from '../../utils/disposable.js';
12
16
  import { getScopedLogger } from '../../utils/logger.scoped.js';
17
+ import { maybeStopWatch } from '../../utils/stopwatch.js';
18
+ import { iterateAsyncByDelimiter } from '../../utils/string.js';
13
19
  import type { Uri } from '../../utils/uri.js';
14
20
  import { toFsPath } from '../../utils/uri.js';
15
21
  import type { CliGitProviderInternal } from '../cliGitProvider.js';
16
22
  import type { Git } from '../exec/git.js';
23
+ import { gitConfigsBranch } from '../exec/git.js';
24
+ import { getRefParser } from '../parsers/refParser.js';
17
25
 
18
26
  export class RefsGitSubProvider implements GitRefsSubProvider {
19
27
  constructor(
@@ -26,29 +34,266 @@ export class RefsGitSubProvider implements GitRefsSubProvider {
26
34
  @debug()
27
35
  async checkIfCouldBeValidBranchOrTagName(repoPath: string, ref: string): Promise<boolean> {
28
36
  try {
29
- const result = await this.git.exec({ cwd: repoPath, errors: 'throw' }, 'check-ref-format', '--branch', ref);
37
+ const result = await this.git.run({ cwd: repoPath, errors: 'throw' }, 'check-ref-format', '--branch', ref);
30
38
  return Boolean(result.stdout.trim());
31
39
  } catch {
32
40
  return false;
33
41
  }
34
42
  }
35
43
 
44
+ /**
45
+ * Raw `git for-each-ref` records covering branches, remotes, and tags in a single pass.
46
+ * CLI-internal — siblings call via `this.provider.refs.getRefs(...)`. The `RefRecord` shape
47
+ * is `for-each-ref`-specific and intentionally absent from the public `GitRefsSubProvider`
48
+ * interface.
49
+ */
50
+ @debug()
51
+ async getRefs(repoPath: string, cancellation?: AbortSignal): Promise<RefRecord[]> {
52
+ if (!repoPath) return [];
53
+
54
+ const scope = getScopedLogger();
55
+
56
+ return this.cache.getRefs(
57
+ repoPath,
58
+ async (commonPath, cacheable, signal) => {
59
+ try {
60
+ const supported = await this.git.supported('git:for-each-ref');
61
+ const parser = getRefParser(supported);
62
+ const result = await this.git.run(
63
+ { cwd: commonPath, cancellation: signal, configs: gitConfigsBranch, errors: 'ignore' },
64
+ 'for-each-ref',
65
+ ...parser.arguments,
66
+ 'refs/heads/',
67
+ 'refs/remotes/',
68
+ 'refs/tags/',
69
+ );
70
+ if (!result?.stdout) return [];
71
+
72
+ using sw = maybeStopWatch(scope, { log: { onlyExit: true, level: 'debug' } });
73
+
74
+ const records = [...parser.parse(result.stdout)];
75
+
76
+ sw?.stop({ suffix: ` parsed ${records.length} ref records` });
77
+
78
+ return records;
79
+ } catch (ex) {
80
+ cacheable?.invalidate();
81
+ if (isCancellationError(ex)) throw ex;
82
+
83
+ scope?.error(ex);
84
+ return [];
85
+ }
86
+ },
87
+ cancellation,
88
+ );
89
+ }
90
+
91
+ @debug()
92
+ async getRefTips(
93
+ repoPath: string,
94
+ options?: { include?: ReadonlyArray<'heads' | 'remotes' | 'tags'> },
95
+ cancellation?: AbortSignal,
96
+ ): Promise<GitRefTip[]> {
97
+ if (!repoPath) return [];
98
+
99
+ const scope = getScopedLogger();
100
+
101
+ // Cache always holds the full set; subset filtering is applied on read so callers asking
102
+ // for different subsets share one cache entry.
103
+ const all = await this.cache.getRefTips(
104
+ repoPath,
105
+ async (_commonPath, _cacheable, signal) => {
106
+ const records = await this.getRefs(repoPath, signal);
107
+
108
+ using sw = maybeStopWatch(scope, { log: { onlyExit: true, level: 'debug' } });
109
+
110
+ const tips: GitRefTip[] = [];
111
+ for (const record of records) {
112
+ const fullName = record.name;
113
+ if (!fullName) continue;
114
+ // Skip refs/remotes/<remote>/HEAD — symbolic, not a real tip.
115
+ if (isRemoteHEAD(fullName)) continue;
116
+
117
+ let type: GitRefTip['type'];
118
+ let name: string;
119
+ if (fullName.startsWith('refs/heads/')) {
120
+ type = 'branch';
121
+ name = fullName.substring(11);
122
+ } else if (fullName.startsWith('refs/remotes/')) {
123
+ type = 'remote';
124
+ name = fullName.substring(13);
125
+ } else if (fullName.startsWith('refs/tags/')) {
126
+ type = 'tag';
127
+ name = fullName.substring(10);
128
+ } else {
129
+ continue;
130
+ }
131
+
132
+ // Annotated tags: peeledObjectname is the commit SHA; objectname is the tag-object SHA.
133
+ // Lightweight tags / branches: peeledObjectname is empty; objectname is already the commit SHA.
134
+ const sha = record.peeledObjectname || record.objectname;
135
+
136
+ tips.push({ type: type, name: name, fullName: fullName, sha: sha });
137
+ }
138
+
139
+ sw?.stop({ suffix: ` projected ${tips.length} ref tips` });
140
+
141
+ return tips;
142
+ },
143
+ cancellation,
144
+ );
145
+
146
+ const include = options?.include;
147
+ if (include == null || (include.includes('heads') && include.includes('remotes') && include.includes('tags'))) {
148
+ return all;
149
+ }
150
+
151
+ return all.filter(r => {
152
+ switch (r.type) {
153
+ case 'branch':
154
+ return include.includes('heads');
155
+ case 'remote':
156
+ return include.includes('remotes');
157
+ case 'tag':
158
+ return include.includes('tags');
159
+ }
160
+ });
161
+ }
162
+
163
+ @debug()
164
+ async getRefsContainingShas(
165
+ repoPath: string,
166
+ shas: ReadonlySet<string> | readonly string[],
167
+ oldestSha: string,
168
+ options?: { include?: ReadonlyArray<'heads' | 'remotes' | 'tags'> },
169
+ cancellation?: AbortSignal,
170
+ ): Promise<Map<string, GitRefTip[]>> {
171
+ const targetShas = shas instanceof Set ? shas : new Set(shas);
172
+ if (!targetShas.size || !oldestSha) return new Map();
173
+
174
+ const scope = getScopedLogger();
175
+
176
+ const tips = await this.getRefTips(repoPath, options, cancellation);
177
+ if (cancellation?.aborted) throw new CancellationError();
178
+ if (!tips.length) return new Map();
179
+
180
+ // Index tips by full ref name (for projection back to GitRefTip later) and seed the
181
+ // propagation map by tip SHA. Multiple refs sharing a tip (e.g. local + remote-tracking)
182
+ // collapse into one Set entry whose union covers all of them.
183
+ const tipsByName = new Map<string, GitRefTip>();
184
+ const propMap = new Map<string, Set<string>>();
185
+ for (const tip of tips) {
186
+ tipsByName.set(tip.fullName, tip);
187
+ let names = propMap.get(tip.sha);
188
+ if (names == null) {
189
+ names = new Set();
190
+ propMap.set(tip.sha, names);
191
+ }
192
+ names.add(tip.fullName);
193
+ }
194
+
195
+ using sw = maybeStopWatch(scope, { log: { onlyExit: true, level: 'debug' } });
196
+
197
+ // `^<oldestSha>^@` excludes the parents of <oldestSha> and everything older. When <oldestSha>
198
+ // is a root commit, `^@` resolves to nothing and the walk is naturally unbounded — git
199
+ // doesn't error in that case (no negative refs to apply).
200
+ const stream = this.git.stream(
201
+ { cwd: repoPath, cancellation: cancellation, configs: gitConfigsBranch },
202
+ 'rev-list',
203
+ '--topo-order',
204
+ '--parents',
205
+ '--all',
206
+ `^${oldestSha}^@`,
207
+ );
208
+ using _streamDisposer = createDisposable(() => void stream.return?.(undefined));
209
+
210
+ // Topological propagation: `--topo-order` emits all children of X before X's own line, so
211
+ // by the time we process "X P1 P2..." every child has already merged its set into X. We
212
+ // then forward X's accumulated set to each parent — one-pass and correct.
213
+ try {
214
+ for await (const line of iterateAsyncByDelimiter(stream, '\n')) {
215
+ if (cancellation?.aborted) throw new CancellationError();
216
+ if (!line) continue;
217
+
218
+ const firstSpace = line.indexOf(' ');
219
+ const sha = firstSpace === -1 ? line : line.substring(0, firstSpace);
220
+ if (!sha) continue;
221
+
222
+ const refs = propMap.get(sha);
223
+ if (!refs?.size) continue;
224
+
225
+ if (firstSpace === -1) continue; // No parents — nothing to propagate to
226
+
227
+ // Walk parent SHAs by index without splitting the whole line.
228
+ let start = firstSpace + 1;
229
+ while (start < line.length) {
230
+ const next = line.indexOf(' ', start);
231
+ const parentSha = next === -1 ? line.substring(start) : line.substring(start, next);
232
+ if (parentSha) {
233
+ let parentRefs = propMap.get(parentSha);
234
+ if (parentRefs == null) {
235
+ parentRefs = new Set(refs);
236
+ propMap.set(parentSha, parentRefs);
237
+ } else {
238
+ for (const name of refs) {
239
+ parentRefs.add(name);
240
+ }
241
+ }
242
+ }
243
+ if (next === -1) break;
244
+
245
+ start = next + 1;
246
+ }
247
+ }
248
+ } catch (ex) {
249
+ if (isCancellationError(ex)) throw ex;
250
+
251
+ scope?.error(ex);
252
+ return new Map();
253
+ }
254
+
255
+ // Project to targets, materialize GitRefTip[], sort.
256
+ const result = new Map<string, GitRefTip[]>();
257
+ for (const sha of targetShas) {
258
+ const names = propMap.get(sha);
259
+ if (!names?.size) continue;
260
+
261
+ const refs: GitRefTip[] = [];
262
+ for (const name of names) {
263
+ const tip = tipsByName.get(name);
264
+ if (tip != null) {
265
+ refs.push(tip);
266
+ }
267
+ }
268
+ refs.sort(compareRefTips);
269
+ result.set(sha, refs);
270
+ }
271
+
272
+ sw?.stop({ suffix: ` resolved ${result.size}/${targetShas.size} target shas` });
273
+
274
+ return result;
275
+ }
276
+
36
277
  @debug()
37
278
  async getMergeBase(
38
279
  repoPath: string,
39
280
  ref1: string,
40
281
  ref2: string,
41
- options?: { forkPoint?: boolean },
282
+ options?: { forkPoint?: boolean; priority?: GitCommandPriority },
42
283
  cancellation?: AbortSignal,
43
284
  ): Promise<string | undefined> {
44
285
  const scope = getScopedLogger();
45
286
 
46
287
  try {
47
- const result = await this.git.exec(
288
+ const result = await this.git.run(
48
289
  {
49
290
  cwd: repoPath,
50
291
  cancellation: cancellation,
292
+ // Why: ref1/ref2 are usually branch names; correctness relies on the gitResults cache being
293
+ // cleared on 'heads'/'remotes' events when refs move. Web (no fs watcher) sees up to
294
+ // `accessTTL` of staleness — acceptable trade-off for the perf win on graph/branch reads.
51
295
  caching: { cache: this.cache.gitResults, options: { accessTTL: 5 * 60 * 1000 } },
296
+ ...(options?.priority != null ? { priority: options.priority } : undefined),
52
297
  },
53
298
  'merge-base',
54
299
  options?.forkPoint ? '--fork-point' : undefined,
@@ -101,12 +346,22 @@ export class RefsGitSubProvider implements GitRefsSubProvider {
101
346
  async getSymbolicReferenceName(
102
347
  repoPath: string,
103
348
  ref: string,
349
+ options?: { priority?: GitCommandPriority },
104
350
  cancellation?: AbortSignal,
105
351
  ): Promise<string | undefined> {
106
352
  const supportsEndOfOptions = await this.git.supports('git:rev-parse:end-of-options');
107
353
 
108
- const result = await this.git.exec(
109
- { cwd: repoPath, cancellation: cancellation, errors: 'ignore' },
354
+ const result = await this.git.run(
355
+ {
356
+ cwd: repoPath,
357
+ cancellation: cancellation,
358
+ errors: 'ignore',
359
+ // Why: a fixed ref name's symbolic name is itself stable; only HEAD is mutable, and the
360
+ // gitResults cache is cleared on 'head' events. 60s TTL is the failsafe for watcher
361
+ // latency / web — matches the other "resolve symbolic state" calls in commits.ts.
362
+ caching: { cache: this.cache.gitResults, options: { accessTTL: 60 * 1000 } },
363
+ ...(options?.priority != null ? { priority: options.priority } : undefined),
364
+ },
110
365
  'rev-parse',
111
366
  '--verify',
112
367
  '--quiet',
@@ -164,12 +419,20 @@ export class RefsGitSubProvider implements GitRefsSubProvider {
164
419
 
165
420
  const supportsEndOfOptions = await this.git.supports('git:rev-parse:end-of-options');
166
421
 
167
- const result = await this.git.exec(
422
+ // Why: a SHA-only validation (no path suffix) is effectively immutable — 5-min TTL is safe.
423
+ // Otherwise the resolved SHA can shift on ref move (or working-tree change for path-scoped
424
+ // validation); rely on gitResults being cleared on 'head'/'heads'/'remotes' events, with 60s
425
+ // TTL as the failsafe for watcher latency / web.
426
+ const stable = relativePath == null && isSha(ref);
427
+ const result = await this.git.run(
168
428
  {
169
429
  cwd: repoPath,
170
430
  cancellation: cancellation,
171
431
  errors: 'ignore',
172
- caching: { cache: this.cache.gitResults, options: { accessTTL: 5 * 60 * 1000 } },
432
+ caching: {
433
+ cache: this.cache.gitResults,
434
+ options: { accessTTL: stable ? 5 * 60 * 1000 : 60 * 1000 },
435
+ },
173
436
  },
174
437
  'rev-parse',
175
438
  '--verify',
@@ -184,7 +447,7 @@ export class RefsGitSubProvider implements GitRefsSubProvider {
184
447
  const scope = getScopedLogger();
185
448
 
186
449
  try {
187
- await this.git.exec({ cwd: repoPath, cancellation: cancellation }, 'update-ref', ref, newRef);
450
+ await this.git.run({ cwd: repoPath, cancellation: cancellation }, 'update-ref', ref, newRef);
188
451
  } catch (ex) {
189
452
  scope?.error(ex);
190
453
  if (isCancellationError(ex)) throw ex;
@@ -41,7 +41,7 @@ export class RemotesGitSubProvider extends RemotesGitProviderBase implements Git
41
41
  const remoteProviderMatcher = createRemoteProviderMatcher(configs, this.context.remotes);
42
42
 
43
43
  try {
44
- const result = await this.git.exec(
44
+ const result = await this.git.run(
45
45
  {
46
46
  cwd: repoPath,
47
47
  cancellation: signal,
@@ -79,7 +79,7 @@ export class RemotesGitSubProvider extends RemotesGitProviderBase implements Git
79
79
  @gate()
80
80
  @debug()
81
81
  async addRemote(repoPath: string, name: string, url: string, options?: { fetch?: boolean }): Promise<void> {
82
- await this.git.exec({ cwd: repoPath }, 'remote', 'add', options?.fetch ? '-f' : undefined, name, url);
82
+ await this.git.run({ cwd: repoPath }, 'remote', 'add', options?.fetch ? '-f' : undefined, name, url);
83
83
  this.context.hooks?.cache?.onReset?.(repoPath, 'remotes');
84
84
  this.context.hooks?.repository?.onChanged?.(repoPath, ['remotes']);
85
85
  }
@@ -100,7 +100,7 @@ export class RemotesGitSubProvider extends RemotesGitProviderBase implements Git
100
100
  @gate()
101
101
  @debug()
102
102
  async pruneRemote(repoPath: string, name: string): Promise<void> {
103
- await this.git.exec({ cwd: repoPath }, 'remote', 'prune', name);
103
+ await this.git.run({ cwd: repoPath }, 'remote', 'prune', name);
104
104
  this.context.hooks?.cache?.onReset?.(repoPath, 'remotes', 'branches');
105
105
  this.context.hooks?.repository?.onChanged?.(repoPath, ['remotes']);
106
106
  }
@@ -108,7 +108,7 @@ export class RemotesGitSubProvider extends RemotesGitProviderBase implements Git
108
108
  @gate()
109
109
  @debug()
110
110
  async removeRemote(repoPath: string, name: string): Promise<void> {
111
- await this.git.exec({ cwd: repoPath }, 'remote', 'remove', name);
111
+ await this.git.run({ cwd: repoPath }, 'remote', 'remove', name);
112
112
  this.context.hooks?.cache?.onReset?.(repoPath, 'remotes');
113
113
  this.context.hooks?.repository?.onChanged?.(repoPath, ['remotes']);
114
114
  }