@gitkraken/core-gitlens 0.2.0 → 0.3.1

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 (448) hide show
  1. package/CHANGELOG.md +11 -1
  2. package/dist/git/cache.d.ts +38 -8
  3. package/dist/git/cache.d.ts.map +1 -1
  4. package/dist/git/cache.js +120 -55
  5. package/dist/git/cache.js.map +1 -1
  6. package/dist/git/context.d.ts +19 -0
  7. package/dist/git/context.d.ts.map +1 -1
  8. package/dist/git/context.js.map +1 -1
  9. package/dist/git/features.d.ts +1 -1
  10. package/dist/git/features.d.ts.map +1 -1
  11. package/dist/git/features.js +1 -0
  12. package/dist/git/features.js.map +1 -1
  13. package/dist/git/models/commit.d.ts.map +1 -1
  14. package/dist/git/models/commit.js.map +1 -1
  15. package/dist/git/models/graph.d.ts +96 -0
  16. package/dist/git/models/graph.d.ts.map +1 -1
  17. package/dist/git/models/graph.js +24 -1
  18. package/dist/git/models/graph.js.map +1 -1
  19. package/dist/git/models/reference.d.ts +31 -0
  20. package/dist/git/models/reference.d.ts.map +1 -1
  21. package/dist/git/models/remote.d.ts.map +1 -1
  22. package/dist/git/models/remote.js.map +1 -1
  23. package/dist/git/models/remoteProvider.d.ts +1 -0
  24. package/dist/git/models/remoteProvider.d.ts.map +1 -1
  25. package/dist/git/models/remoteProvider.js.map +1 -1
  26. package/dist/git/models/repository.d.ts +30 -13
  27. package/dist/git/models/repository.d.ts.map +1 -1
  28. package/dist/git/models/repository.js +89 -87
  29. package/dist/git/models/repository.js.map +1 -1
  30. package/dist/git/models/search.d.ts +2 -2
  31. package/dist/git/models/search.d.ts.map +1 -1
  32. package/dist/git/models/statusFile.d.ts +9 -0
  33. package/dist/git/models/statusFile.d.ts.map +1 -1
  34. package/dist/git/models/statusFile.js +11 -0
  35. package/dist/git/models/statusFile.js.map +1 -1
  36. package/dist/git/models/worktree.d.ts +4 -1
  37. package/dist/git/models/worktree.d.ts.map +1 -1
  38. package/dist/git/models/worktree.js +2 -2
  39. package/dist/git/models/worktree.js.map +1 -1
  40. package/dist/git/parsers/diffParser.d.ts.map +1 -1
  41. package/dist/git/parsers/diffParser.js.map +1 -1
  42. package/dist/git/providers/branches.d.ts +15 -4
  43. package/dist/git/providers/branches.d.ts.map +1 -1
  44. package/dist/git/providers/commits.d.ts +4 -0
  45. package/dist/git/providers/commits.d.ts.map +1 -1
  46. package/dist/git/providers/config.d.ts +5 -4
  47. package/dist/git/providers/config.d.ts.map +1 -1
  48. package/dist/git/providers/operations.d.ts +61 -12
  49. package/dist/git/providers/operations.d.ts.map +1 -1
  50. package/dist/git/providers/pausedOperations.d.ts +3 -1
  51. package/dist/git/providers/pausedOperations.d.ts.map +1 -1
  52. package/dist/git/providers/refs.d.ts +23 -2
  53. package/dist/git/providers/refs.d.ts.map +1 -1
  54. package/dist/git/providers/staging.d.ts +16 -0
  55. package/dist/git/providers/staging.d.ts.map +1 -1
  56. package/dist/git/providers/status.d.ts +4 -1
  57. package/dist/git/providers/status.d.ts.map +1 -1
  58. package/dist/git/remotes/azure-devops.d.ts.map +1 -1
  59. package/dist/git/remotes/azure-devops.js.map +1 -1
  60. package/dist/git/remotes/custom.d.ts +2 -0
  61. package/dist/git/remotes/custom.d.ts.map +1 -1
  62. package/dist/git/remotes/custom.js +20 -0
  63. package/dist/git/remotes/custom.js.map +1 -1
  64. package/dist/git/{exec.types.d.ts → run.types.d.ts} +22 -3
  65. package/dist/git/run.types.d.ts.map +1 -0
  66. package/dist/git/run.types.js +2 -0
  67. package/dist/git/run.types.js.map +1 -0
  68. package/dist/git/service.d.ts.map +1 -1
  69. package/dist/git/service.js.map +1 -1
  70. package/dist/git/utils/autolink.utils.d.ts.map +1 -1
  71. package/dist/git/utils/autolink.utils.js.map +1 -1
  72. package/dist/git/utils/blame.utils.d.ts.map +1 -1
  73. package/dist/git/utils/blame.utils.js.map +1 -1
  74. package/dist/git/utils/conflictResolution.utils.d.ts +6 -0
  75. package/dist/git/utils/conflictResolution.utils.d.ts.map +1 -0
  76. package/dist/git/utils/conflictResolution.utils.js +25 -0
  77. package/dist/git/utils/conflictResolution.utils.js.map +1 -0
  78. package/dist/git/utils/contributor.utils.d.ts +3 -0
  79. package/dist/git/utils/contributor.utils.d.ts.map +1 -1
  80. package/dist/git/utils/contributor.utils.js +22 -0
  81. package/dist/git/utils/contributor.utils.js.map +1 -1
  82. package/dist/git/utils/fileStatus.utils.d.ts +2 -1
  83. package/dist/git/utils/fileStatus.utils.d.ts.map +1 -1
  84. package/dist/git/utils/fileStatus.utils.js +4 -0
  85. package/dist/git/utils/fileStatus.utils.js.map +1 -1
  86. package/dist/git/utils/reachability.utils.d.ts +37 -0
  87. package/dist/git/utils/reachability.utils.d.ts.map +1 -0
  88. package/dist/git/utils/reachability.utils.js +96 -0
  89. package/dist/git/utils/reachability.utils.js.map +1 -0
  90. package/dist/git/utils/search.utils.d.ts.map +1 -1
  91. package/dist/git/utils/search.utils.js +3 -0
  92. package/dist/git/utils/search.utils.js.map +1 -1
  93. package/dist/git/utils/sorting.d.ts +8 -0
  94. package/dist/git/utils/sorting.d.ts.map +1 -1
  95. package/dist/git/utils/sorting.js +15 -0
  96. package/dist/git/utils/sorting.js.map +1 -1
  97. package/dist/git/utils/status.utils.d.ts.map +1 -1
  98. package/dist/git/utils/status.utils.js.map +1 -1
  99. package/dist/git/watching/classifyChange.d.ts.map +1 -1
  100. package/dist/git/watching/classifyChange.js +8 -0
  101. package/dist/git/watching/classifyChange.js.map +1 -1
  102. package/dist/git/watching/gitIgnoreFilter.js +1 -1
  103. package/dist/git/watching/gitIgnoreFilter.js.map +1 -1
  104. package/dist/git/watching/initWatcher.d.ts.map +1 -1
  105. package/dist/git/watching/initWatcher.js.map +1 -1
  106. package/dist/git/watching/watchGroup.d.ts.map +1 -1
  107. package/dist/git/watching/watchGroup.js.map +1 -1
  108. package/dist/git/watching/watchService.d.ts +4 -2
  109. package/dist/git/watching/watchService.d.ts.map +1 -1
  110. package/dist/git/watching/watchService.js +31 -6
  111. package/dist/git/watching/watchService.js.map +1 -1
  112. package/dist/git/watching/watchSession.d.ts +14 -12
  113. package/dist/git/watching/watchSession.d.ts.map +1 -1
  114. package/dist/git/watching/watchSession.js +56 -55
  115. package/dist/git/watching/watchSession.js.map +1 -1
  116. package/dist/git-cli/exec/exec.types.d.ts +1 -1
  117. package/dist/git-cli/exec/exec.types.d.ts.map +1 -1
  118. package/dist/git-cli/exec/git.d.ts +3 -3
  119. package/dist/git-cli/exec/git.d.ts.map +1 -1
  120. package/dist/git-cli/exec/git.js.map +1 -1
  121. package/dist/git-cli/exec/gitQueue.d.ts +10 -2
  122. package/dist/git-cli/exec/gitQueue.d.ts.map +1 -1
  123. package/dist/git-cli/exec/gitQueue.js +39 -12
  124. package/dist/git-cli/exec/gitQueue.js.map +1 -1
  125. package/dist/git-cli/parsers/blameParser.d.ts.map +1 -1
  126. package/dist/git-cli/parsers/blameParser.js.map +1 -1
  127. package/dist/git-cli/parsers/logParser.js.map +1 -1
  128. package/dist/git-cli/parsers/refParser.d.ts +3 -30
  129. package/dist/git-cli/parsers/refParser.d.ts.map +1 -1
  130. package/dist/git-cli/parsers/refParser.js +30 -30
  131. package/dist/git-cli/parsers/refParser.js.map +1 -1
  132. package/dist/git-cli/providers/blame.d.ts.map +1 -1
  133. package/dist/git-cli/providers/blame.js.map +1 -1
  134. package/dist/git-cli/providers/branches.d.ts +15 -5
  135. package/dist/git-cli/providers/branches.d.ts.map +1 -1
  136. package/dist/git-cli/providers/branches.js +99 -68
  137. package/dist/git-cli/providers/branches.js.map +1 -1
  138. package/dist/git-cli/providers/commits.d.ts +1 -0
  139. package/dist/git-cli/providers/commits.d.ts.map +1 -1
  140. package/dist/git-cli/providers/commits.js +86 -30
  141. package/dist/git-cli/providers/commits.js.map +1 -1
  142. package/dist/git-cli/providers/config.d.ts +19 -6
  143. package/dist/git-cli/providers/config.d.ts.map +1 -1
  144. package/dist/git-cli/providers/config.js +86 -38
  145. package/dist/git-cli/providers/config.js.map +1 -1
  146. package/dist/git-cli/providers/diff.d.ts.map +1 -1
  147. package/dist/git-cli/providers/diff.js +5 -3
  148. package/dist/git-cli/providers/diff.js.map +1 -1
  149. package/dist/git-cli/providers/graph.d.ts.map +1 -1
  150. package/dist/git-cli/providers/graph.js +139 -16
  151. package/dist/git-cli/providers/graph.js.map +1 -1
  152. package/dist/git-cli/providers/operations.d.ts +17 -14
  153. package/dist/git-cli/providers/operations.d.ts.map +1 -1
  154. package/dist/git-cli/providers/operations.js +135 -63
  155. package/dist/git-cli/providers/operations.js.map +1 -1
  156. package/dist/git-cli/providers/patch.d.ts.map +1 -1
  157. package/dist/git-cli/providers/patch.js.map +1 -1
  158. package/dist/git-cli/providers/pausedOperations.d.ts +3 -1
  159. package/dist/git-cli/providers/pausedOperations.d.ts.map +1 -1
  160. package/dist/git-cli/providers/pausedOperations.js +7 -1
  161. package/dist/git-cli/providers/pausedOperations.js.map +1 -1
  162. package/dist/git-cli/providers/refs.d.ts +19 -2
  163. package/dist/git-cli/providers/refs.d.ts.map +1 -1
  164. package/dist/git-cli/providers/refs.js +286 -2
  165. package/dist/git-cli/providers/refs.js.map +1 -1
  166. package/dist/git-cli/providers/revision.js.map +1 -1
  167. package/dist/git-cli/providers/staging.d.ts +6 -0
  168. package/dist/git-cli/providers/staging.d.ts.map +1 -1
  169. package/dist/git-cli/providers/staging.js +32 -0
  170. package/dist/git-cli/providers/staging.js.map +1 -1
  171. package/dist/git-cli/providers/stash.d.ts.map +1 -1
  172. package/dist/git-cli/providers/stash.js +20 -2
  173. package/dist/git-cli/providers/stash.js.map +1 -1
  174. package/dist/git-cli/providers/status.d.ts +4 -1
  175. package/dist/git-cli/providers/status.d.ts.map +1 -1
  176. package/dist/git-cli/providers/status.js +8 -4
  177. package/dist/git-cli/providers/status.js.map +1 -1
  178. package/dist/git-cli/providers/tags.d.ts.map +1 -1
  179. package/dist/git-cli/providers/tags.js +10 -6
  180. package/dist/git-cli/providers/tags.js.map +1 -1
  181. package/dist/ipc/discovery.d.ts +49 -0
  182. package/dist/ipc/discovery.d.ts.map +1 -0
  183. package/dist/ipc/discovery.js +147 -0
  184. package/dist/ipc/discovery.js.map +1 -0
  185. package/dist/ipc/ipcServer.d.ts +20 -0
  186. package/dist/ipc/ipcServer.d.ts.map +1 -0
  187. package/dist/ipc/ipcServer.js +162 -0
  188. package/dist/ipc/ipcServer.js.map +1 -0
  189. package/dist/plus/agents/providers/claudeCodeProvider.d.ts +167 -0
  190. package/dist/plus/agents/providers/claudeCodeProvider.d.ts.map +1 -0
  191. package/dist/plus/agents/providers/claudeCodeProvider.js +1786 -0
  192. package/dist/plus/agents/providers/claudeCodeProvider.js.map +1 -0
  193. package/dist/plus/agents/providers/claudeCodeTranscript.d.ts +36 -0
  194. package/dist/plus/agents/providers/claudeCodeTranscript.d.ts.map +1 -0
  195. package/dist/plus/agents/providers/claudeCodeTranscript.js +171 -0
  196. package/dist/plus/agents/providers/claudeCodeTranscript.js.map +1 -0
  197. package/dist/plus/agents/sanitizePrompt.d.ts +15 -0
  198. package/dist/plus/agents/sanitizePrompt.d.ts.map +1 -0
  199. package/dist/plus/agents/sanitizePrompt.js +103 -0
  200. package/dist/plus/agents/sanitizePrompt.js.map +1 -0
  201. package/dist/plus/agents/stateMachine.d.ts +32 -0
  202. package/dist/plus/agents/stateMachine.d.ts.map +1 -0
  203. package/dist/plus/agents/stateMachine.js +180 -0
  204. package/dist/plus/agents/stateMachine.js.map +1 -0
  205. package/dist/plus/agents/types.d.ts +254 -0
  206. package/dist/plus/agents/types.d.ts.map +1 -0
  207. package/dist/plus/agents/types.js +49 -0
  208. package/dist/plus/agents/types.js.map +1 -0
  209. package/dist/plus/ai/errors.d.ts +4 -1
  210. package/dist/plus/ai/errors.d.ts.map +1 -1
  211. package/dist/plus/ai/errors.js +38 -0
  212. package/dist/plus/ai/errors.js.map +1 -1
  213. package/dist/plus/ai/models/model.d.ts +1 -1
  214. package/dist/plus/ai/models/model.d.ts.map +1 -1
  215. package/dist/plus/ai/models/model.js.map +1 -1
  216. package/dist/plus/ai/models/promptTemplates.d.ts +11 -2
  217. package/dist/plus/ai/models/promptTemplates.d.ts.map +1 -1
  218. package/dist/plus/ai/models/provider.d.ts +3 -0
  219. package/dist/plus/ai/models/provider.d.ts.map +1 -1
  220. package/dist/plus/ai/prompts.d.ts +1 -0
  221. package/dist/plus/ai/prompts.d.ts.map +1 -1
  222. package/dist/plus/ai/prompts.js +48 -8
  223. package/dist/plus/ai/prompts.js.map +1 -1
  224. package/dist/plus/ai/providers/gitkrakenProvider.d.ts +1 -1
  225. package/dist/plus/ai/providers/gitkrakenProvider.d.ts.map +1 -1
  226. package/dist/plus/ai/providers/gitkrakenProvider.js +4 -1
  227. package/dist/plus/ai/providers/gitkrakenProvider.js.map +1 -1
  228. package/dist/plus/ai/providers/openAICompatibleProviderBase.d.ts +4 -3
  229. package/dist/plus/ai/providers/openAICompatibleProviderBase.d.ts.map +1 -1
  230. package/dist/plus/ai/providers/openAICompatibleProviderBase.js +9 -6
  231. package/dist/plus/ai/providers/openAICompatibleProviderBase.js.map +1 -1
  232. package/dist/plus/ai/utils/ai.utils.d.ts.map +1 -1
  233. package/dist/plus/ai/utils/ai.utils.js +2 -0
  234. package/dist/plus/ai/utils/ai.utils.js.map +1 -1
  235. package/dist/plus/ai/utils/results.utils.d.ts.map +1 -1
  236. package/dist/plus/ai/utils/results.utils.js.map +1 -1
  237. package/dist/plus/git-github/api/github.d.ts +12 -1
  238. package/dist/plus/git-github/api/github.d.ts.map +1 -1
  239. package/dist/plus/git-github/api/github.js +245 -51
  240. package/dist/plus/git-github/api/github.js.map +1 -1
  241. package/dist/plus/git-github/api/types.d.ts +8 -0
  242. package/dist/plus/git-github/api/types.d.ts.map +1 -1
  243. package/dist/plus/git-github/models.d.ts +1 -1
  244. package/dist/plus/git-github/models.d.ts.map +1 -1
  245. package/dist/plus/git-github/models.js.map +1 -1
  246. package/dist/plus/git-github/providers/github/blame.d.ts.map +1 -1
  247. package/dist/plus/git-github/providers/github/blame.js.map +1 -1
  248. package/dist/plus/git-github/providers/github/branches.d.ts +5 -1
  249. package/dist/plus/git-github/providers/github/branches.d.ts.map +1 -1
  250. package/dist/plus/git-github/providers/github/branches.js +47 -24
  251. package/dist/plus/git-github/providers/github/branches.js.map +1 -1
  252. package/dist/plus/git-github/providers/github/commits.d.ts.map +1 -1
  253. package/dist/plus/git-github/providers/github/commits.js +144 -92
  254. package/dist/plus/git-github/providers/github/commits.js.map +1 -1
  255. package/dist/plus/git-github/providers/github/diff.d.ts +1 -1
  256. package/dist/plus/git-github/providers/github/diff.d.ts.map +1 -1
  257. package/dist/plus/git-github/providers/github/diff.js +23 -9
  258. package/dist/plus/git-github/providers/github/diff.js.map +1 -1
  259. package/dist/plus/git-github/providers/github/refs.d.ts +9 -1
  260. package/dist/plus/git-github/providers/github/refs.d.ts.map +1 -1
  261. package/dist/plus/git-github/providers/github/refs.js +39 -14
  262. package/dist/plus/git-github/providers/github/refs.js.map +1 -1
  263. package/dist/plus/git-github/providers/github/revision.d.ts.map +1 -1
  264. package/dist/plus/git-github/providers/github/revision.js +1 -2
  265. package/dist/plus/git-github/providers/github/revision.js.map +1 -1
  266. package/dist/plus/git-github/providers/github/status.d.ts +4 -1
  267. package/dist/plus/git-github/providers/github/status.d.ts.map +1 -1
  268. package/dist/plus/git-github/providers/github/status.js +1 -1
  269. package/dist/plus/git-github/providers/github/status.js.map +1 -1
  270. package/dist/plus/git-github/providers/github/tags.d.ts.map +1 -1
  271. package/dist/plus/git-github/providers/github/tags.js +35 -36
  272. package/dist/plus/git-github/providers/github/tags.js.map +1 -1
  273. package/dist/plus/git-github/providers/githubGitProvider.d.ts.map +1 -1
  274. package/dist/plus/git-github/providers/githubGitProvider.js.map +1 -1
  275. package/dist/utils/color.d.ts.map +1 -1
  276. package/dist/utils/color.js.map +1 -1
  277. package/dist/utils/date.d.ts.map +1 -1
  278. package/dist/utils/date.js +6 -0
  279. package/dist/utils/date.js.map +1 -1
  280. package/dist/utils/debounce.js +1 -1
  281. package/dist/utils/decorators/serializable.d.ts.map +1 -1
  282. package/dist/utils/decorators/serializable.js.map +1 -1
  283. package/dist/utils/dedupedAsyncCache.d.ts +37 -0
  284. package/dist/utils/dedupedAsyncCache.d.ts.map +1 -0
  285. package/dist/utils/dedupedAsyncCache.js +68 -0
  286. package/dist/utils/dedupedAsyncCache.js.map +1 -0
  287. package/dist/utils/diff.d.ts +2 -0
  288. package/dist/utils/diff.d.ts.map +1 -0
  289. package/dist/utils/diff.js +53 -0
  290. package/dist/utils/diff.js.map +1 -0
  291. package/dist/utils/disposable.d.ts.map +1 -1
  292. package/dist/utils/disposable.js.map +1 -1
  293. package/dist/utils/env/node/exec.d.ts.map +1 -1
  294. package/dist/utils/env/node/exec.js.map +1 -1
  295. package/dist/utils/error.d.ts.map +1 -1
  296. package/dist/utils/error.js.map +1 -1
  297. package/dist/utils/iterable.d.ts +7 -1
  298. package/dist/utils/iterable.d.ts.map +1 -1
  299. package/dist/utils/iterable.js +12 -4
  300. package/dist/utils/iterable.js.map +1 -1
  301. package/dist/utils/logger.d.ts.map +1 -1
  302. package/dist/utils/logger.js.map +1 -1
  303. package/dist/utils/lruMap.d.ts +9 -0
  304. package/dist/utils/lruMap.d.ts.map +1 -1
  305. package/dist/utils/lruMap.js +26 -4
  306. package/dist/utils/lruMap.js.map +1 -1
  307. package/dist/utils/markdown.d.ts.map +1 -1
  308. package/dist/utils/markdown.js.map +1 -1
  309. package/dist/utils/mru.d.ts.map +1 -1
  310. package/dist/utils/mru.js.map +1 -1
  311. package/dist/utils/object.d.ts +22 -1
  312. package/dist/utils/object.d.ts.map +1 -1
  313. package/dist/utils/object.js +56 -3
  314. package/dist/utils/object.js.map +1 -1
  315. package/dist/utils/paging.js +14 -15
  316. package/dist/utils/paging.js.map +1 -1
  317. package/dist/utils/path.d.ts.map +1 -1
  318. package/dist/utils/path.js.map +1 -1
  319. package/dist/utils/promise.d.ts +1 -0
  320. package/dist/utils/promise.d.ts.map +1 -1
  321. package/dist/utils/promise.js +17 -0
  322. package/dist/utils/promise.js.map +1 -1
  323. package/dist/utils/promiseCache.d.ts +10 -0
  324. package/dist/utils/promiseCache.d.ts.map +1 -1
  325. package/dist/utils/promiseCache.js +34 -4
  326. package/dist/utils/promiseCache.js.map +1 -1
  327. package/dist/utils/string.d.ts.map +1 -1
  328. package/dist/utils/string.js +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.map +1 -1
  333. package/dist/utils/version.js.map +1 -1
  334. package/package.json +13 -1
  335. package/src/git/cache.ts +192 -90
  336. package/src/git/context.ts +21 -0
  337. package/src/git/features.ts +2 -0
  338. package/src/git/models/commit.ts +1 -0
  339. package/src/git/models/graph.ts +97 -0
  340. package/src/git/models/reference.ts +33 -0
  341. package/src/git/models/remote.ts +1 -0
  342. package/src/git/models/remoteProvider.ts +1 -0
  343. package/src/git/models/repository.ts +105 -96
  344. package/src/git/models/search.ts +2 -2
  345. package/src/git/models/statusFile.ts +12 -0
  346. package/src/git/models/worktree.ts +10 -2
  347. package/src/git/parsers/diffParser.ts +2 -0
  348. package/src/git/providers/branches.ts +22 -4
  349. package/src/git/providers/commits.ts +4 -0
  350. package/src/git/providers/config.ts +3 -5
  351. package/src/git/providers/operations.ts +65 -1
  352. package/src/git/providers/pausedOperations.ts +1 -0
  353. package/src/git/providers/refs.ts +32 -3
  354. package/src/git/providers/staging.ts +12 -0
  355. package/src/git/providers/status.ts +6 -1
  356. package/src/git/remotes/azure-devops.ts +2 -0
  357. package/src/git/remotes/custom.ts +23 -0
  358. package/src/git/{exec.types.ts → run.types.ts} +22 -2
  359. package/src/git/service.ts +1 -0
  360. package/src/git/utils/autolink.utils.ts +1 -0
  361. package/src/git/utils/blame.utils.ts +2 -0
  362. package/src/git/utils/conflictResolution.utils.ts +31 -0
  363. package/src/git/utils/contributor.utils.ts +24 -0
  364. package/src/git/utils/fileStatus.utils.ts +7 -1
  365. package/src/git/utils/reachability.utils.ts +109 -0
  366. package/src/git/utils/search.utils.ts +2 -0
  367. package/src/git/utils/sorting.ts +17 -0
  368. package/src/git/utils/status.utils.ts +1 -0
  369. package/src/git/watching/classifyChange.ts +9 -0
  370. package/src/git/watching/gitIgnoreFilter.ts +2 -2
  371. package/src/git/watching/initWatcher.ts +2 -0
  372. package/src/git/watching/watchGroup.ts +3 -0
  373. package/src/git/watching/watchService.ts +45 -7
  374. package/src/git/watching/watchSession.ts +71 -55
  375. package/src/git-cli/exec/exec.types.ts +2 -2
  376. package/src/git-cli/exec/git.ts +6 -5
  377. package/src/git-cli/exec/gitQueue.ts +41 -12
  378. package/src/git-cli/parsers/blameParser.ts +1 -0
  379. package/src/git-cli/parsers/logParser.ts +1 -0
  380. package/src/git-cli/parsers/refParser.ts +33 -34
  381. package/src/git-cli/providers/blame.ts +1 -0
  382. package/src/git-cli/providers/branches.ts +165 -93
  383. package/src/git-cli/providers/commits.ts +107 -37
  384. package/src/git-cli/providers/config.ts +101 -48
  385. package/src/git-cli/providers/diff.ts +10 -3
  386. package/src/git-cli/providers/graph.ts +156 -16
  387. package/src/git-cli/providers/operations.ts +208 -83
  388. package/src/git-cli/providers/patch.ts +1 -0
  389. package/src/git-cli/providers/pausedOperations.ts +8 -0
  390. package/src/git-cli/providers/refs.ts +247 -3
  391. package/src/git-cli/providers/revision.ts +2 -2
  392. package/src/git-cli/providers/staging.ts +33 -0
  393. package/src/git-cli/providers/stash.ts +20 -2
  394. package/src/git-cli/providers/status.ts +24 -5
  395. package/src/git-cli/providers/tags.ts +15 -16
  396. package/src/ipc/discovery.ts +186 -0
  397. package/src/ipc/ipcServer.ts +171 -0
  398. package/src/plus/agents/providers/claudeCodeProvider.ts +2122 -0
  399. package/src/plus/agents/providers/claudeCodeTranscript.ts +214 -0
  400. package/src/plus/agents/sanitizePrompt.ts +109 -0
  401. package/src/plus/agents/stateMachine.ts +197 -0
  402. package/src/plus/agents/types.ts +325 -0
  403. package/src/plus/ai/errors.ts +40 -0
  404. package/src/plus/ai/models/model.ts +1 -0
  405. package/src/plus/ai/models/promptTemplates.ts +13 -0
  406. package/src/plus/ai/models/provider.ts +7 -1
  407. package/src/plus/ai/prompts.ts +49 -8
  408. package/src/plus/ai/providers/gitkrakenProvider.ts +4 -0
  409. package/src/plus/ai/providers/openAICompatibleProviderBase.ts +21 -4
  410. package/src/plus/ai/utils/ai.utils.ts +2 -0
  411. package/src/plus/ai/utils/results.utils.ts +2 -0
  412. package/src/plus/git-github/api/github.ts +315 -57
  413. package/src/plus/git-github/api/types.ts +15 -0
  414. package/src/plus/git-github/models.ts +1 -1
  415. package/src/plus/git-github/providers/github/blame.ts +2 -0
  416. package/src/plus/git-github/providers/github/branches.ts +61 -31
  417. package/src/plus/git-github/providers/github/commits.ts +231 -160
  418. package/src/plus/git-github/providers/github/diff.ts +27 -19
  419. package/src/plus/git-github/providers/github/refs.ts +58 -23
  420. package/src/plus/git-github/providers/github/revision.ts +1 -2
  421. package/src/plus/git-github/providers/github/status.ts +6 -1
  422. package/src/plus/git-github/providers/github/tags.ts +61 -62
  423. package/src/plus/git-github/providers/githubGitProvider.ts +1 -0
  424. package/src/utils/color.ts +2 -0
  425. package/src/utils/date.ts +5 -0
  426. package/src/utils/debounce.ts +1 -1
  427. package/src/utils/decorators/serializable.ts +1 -0
  428. package/src/utils/dedupedAsyncCache.ts +74 -0
  429. package/src/utils/diff.ts +61 -0
  430. package/src/utils/disposable.ts +2 -0
  431. package/src/utils/env/node/exec.ts +2 -0
  432. package/src/utils/error.ts +1 -0
  433. package/src/utils/iterable.ts +17 -3
  434. package/src/utils/logger.ts +1 -0
  435. package/src/utils/lruMap.ts +29 -4
  436. package/src/utils/markdown.ts +1 -0
  437. package/src/utils/mru.ts +2 -0
  438. package/src/utils/object.ts +55 -4
  439. package/src/utils/paging.ts +14 -14
  440. package/src/utils/path.ts +1 -0
  441. package/src/utils/promise.ts +22 -0
  442. package/src/utils/promiseCache.ts +48 -16
  443. package/src/utils/string.ts +3 -1
  444. package/src/utils/uri.ts +1 -0
  445. package/src/utils/version.ts +1 -0
  446. package/dist/git/exec.types.d.ts.map +0 -1
  447. package/dist/git/exec.types.js +0 -2
  448. package/dist/git/exec.types.js.map +0 -1
@@ -41,7 +41,7 @@ import { escapeRegex } from '../../utils/string.js';
41
41
  import type { Uri } from '../../utils/uri.js';
42
42
  import { fileUri, joinUriPath, toFsPath } from '../../utils/uri.js';
43
43
  import type { CliGitProviderInternal } from '../cliGitProvider.js';
44
- import type { GitExecOptions, GitResult } from '../exec/exec.types.js';
44
+ import type { GitResult, GitRunOptions } from '../exec/exec.types.js';
45
45
  import type { Git } from '../exec/git.js';
46
46
  import { gitConfigsLog, gitConfigsLogWithFiles, GitErrors } from '../exec/git.js';
47
47
  import type {
@@ -129,6 +129,30 @@ export class CommitsGitSubProvider implements GitCommitsSubProvider {
129
129
  return isNaN(count) ? undefined : count;
130
130
  }
131
131
 
132
+ @debug({ exit: true })
133
+ async hasUnpublishedCommits(
134
+ repoPath: string,
135
+ rev: string,
136
+ cancellation?: AbortSignal,
137
+ ): Promise<boolean | undefined> {
138
+ // `<rev> --not --remotes` = commits reachable from `rev` but not from any remote-tracking ref.
139
+ // `--max-count=1` early-exits at the first such commit, so this is a presence probe, not a count.
140
+ const result = await this.git.run(
141
+ { cwd: repoPath, cancellation: cancellation, errors: 'ignore' },
142
+ 'rev-list',
143
+ '--max-count=1',
144
+ rev,
145
+ '--not',
146
+ '--remotes',
147
+ '--',
148
+ );
149
+ if (result.cancelled || cancellation?.aborted) {
150
+ throw new CancellationError();
151
+ }
152
+
153
+ return result.stdout.trim().length > 0;
154
+ }
155
+
132
156
  @debug({ exit: true })
133
157
  async getCommitDates(
134
158
  repoPath: string,
@@ -172,9 +196,7 @@ export class CommitsGitSubProvider implements GitCommitsSubProvider {
172
196
  async getCommitFiles(repoPath: string, rev: string, cancellation?: AbortSignal): Promise<GitFileChange[]> {
173
197
  const parser = getShaAndFilesAndStatsLogParser();
174
198
  const result = await this.git.run(
175
- // Single-commit log is cheap and almost always serves a user-initiated read; override
176
- // the inferred 'background' priority so it doesn't queue behind heavier graph/log work.
177
- { cwd: repoPath, cancellation: cancellation, configs: gitConfigsLog, priority: 'normal' },
199
+ { cwd: repoPath, cancellation: cancellation, configs: gitConfigsLog },
178
200
  'log',
179
201
  ...parser.arguments,
180
202
  '-n1',
@@ -354,7 +376,7 @@ export class CommitsGitSubProvider implements GitCommitsSubProvider {
354
376
 
355
377
  try {
356
378
  const result = await this.git.run(
357
- { cwd: repoPath, cancellation: cancellation, configs: gitConfigsLog },
379
+ { cwd: repoPath, cancellation: cancellation, configs: gitConfigsLog, priority: 'background' },
358
380
  'log',
359
381
  ...args,
360
382
  );
@@ -479,7 +501,7 @@ export class CommitsGitSubProvider implements GitCommitsSubProvider {
479
501
  // Cache key: range + excludeMerges. RepositoryChange events affecting branches/remotes
480
502
  // invalidate this cache via clearCaches('branches').
481
503
  const cacheKey = `${range}\x1f${options?.excludeMerges ? 'no-merges' : ''}`;
482
- return this.cache.getLeftRightCommitCount(repoPath, cacheKey, run);
504
+ return this.cache.leftRightCommitCount.getOrCreate(repoPath, cacheKey, run);
483
505
  }
484
506
 
485
507
  @debug()
@@ -573,24 +595,15 @@ export class CommitsGitSubProvider implements GitCommitsSubProvider {
573
595
  args.push(`-n${isSingleCommit ? 1 : limit + 1}`);
574
596
  }
575
597
 
576
- let stashes: Map<string, GitStashCommit> | undefined;
577
- let stdin: string | undefined;
598
+ let stashes: ReadonlyMap<string, GitStashCommit> | undefined;
578
599
 
579
- if (!isSingleCommit) {
580
- if (options?.stashes) {
581
- // There *HAS* to be a better way to get git log to return stashes, but this is the best we've found
582
- ({ stdin, stashes } = convertStashesToStdin(
583
- typeof options.stashes === 'boolean'
584
- ? await this.provider.stash?.getStash(repoPath, { reachableFrom: rev }, cancellation)
585
- : options.stashes,
586
- ));
587
- if (stashes.size) {
588
- rev ??= 'HEAD';
589
- }
590
- }
591
-
592
- if (stdin) {
593
- args.push('--stdin');
600
+ if (!isSingleCommit && options?.stashes) {
601
+ stashes =
602
+ typeof options.stashes === 'boolean'
603
+ ? (await this.provider.stash?.getStash(repoPath, { reachableFrom: rev }, cancellation))?.stashes
604
+ : options.stashes;
605
+ if (stashes?.size) {
606
+ rev ??= 'HEAD';
594
607
  }
595
608
  }
596
609
 
@@ -628,24 +641,30 @@ export class CommitsGitSubProvider implements GitCommitsSubProvider {
628
641
  const currentUser = await currentUserPromise.catch(() => undefined);
629
642
  if (cancellation?.aborted) throw new CancellationError();
630
643
 
631
- const cmdOpts: GitExecOptions = {
644
+ const cmdOpts: GitRunOptions = {
632
645
  cwd: repoPath,
633
646
  cancellation: cancellation,
634
647
  configs: gitConfigsLogWithFiles,
635
- stdin: stdin,
636
- // Single-commit log is cheap (typically <50ms) and almost always serves a user-
637
- // initiated read (commit details, hover, etc.). Override the inferred 'background'
638
- // priority so it doesn't queue behind heavier graph/log work without this, a click
639
- // on a commit while the graph is still loading can wait seconds for files to appear.
640
- ...(isSingleCommit ? { priority: 'normal' as const } : undefined),
648
+ // Single-commit log serves user-initiated reads (commit details, hover, etc.).
649
+ // Mirrors getCommitDates: full SHAs are immutable so a 5-min TTL is safe; non-SHA refs
650
+ // rely on gitResults being cleared on head/heads/remotes events (60s is the failsafe
651
+ // for watcher latency / web with no fs watcher).
652
+ ...(isSingleCommit && rev
653
+ ? {
654
+ caching: {
655
+ cache: this.cache.gitResults,
656
+ options: { accessTTL: isSha(rev) ? 5 * 60 * 1000 : 60 * 1000 },
657
+ },
658
+ }
659
+ : undefined),
641
660
  };
642
- let { commits, count, countStashChildCommits } = await parseCommits(
661
+ let { commits, count } = await parseCommits(
643
662
  parser,
644
663
  isSingleCommit ? this.git.run(cmdOpts, ...args) : this.git.stream(cmdOpts, ...args),
645
664
  repoPath,
646
665
  pathspec,
647
666
  limit,
648
- stashes,
667
+ undefined,
649
668
  currentUser,
650
669
  );
651
670
 
@@ -667,25 +686,67 @@ export class CommitsGitSubProvider implements GitCommitsSubProvider {
667
686
  args.splice(args.length - 1, 1, pathspec);
668
687
  }
669
688
 
670
- ({ commits, count, countStashChildCommits } = await parseCommits(
689
+ ({ commits, count } = await parseCommits(
671
690
  parser,
672
691
  isSingleCommit ? this.git.run(cmdOpts, ...args) : this.git.stream(cmdOpts, ...args),
673
692
  repoPath,
674
693
  pathspec,
675
694
  limit,
676
- stashes,
695
+ undefined,
677
696
  currentUser,
678
697
  ));
679
698
  }
680
699
  }
681
700
 
701
+ // Merge stashes in-memory rather than via `git log --stdin <stash>` — git would
702
+ // walk each stash's parent chains and pull in pre-rebase ancestors that aren't
703
+ // reachable from <rev>. Slot each stash directly above its first parent; stashes
704
+ // whose parent isn't in the result (rebased away, or below the current limit) are
705
+ // dropped — the Stashes view still surfaces them, and they reappear here if the
706
+ // parent loads via "Load more".
707
+ if (stashes?.size) {
708
+ // `stashes` arrives in `git stash list` order (newest @{0} first), so per-parent
709
+ // groups naturally land newest-first without an explicit sort
710
+ const stashesByParent = new Map<string, GitStashCommit[]>();
711
+ for (const stash of stashes.values()) {
712
+ const parentSha = stash.parents[0];
713
+ if (parentSha == null || !commits.has(parentSha)) continue;
714
+
715
+ const group = stashesByParent.get(parentSha);
716
+ if (group != null) {
717
+ group.push(stash);
718
+ } else {
719
+ stashesByParent.set(parentSha, [stash]);
720
+ }
721
+ }
722
+
723
+ if (stashesByParent.size) {
724
+ const cap = limit > 0 ? limit + 1 : Number.POSITIVE_INFINITY;
725
+ const merged = new Map<string, GitCommit>();
726
+ outer: for (const c of commits.values()) {
727
+ const group = stashesByParent.get(c.sha);
728
+ if (group != null) {
729
+ for (const s of group) {
730
+ if (merged.size >= cap) break outer;
731
+
732
+ merged.set(s.sha, s);
733
+ }
734
+ }
735
+ if (merged.size >= cap) break;
736
+
737
+ merged.set(c.sha, c);
738
+ }
739
+ commits = merged;
740
+ }
741
+ }
742
+
682
743
  const log: GitLog = {
683
744
  repoPath: repoPath,
684
745
  commits: commits,
685
746
  sha: isRevisionRange(rev) ? undefined : rev,
686
747
  count: commits.size,
687
748
  limit: limit,
688
- hasMore: overrideHasMore ?? count - countStashChildCommits > commits.size,
749
+ hasMore: overrideHasMore ?? (limit > 0 && count > limit),
689
750
  };
690
751
 
691
752
  if (!isSingleCommit) {
@@ -950,6 +1011,7 @@ export class CommitsGitSubProvider implements GitCommitsSubProvider {
950
1011
  filterMap<[string, GitCommit], [string, GitCommit]>(log.commits.entries(), ([sha, c]) => {
951
1012
  if (skip) {
952
1013
  if (sha !== rev) return undefined;
1014
+
953
1015
  skip = false;
954
1016
  }
955
1017
 
@@ -1120,6 +1182,7 @@ export class CommitsGitSubProvider implements GitCommitsSubProvider {
1120
1182
  } catch (ex) {
1121
1183
  scope?.error(ex);
1122
1184
  if (isCancellationError(ex)) throw ex;
1185
+
1123
1186
  debugger;
1124
1187
 
1125
1188
  return [];
@@ -1167,6 +1230,7 @@ export class CommitsGitSubProvider implements GitCommitsSubProvider {
1167
1230
  } catch (ex) {
1168
1231
  scope?.error(ex);
1169
1232
  if (isCancellationError(ex)) throw ex;
1233
+
1170
1234
  debugger;
1171
1235
 
1172
1236
  return undefined;
@@ -1367,7 +1431,10 @@ export class CommitsGitSubProvider implements GitCommitsSubProvider {
1367
1431
  {
1368
1432
  cwd: repoPath,
1369
1433
  errors: 'ignore',
1370
- caching: { cache: this.cache.gitResults, options: { accessTTL: 60 * 1000 } },
1434
+ caching: {
1435
+ cache: this.cache.gitResults,
1436
+ options: { accessTTL: isSha(sha) ? 5 * 60 * 1000 : 60 * 1000 },
1437
+ },
1371
1438
  configs: gitConfigsLog,
1372
1439
  },
1373
1440
  'log',
@@ -1394,7 +1461,10 @@ export class CommitsGitSubProvider implements GitCommitsSubProvider {
1394
1461
  {
1395
1462
  cwd: repoPath,
1396
1463
  errors: 'ignore',
1397
- caching: { cache: this.cache.gitResults, options: { accessTTL: 60 * 1000 } },
1464
+ caching: {
1465
+ cache: this.cache.gitResults,
1466
+ options: { accessTTL: isSha(sha) ? 5 * 60 * 1000 : 60 * 1000 },
1467
+ },
1398
1468
  },
1399
1469
  'cat-file',
1400
1470
  'commit',
@@ -1,7 +1,7 @@
1
1
  import { promises as fs } from 'fs';
2
2
  import { hostname, userInfo } from 'os';
3
3
  import { env as process_env } from 'process';
4
- import type { Cache } from '../../git/cache.js';
4
+ import type { Cache, GkConfigInvalidationTarget } from '../../git/cache.js';
5
5
  import type { GitServiceContext } from '../../git/context.js';
6
6
  import { WorkspaceUntrustedError } from '../../git/errors.js';
7
7
  import type { GitDir } from '../../git/models/repository.js';
@@ -27,15 +27,24 @@ import type { Git } from '../exec/git.js';
27
27
  const mappedAuthorRegex = /(.+)\s<(.+)>/;
28
28
  const emptyArray: readonly never[] = Object.freeze([]);
29
29
 
30
+ /** Catch-all pattern matching every key in `.git/gk/config` for the one-shot bulk read. */
31
+ const gkConfigAllPattern = '.';
32
+
30
33
  /**
31
- * Namespaces whose individual reads should be served from one --get-regex fetch instead
32
- * of one `git config --get` per key. The regex cache backing getGkConfigRegex dedupes
33
- * concurrent callers so a burst of per-branch reads produces a single subprocess.
34
+ * Canonicalizes a git config key for lookup against `--get-regexp` output, which git emits with the
35
+ * section and variable-name lowercased and only the subsection case-preserved. Without this a
36
+ * subsection-less key like `gk.defaultRemote` would miss the lowercased `gk.defaultremote` in the map.
34
37
  */
35
- const gkConfigCacheableSets: readonly { match: RegExp; pattern: string }[] = [
36
- { match: /^branch\..+\.gk-associated-issues$/, pattern: '^branch\\..+\\.gk-associated-issues$' },
37
- { match: /^branch\..+\.gk-merge-target-user$/, pattern: '^branch\\..+\\.gk-merge-target-user$' },
38
- ];
38
+ function canonicalizeGitConfigKey(key: string): string {
39
+ const first = key.indexOf('.');
40
+ if (first === -1) return key.toLowerCase();
41
+
42
+ const last = key.lastIndexOf('.');
43
+ // `section.name` (no subsection) → fully lowercased; `section.subsection.name` → lowercase
44
+ // section + name, preserve the case-sensitive subsection in the middle.
45
+ if (first === last) return key.toLowerCase();
46
+ return `${key.slice(0, first).toLowerCase()}${key.slice(first, last)}${key.slice(last).toLowerCase()}`;
47
+ }
39
48
 
40
49
  /**
41
50
  * Parses git config --get-regex output into a Map.
@@ -59,6 +68,7 @@ function parseConfigRegexOutput(data: string | undefined): Map<string, string> {
59
68
 
60
69
  function parseGitBoolean(value: string | undefined): boolean {
61
70
  if (value == null) return false;
71
+
62
72
  const normalized = value.toLowerCase().trim();
63
73
  return normalized === 'true' || normalized === 'yes' || normalized === 'on' || normalized === '1';
64
74
  }
@@ -71,6 +81,13 @@ export class ConfigGitSubProvider implements GitConfigSubProvider {
71
81
  private readonly provider: CliGitProviderInternal,
72
82
  ) {}
73
83
 
84
+ /**
85
+ * Pending `setGkConfig` writes keyed by `(commonPath, key, value, skip-option)`. Concurrent
86
+ * callers writing the same `(key, value)` pair share the in-flight Promise so only one
87
+ * `git config --set` subprocess actually runs. Cleared on settle.
88
+ */
89
+ private readonly _pendingGkConfigWrites = new Map<string, Promise<void>>();
90
+
74
91
  @trace()
75
92
  getConfig(
76
93
  repoPath: string | undefined,
@@ -243,6 +260,7 @@ export class ConfigGitSubProvider implements GitConfigSubProvider {
243
260
  async getDefaultWorktreePath(repoPath: string): Promise<string | undefined> {
244
261
  const gitDir = await this.getGitDir(repoPath);
245
262
  if (gitDir == null) return undefined;
263
+
246
264
  const basePath = (gitDir.commonUri ?? gitDir.uri).fsPath;
247
265
  return getBestPath(normalizePath(joinPaths(basePath, '..')));
248
266
  }
@@ -291,51 +309,56 @@ export class ConfigGitSubProvider implements GitConfigSubProvider {
291
309
  private async getGkConfigPath(repoPath: string): Promise<string | undefined> {
292
310
  const gitDir = await this.getGitDir(repoPath);
293
311
  if (gitDir == null) return undefined;
312
+
294
313
  // Use commonUri (main .git dir) for worktrees, otherwise use uri
295
314
  const basePath = (gitDir.commonUri ?? gitDir.uri).fsPath;
296
315
  return joinPaths(basePath, 'gk', 'config');
297
316
  }
298
317
 
299
318
  @debug()
300
- async getGkConfig(
301
- repoPath: string,
302
- key: GkConfigKeys | DeprecatedGkConfigKeys,
303
- options?: { type?: GitConfigType },
304
- ): Promise<string | undefined> {
305
- await this.migrateGkConfigFromGitConfig(this.cache.getCommonPath(repoPath));
319
+ async getGkConfig(repoPath: string, key: GkConfigKeys | DeprecatedGkConfigKeys): Promise<string | undefined> {
320
+ // Served in-memory from a single bulk read of the whole `.git/gk/config` (no gk read needs `--type`).
321
+ // Canonicalize the key the way git does for `--get-regexp` output so subsection-less keys
322
+ // (e.g. `gk.defaultRemote`) match, and coerce an empty value to undefined to match the old
323
+ // `git config --get` (`.trim() || undefined`) contract.
324
+ return (await this.getGkConfigMap(repoPath)).get(canonicalizeGitConfigKey(key)) || undefined;
325
+ }
306
326
 
307
- // Per-branch keys are commonly read in fan-out loops (e.g. Home overview enrichment).
308
- // Satisfy the read from a single --get-regex over the namespace instead of spawning
309
- // one `git config --get` per branch.
310
- const set = gkConfigCacheableSets.find(s => s.match.test(key));
311
- if (set != null) {
312
- return this.cache.getGkConfig(repoPath, key, async () => {
313
- const entries = await this.getGkConfigRegex(repoPath, set.pattern);
314
- return entries.get(key);
315
- });
316
- }
327
+ @debug()
328
+ async getGkConfigRegex(repoPath: string, pattern: string): Promise<Map<string, string>> {
329
+ const all = await this.getGkConfigMap(repoPath);
317
330
 
318
- return this.cache.getGkConfig(repoPath, key, () => this.getGkConfigCore(repoPath, key, options));
319
- }
331
+ // Filter the bulk map in-memory. The old path passed `pattern` to `git config --get-regex`
332
+ // (errors ignored → empty result on a bad pattern); preserve that no-throw contract here
333
+ // rather than letting an invalid-JS pattern reject the read.
334
+ let re: RegExp;
335
+ try {
336
+ re = new RegExp(pattern);
337
+ } catch {
338
+ return new Map();
339
+ }
320
340
 
321
- private async getGkConfigCore(
322
- repoPath: string,
323
- key: string,
324
- options?: { type?: GitConfigType },
325
- ): Promise<string | undefined> {
326
- const gkConfigPath = await this.getGkConfigPath(repoPath);
327
- if (!gkConfigPath) return undefined;
328
- return this.getConfigCore(repoPath, key, {
329
- ...options,
330
- runGitLocally: true,
331
- file: gkConfigPath,
332
- });
341
+ const result = new Map<string, string>();
342
+ for (const [k, v] of all) {
343
+ if (re.test(k)) {
344
+ result.set(k, v);
345
+ }
346
+ }
347
+ return result;
333
348
  }
334
349
 
335
- @debug()
336
- async getGkConfigRegex(repoPath: string, pattern: string): Promise<Map<string, string>> {
350
+ /**
351
+ * Reads the entire `.git/gk/config` in one `git config --get-regexp` and caches the parsed map
352
+ * per commonPath. Per-key (getGkConfig) and per-namespace (getGkConfigRegex) lookups are served
353
+ * from this single cached read — so a branch-overview render that fans out across several gk
354
+ * namespaces costs one `git config` call instead of one per namespace.
355
+ */
356
+ private async getGkConfigMap(repoPath: string): Promise<Map<string, string>> {
357
+ // Migrate BEFORE populating the cache, not inside the factory: a first-time migration calls
358
+ // clearCaches('gkConfig'), which would otherwise evict the in-flight gkConfigMap entry the
359
+ // cache wrapper synchronously stored and force a redundant bulk re-read.
337
360
  await this.migrateGkConfigFromGitConfig(this.cache.getCommonPath(repoPath));
338
- return this.cache.getGkConfigRegex(repoPath, pattern, () => this.getGkConfigRegexCore(repoPath, pattern));
361
+ return this.cache.getGkConfigMap(repoPath, () => this.getGkConfigRegexCore(repoPath, gkConfigAllPattern));
339
362
  }
340
363
 
341
364
  private async getGkConfigRegexCore(repoPath: string, pattern: string): Promise<Map<string, string>> {
@@ -349,6 +372,33 @@ export class ConfigGitSubProvider implements GitConfigSubProvider {
349
372
  repoPath: string,
350
373
  key: GkConfigKeys | DeprecatedGkConfigKeys,
351
374
  value: string | undefined,
375
+ options?: { skipInvalidation?: readonly GkConfigInvalidationTarget[] },
376
+ ): Promise<void> {
377
+ // Encode the skip-invalidation option in the dedup key: a self-write (with skip targets)
378
+ // and a user-driven write of the same `(key, value)` (no skip targets) have different
379
+ // cache-invalidation semantics, so sharing their Promise would silently let the user-driven
380
+ // write skip invalidation. Sort the array so callers passing the same targets in different
381
+ // orders share a single in-flight write.
382
+ const commonPath = this.cache.getCommonPath(repoPath);
383
+ const skipKey = options?.skipInvalidation?.length ? options.skipInvalidation.toSorted().join(',') : '';
384
+ const dedupKey = `${commonPath}\0${key}\0${value ?? ''}\0${skipKey}`;
385
+
386
+ const pending = this._pendingGkConfigWrites.get(dedupKey);
387
+ if (pending != null) return pending;
388
+
389
+ const promise = this.setGkConfigCore(repoPath, key, value, options);
390
+ this._pendingGkConfigWrites.set(dedupKey, promise);
391
+ // Swallow the cleanup chain's rejection so a failed write doesn't surface as an unhandled
392
+ // rejection separate from the caller's own handling of the returned promise.
393
+ void promise.finally(() => this._pendingGkConfigWrites.delete(dedupKey)).catch(() => {});
394
+ return promise;
395
+ }
396
+
397
+ private async setGkConfigCore(
398
+ repoPath: string,
399
+ key: GkConfigKeys | DeprecatedGkConfigKeys,
400
+ value: string | undefined,
401
+ options?: { skipInvalidation?: readonly GkConfigInvalidationTarget[] },
352
402
  ): Promise<void> {
353
403
  const scope = getScopedLogger();
354
404
 
@@ -361,8 +411,10 @@ export class ConfigGitSubProvider implements GitConfigSubProvider {
361
411
 
362
412
  await this.setConfigCore(repoPath, key, value, { file: gkConfigPath });
363
413
 
364
- // Invalidate the cached value for this key and clear all regex patterns for this scope
365
- this.cache.deleteGkConfig(repoPath, key);
414
+ // Invalidate the bulk map (so the next read re-fetches) and the derived caches for this key's
415
+ // ref. The `.git/gk/config` file-watcher also fires `'gkConfig'` shortly after, which clears
416
+ // the same caches coarsely — both paths are idempotent.
417
+ this.cache.deleteGkConfig(repoPath, key, options);
366
418
  }
367
419
 
368
420
  @debug()
@@ -381,11 +433,10 @@ export class ConfigGitSubProvider implements GitConfigSubProvider {
381
433
  const sshProgram = configMap.get('gpg.ssh.program');
382
434
  const allowedSignersFile = configMap.get('gpg.ssh.allowedsignersfile');
383
435
 
384
- // Check if git config has commit signing enabled
385
- const isEnabled = parseGitBoolean(enabledRaw);
386
-
387
- // Note: To override commit signing, pass it via the host/caller.
388
- // The library no longer reads a config for this.
436
+ // Check if git config has commit signing enabled, falling back to the host-level override
437
+ // (e.g. VS Code's `git.enableCommitSigning`) when `commit.gpgsign` is unset/false. The host
438
+ // override can only enable signing, never force it off.
439
+ const isEnabled = parseGitBoolean(enabledRaw) || this.context.config?.signing?.enabled === true;
389
440
 
390
441
  return {
391
442
  enabled: isEnabled,
@@ -648,6 +699,7 @@ export class ConfigGitSubProvider implements GitConfigSubProvider {
648
699
  this._migratedRepos.add(repoPath);
649
700
  return;
650
701
  }
702
+
651
703
  const gkConfigFolder = joinPaths(gkConfigPath, '..');
652
704
 
653
705
  // If .git/gk/config already exists, consider migration done — it was either
@@ -662,6 +714,7 @@ export class ConfigGitSubProvider implements GitConfigSubProvider {
662
714
 
663
715
  // If .git/gk/config doesn't exist, create an empty file to prevent multiple migration attempts in future sessions
664
716
  if (!(await this.ensureGkConfigFolder(gkConfigFolder, scope))) return;
717
+
665
718
  try {
666
719
  await fs.writeFile(gkConfigPath, new Uint8Array());
667
720
  } catch (ex) {
@@ -105,7 +105,7 @@ export class DiffGitSubProvider implements GitDiffSubProvider {
105
105
  return stat;
106
106
  } catch (ex) {
107
107
  const msg: string = ex?.toString() ?? '';
108
- if (GitErrors.noMergeBase.test(msg)) {
108
+ if (GitErrors.noMergeBase.test(msg) || GitErrors.badRevision.test(msg)) {
109
109
  return undefined;
110
110
  }
111
111
 
@@ -218,7 +218,8 @@ export class DiffGitSubProvider implements GitDiffSubProvider {
218
218
  },
219
219
  ): Promise<GitFile[] | undefined> {
220
220
  try {
221
- const similarityThreshold = options?.similarityThreshold;
221
+ const similarityThreshold =
222
+ options?.similarityThreshold ?? this.context.config?.commits.similarityThreshold;
222
223
  const configs =
223
224
  options?.renameLimit != null
224
225
  ? [...gitConfigsDiff, '-c', `diff.renameLimit=${options.renameLimit}`]
@@ -258,6 +259,7 @@ export class DiffGitSubProvider implements GitDiffSubProvider {
258
259
  for (const file of untracked) {
259
260
  if (seen.has(file.path)) continue;
260
261
  if (options.path && options.path !== file.path) continue;
262
+
261
263
  files.push(file);
262
264
  }
263
265
  }
@@ -328,7 +330,12 @@ export class DiffGitSubProvider implements GitDiffSubProvider {
328
330
  // Follow file history and specify the file path
329
331
  args.push('--follow', '--', relativePath);
330
332
 
331
- const result = await this.git.run({ cwd: repoPath, configs: gitConfigsLog }, ...args);
333
+ // Unbounded --follow walk over file history can be slow on long histories — queue as background
334
+ // so it doesn't compete with interactive work.
335
+ const result = await this.git.run(
336
+ { cwd: repoPath, configs: gitConfigsLog, priority: 'background' },
337
+ ...args,
338
+ );
332
339
 
333
340
  let currentSha;
334
341
  let currentPath;