@gitkraken/core-gitlens 0.24.0 → 0.26.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 (176) hide show
  1. package/CHANGELOG.md +40 -1
  2. package/README.md +23 -15
  3. package/dist/git/errors.d.ts +6 -5
  4. package/dist/git/errors.js +7 -6
  5. package/dist/git/errors.js.map +1 -1
  6. package/dist/git/features.d.ts +1 -1
  7. package/dist/git/features.js +1 -1
  8. package/dist/git/features.js.map +1 -1
  9. package/dist/git/models/remoteProvider.d.ts +4 -1
  10. package/dist/git/models/remoteProvider.js.map +1 -1
  11. package/dist/git/providers/operations.d.ts +15 -0
  12. package/dist/git/providers/provider.d.ts +4 -2
  13. package/dist/git/utils/branch.utils.d.ts +4 -1
  14. package/dist/git/utils/branch.utils.js +5 -2
  15. package/dist/git/utils/branch.utils.js.map +1 -1
  16. package/dist/git/utils/mergeConflicts.utils.js +2 -2
  17. package/dist/git/utils/mergeConflicts.utils.js.map +1 -1
  18. package/dist/git/watching/worktreeSummary.d.ts +15 -3
  19. package/dist/git/watching/worktreeSummary.js +179 -31
  20. package/dist/git/watching/worktreeSummary.js.map +1 -1
  21. package/dist/git-cli/cliGitProvider.d.ts +30 -3
  22. package/dist/git-cli/cliGitProvider.js +102 -40
  23. package/dist/git-cli/cliGitProvider.js.map +1 -1
  24. package/dist/git-cli/exec/git.d.ts +9 -1
  25. package/dist/git-cli/exec/git.js +23 -4
  26. package/dist/git-cli/exec/git.js.map +1 -1
  27. package/dist/git-cli/exec/gitDirResolver.d.ts +26 -0
  28. package/dist/git-cli/exec/gitDirResolver.js +181 -0
  29. package/dist/git-cli/exec/gitDirResolver.js.map +1 -0
  30. package/dist/git-cli/exec/headState.js +3 -3
  31. package/dist/git-cli/exec/headState.js.map +1 -1
  32. package/dist/git-cli/exec/indexRefresh.d.ts +78 -0
  33. package/dist/git-cli/exec/indexRefresh.js +159 -0
  34. package/dist/git-cli/exec/indexRefresh.js.map +1 -0
  35. package/dist/git-cli/providers/branchRemote.js +2 -5
  36. package/dist/git-cli/providers/branchRemote.js.map +1 -1
  37. package/dist/git-cli/providers/branches.js +4 -4
  38. package/dist/git-cli/providers/branches.js.map +1 -1
  39. package/dist/git-cli/providers/config.d.ts +2 -0
  40. package/dist/git-cli/providers/config.js +26 -4
  41. package/dist/git-cli/providers/config.js.map +1 -1
  42. package/dist/git-cli/providers/maintenance.js +1 -1
  43. package/dist/git-cli/providers/operations.d.ts +4 -1
  44. package/dist/git-cli/providers/operations.js +33 -25
  45. package/dist/git-cli/providers/operations.js.map +1 -1
  46. package/dist/git-cli/providers/pausedOperations.d.ts +3 -1
  47. package/dist/git-cli/providers/pausedOperations.js +10 -7
  48. package/dist/git-cli/providers/pausedOperations.js.map +1 -1
  49. package/dist/git-cli/providers/refs.js +25 -1
  50. package/dist/git-cli/providers/refs.js.map +1 -1
  51. package/dist/git-cli/providers/staging.js +1 -1
  52. package/dist/git-cli/providers/stash.d.ts +3 -1
  53. package/dist/git-cli/providers/stash.js +8 -5
  54. package/dist/git-cli/providers/stash.js.map +1 -1
  55. package/dist/git-cli/providers/worktrees.d.ts +6 -1
  56. package/dist/git-cli/providers/worktrees.js +6 -2
  57. package/dist/git-cli/providers/worktrees.js.map +1 -1
  58. package/dist/git-cli/service.d.ts +2 -0
  59. package/dist/git-cli/service.js +2 -1
  60. package/dist/git-cli/service.js.map +1 -1
  61. package/dist/ipc/discovery.js +1 -1
  62. package/dist/plus/agents/providers/claudeCodeTranscript.js +6 -6
  63. package/dist/plus/agents/providers/claudeCodeTranscript.js.map +1 -1
  64. package/dist/plus/ai/errors.d.ts +4 -1
  65. package/dist/plus/ai/errors.js +4 -0
  66. package/dist/plus/ai/errors.js.map +1 -1
  67. package/dist/plus/ai/providers/mistralProvider.js +1 -1
  68. package/dist/plus/ai/providers/mistralProvider.js.map +1 -1
  69. package/dist/plus/ai/providers/openAICompatibleProviderBase.js +2 -1
  70. package/dist/plus/ai/providers/openAICompatibleProviderBase.js.map +1 -1
  71. package/dist/plus/git-github/api/github.js +12 -13
  72. package/dist/plus/git-github/api/github.js.map +1 -1
  73. package/dist/plus/git-github/api/token.d.ts +2 -0
  74. package/dist/plus/integrations/authentication/cloudIntegrationService.d.ts +1 -1
  75. package/dist/plus/integrations/authentication/cloudIntegrationService.js +6 -1
  76. package/dist/plus/integrations/authentication/cloudIntegrationService.js.map +1 -1
  77. package/dist/plus/integrations/authentication/configuredIntegrationService.js +2 -2
  78. package/dist/plus/integrations/authentication/integrationAuthenticationProvider.js +18 -5
  79. package/dist/plus/integrations/authentication/integrationAuthenticationProvider.js.map +1 -1
  80. package/dist/plus/integrations/authentication/integrationAuthenticationService.d.ts +3 -1
  81. package/dist/plus/integrations/authentication/integrationAuthenticationService.js +4 -0
  82. package/dist/plus/integrations/authentication/integrationAuthenticationService.js.map +1 -1
  83. package/dist/plus/integrations/authentication/models.d.ts +2 -0
  84. package/dist/plus/integrations/authentication/models.js +2 -1
  85. package/dist/plus/integrations/authentication/models.js.map +1 -1
  86. package/dist/plus/integrations/authentication/observedAuthenticationProvider.js +1 -1
  87. package/dist/plus/integrations/authentication/rejectedTokenTracker.d.ts +5 -4
  88. package/dist/plus/integrations/authentication/rejectedTokenTracker.js +5 -4
  89. package/dist/plus/integrations/authentication/rejectedTokenTracker.js.map +1 -1
  90. package/dist/plus/integrations/index.d.ts +2 -2
  91. package/dist/plus/integrations/index.js +1 -1
  92. package/dist/plus/integrations/index.js.map +1 -1
  93. package/dist/plus/integrations/integrationService.d.ts +6 -0
  94. package/dist/plus/integrations/integrationService.js +3 -3
  95. package/dist/plus/integrations/integrationService.js.map +1 -1
  96. package/dist/plus/integrations/lite.js +1 -1
  97. package/dist/plus/integrations/manager.d.ts +51 -3
  98. package/dist/plus/integrations/models/gitHostIntegration.d.ts +14 -0
  99. package/dist/plus/integrations/models/gitHostIntegration.js +50 -41
  100. package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
  101. package/dist/plus/integrations/models/integration.d.ts +27 -5
  102. package/dist/plus/integrations/models/integration.js +57 -15
  103. package/dist/plus/integrations/models/integration.js.map +1 -1
  104. package/dist/plus/integrations/models/issueReads.d.ts +6 -0
  105. package/dist/plus/integrations/models/issuesIntegration.js +11 -11
  106. package/dist/plus/integrations/models/issuesIntegration.js.map +1 -1
  107. package/dist/plus/integrations/providers/azure/azure.js +2 -2
  108. package/dist/plus/integrations/providers/azureDevOps.js +1 -1
  109. package/dist/plus/integrations/providers/azureDevOpsServer.js +1 -1
  110. package/dist/plus/integrations/providers/bitbucket/bitbucket.js +1 -1
  111. package/dist/plus/integrations/providers/bitbucket/bitbucket.js.map +1 -1
  112. package/dist/plus/integrations/providers/bitbucket-server.js +1 -1
  113. package/dist/plus/integrations/providers/bitbucket.js +1 -1
  114. package/dist/plus/integrations/providers/github.js +1 -1
  115. package/dist/plus/integrations/providers/gitlab/gitlab.js +2 -2
  116. package/dist/plus/integrations/providers/gitlab/gitlab.js.map +1 -1
  117. package/dist/plus/integrations/providers/gitlab.js +1 -1
  118. package/dist/plus/integrations/providers/jira-server.js +2 -2
  119. package/dist/plus/integrations/providers/jira.js +1 -1
  120. package/dist/plus/integrations/providers/linear.js +2 -2
  121. package/dist/plus/integrations/providers/linear.js.map +1 -1
  122. package/dist/plus/integrations/providers/models.js +2 -1
  123. package/dist/plus/integrations/providers/models.js.map +1 -1
  124. package/dist/plus/integrations/providers/providerErrors.js +9 -0
  125. package/dist/plus/integrations/providers/providerErrors.js.map +1 -1
  126. package/dist/plus/integrations/providers/providersApi.js +1 -1
  127. package/dist/plus/integrations/providers/trello.js +1 -1
  128. package/dist/plus/integrations/providers/utils.js +1 -1
  129. package/dist/plus/integrations/reads/counts.js +1 -1
  130. package/dist/plus/integrations/reads/cursors.js +1 -1
  131. package/dist/plus/integrations/reads/drains.d.ts +5 -4
  132. package/dist/plus/integrations/reads/drains.js +28 -8
  133. package/dist/plus/integrations/reads/drains.js.map +1 -1
  134. package/dist/plus/integrations/reads/hierarchy.js +1 -1
  135. package/dist/plus/integrations/reads/issueBatch.d.ts +1 -1
  136. package/dist/plus/integrations/reads/issueBatch.js.map +1 -1
  137. package/dist/plus/integrations/reads/issueTracker.js +1 -1
  138. package/dist/plus/integrations/reads/issues.d.ts +2 -0
  139. package/dist/plus/integrations/reads/issues.js +5 -3
  140. package/dist/plus/integrations/reads/issues.js.map +1 -1
  141. package/dist/plus/integrations/reads/paging.d.ts +5 -6
  142. package/dist/plus/integrations/reads/paging.js +5 -6
  143. package/dist/plus/integrations/reads/paging.js.map +1 -1
  144. package/dist/plus/integrations/reads/pullRequests.d.ts +4 -0
  145. package/dist/plus/integrations/reads/pullRequests.js +4 -2
  146. package/dist/plus/integrations/reads/pullRequests.js.map +1 -1
  147. package/dist/plus/integrations/reads/resolveRepository.js +1 -1
  148. package/dist/plus/integrations/reads/sweeps.js +42 -10
  149. package/dist/plus/integrations/reads/sweeps.js.map +1 -1
  150. package/dist/plus/integrations/results.d.ts +23 -3
  151. package/dist/plus/integrations/results.js.map +1 -1
  152. package/dist/plus/notifications/api.d.ts +20 -0
  153. package/dist/plus/notifications/api.js +89 -0
  154. package/dist/plus/notifications/api.js.map +1 -0
  155. package/dist/plus/notifications/context.d.ts +28 -0
  156. package/dist/plus/notifications/context.js +0 -0
  157. package/dist/plus/notifications/errors.d.ts +13 -0
  158. package/dist/plus/notifications/errors.js +22 -0
  159. package/dist/plus/notifications/errors.js.map +1 -0
  160. package/dist/plus/notifications/models.d.ts +94 -0
  161. package/dist/plus/notifications/models.js +0 -0
  162. package/dist/plus/notifications/notificationsService.d.ts +115 -0
  163. package/dist/plus/notifications/notificationsService.js +381 -0
  164. package/dist/plus/notifications/notificationsService.js.map +1 -0
  165. package/dist/plus/notifications/parse.d.ts +12 -0
  166. package/dist/plus/notifications/parse.js +152 -0
  167. package/dist/plus/notifications/parse.js.map +1 -0
  168. package/dist/plus/notifications/presentation.d.ts +28 -0
  169. package/dist/plus/notifications/presentation.js +55 -0
  170. package/dist/plus/notifications/presentation.js.map +1 -0
  171. package/dist/utils/env/node/exec.d.ts +10 -1
  172. package/dist/utils/env/node/exec.js +41 -4
  173. package/dist/utils/env/node/exec.js.map +1 -1
  174. package/docs/integrations.md +21 -2
  175. package/docs/notifications.md +239 -0
  176. package/package.json +21 -1
@@ -20,6 +20,14 @@ const baseConfigField = 16;
20
20
  * the base's own ref just moved forward, it is re-measured rather than resolved again. {@link baseField} overrides it.
21
21
  */
22
22
  const baseMoveField = 32;
23
+ /**
24
+ * Checks the summary against what a probe finds now, for a change that may have moved one of its refs without naming it
25
+ * (a packed-refs rewrite, a ref directory, an overflow or a poll): HEAD, the upstream and the counts against it as
26
+ * `getBranch` answers them, and the refs the base depends on against the tips it was read from (see {@link ReadTips});
27
+ * reads the groups that moved, as an unwatched read would — everything when HEAD's branch or commit did — and nothing
28
+ * when none did
29
+ */
30
+ const tipCheckField = 64;
23
31
  /** Every group a full read covers — a base read refreshes the {@link BaseKeys} snapshot itself */
24
32
  const allFields = 7;
25
33
  const maxConcurrentReadsPerRepository = 4;
@@ -27,6 +35,7 @@ const maxConcurrentReads = 8;
27
35
  const maxUnwatchedReads = 256;
28
36
  const maxDeferredDirtyMs = 1e4;
29
37
  const emptyRefs = Object.freeze([]);
38
+ const noRemotes = /* @__PURE__ */ new Set();
30
39
  const noBaseKeys = [
31
40
  void 0,
32
41
  void 0,
@@ -125,9 +134,13 @@ var SummarySubscription = class {
125
134
  * inputs its last base read consulted (every branch's tracking but those of branches it didn't depend on), the stored
126
135
  * values, HEAD's commit or the upstream changed, unless it was confined to the
127
136
  * `branch.<name>` sections of branches the summary neither is on, tracks nor bases on (its `configBranches`), which
128
- * reads nothing; the checked-out branch moving, or a HEAD change, reads all of them. Stash, unrelated tags and
129
- * branches, and the like read nothing. One run is in flight per worktree at a time, at most four per repository (the
130
- * worktrees sharing a common git directory), and at most eight across the service. Runs take turns first come, first
137
+ * reads nothing; the checked-out branch moving, or a HEAD change, reads all of them. A change that may have moved one
138
+ * of those refs without naming it (a packed-refs rewrite, as deleting a packed branch makes, a ref directory, an
139
+ * overflow or a poll) first checks HEAD, the upstream and the counts against it as core's cached `getBranch` answers
140
+ * them, and the tips the base was read from against core's cached ref list, both shared by the repository's
141
+ * checkouts, and reads only the groups that moved, by the same rules — nothing when none did.
142
+ * Stash, unrelated tags and branches, and the like read nothing. One run is in flight per worktree at a time, at most
143
+ * four per repository (the worktrees sharing a common git directory), and at most eight across the service. Runs take turns first come, first
131
144
  * served, except that one whose repository is at its cap lets later runs of other repositories go first, so a burst in
132
145
  * one repository never delays another's reads: events while a run waits for its turn join it, and events during a run
133
146
  * are merged into a single follow-up run.
@@ -370,13 +383,11 @@ var WorktreeSummaryService = class {
370
383
  * the `HEAD` symrefs of `remotes` (every remote's when `undefined`); without `statIndex`, the index is unknown
371
384
  */
372
385
  async probeUnwatched(repo, remotes, statIndex, signal) {
373
- const remoteHeads = /* @__PURE__ */ new Map();
374
386
  const stat = statIndex ? this.stat : void 0;
375
- const [current, tips, gitDir] = await Promise.all([
387
+ const [current, refs, gitDir] = await Promise.all([
376
388
  repo.branches.getBranch(void 0, void 0, signal),
377
- repo.refs.getRefTips(void 0, signal),
378
- stat != null ? getGitDir(repo) : void 0,
379
- readRemoteHeads(repo, remoteHeads, remotes, signal)
389
+ probeRefs(repo, remotes, signal),
390
+ stat != null ? getGitDir(repo) : void 0
380
391
  ]);
381
392
  let index;
382
393
  if (stat != null && gitDir != null) try {
@@ -387,15 +398,59 @@ var WorktreeSummaryService = class {
387
398
  }
388
399
  const detached = current?.detached ?? false;
389
400
  return {
401
+ current,
390
402
  branch: detached ? void 0 : current?.name || void 0,
391
403
  detached,
392
404
  sha: current?.sha,
393
405
  upstream: current?.upstream?.name,
394
- tips: getTipsByName(tips),
395
- remoteHeads,
406
+ tips: refs.tips,
407
+ remoteHeads: refs.remoteHeads,
396
408
  index
397
409
  };
398
410
  }
411
+ /**
412
+ * A subscribed run's {@link ReadProbe}, from cached answers: HEAD when the branch is due or a tip check is, the ref
413
+ * tips (kept in `probed`), and the `HEAD` symrefs of the remotes the base depends on when the base may be read or a
414
+ * tip check is due — every remote's for a first read, which can come to depend on any. A tip check widens `fields` as
415
+ * {@link getTipCheckFields} finds, and is read in full when the probe fails; any other probe that fails leaves
416
+ * the tips its groups read unknown.
417
+ */
418
+ async probeRead(repo, previous, tips, fields, baseMoves, probed, signal) {
419
+ const check = (fields & tipCheckField) !== 0 && previous != null && (fields & allFields) !== allFields;
420
+ fields &= -65;
421
+ const remotes = previous == null ? void 0 : check || (fields & 60) !== 0 ? getHeadRemotes(previous.baseDependsOn) : noRemotes;
422
+ try {
423
+ if (!check && (fields & branchField) === 0) {
424
+ probed.refs = await probeRefs(repo, remotes, signal);
425
+ return {
426
+ fields,
427
+ baseMoves
428
+ };
429
+ }
430
+ const probe = await this.probeUnwatched(repo, remotes, false, signal);
431
+ probed.refs = probe;
432
+ const head = { branch: probe.current };
433
+ if (!check) return {
434
+ fields,
435
+ baseMoves,
436
+ head
437
+ };
438
+ const moved = getTipCheckFields(probe, previous, tips);
439
+ if (moved.baseMoves != null && baseMoves != null) for (const ref of baseMoves) moved.baseMoves.add(ref);
440
+ return {
441
+ fields: fields | moved.fields,
442
+ baseMoves: moved.baseMoves ?? baseMoves,
443
+ head
444
+ };
445
+ } catch (ex) {
446
+ if (isCancellationError(ex)) throw ex;
447
+ probed.refs = void 0;
448
+ return {
449
+ fields: check ? fields | allFields : fields,
450
+ baseMoves
451
+ };
452
+ }
453
+ }
399
454
  getResourceUsage() {
400
455
  return { "worktreeSummary.entries.count": this.entries.size };
401
456
  }
@@ -424,6 +479,7 @@ var WorktreeSummaryService = class {
424
479
  entry.baseKeys = last.result.baseKeys;
425
480
  entry.baseConfigKey = last.result.baseConfigKey;
426
481
  entry.baseDefaultBranch = last.result.baseDefaultBranch;
482
+ entry.tips = { base: last.inputs.baseTips };
427
483
  } else entry.pending |= 23;
428
484
  entry.handle = handle;
429
485
  entry.slotsKey = getRepositoryKey(gitDir.commonUri ?? gitDir.uri);
@@ -501,17 +557,23 @@ var WorktreeSummaryService = class {
501
557
  if (e.changed("index", "ignores")) fields |= dirtyField;
502
558
  if (e.changed("config") && e.mayHaveChangedConfig(getConfigRelevantRefs(value))) fields |= 26;
503
559
  if (e.changed("gkConfig")) fields |= baseKeysField;
504
- if (value.branch != null && e.mayHaveChangedRef(`refs/heads/${value.branch}`)) fields |= allFields;
505
- if (value.upstream != null && (e.mayHaveChangedRef(`refs/remotes/${value.upstream.name}`) || e.mayHaveChangedRef(`refs/heads/${value.upstream.name}`))) fields |= branchField;
560
+ if (value.branch != null) {
561
+ const ref = `refs/heads/${value.branch}`;
562
+ if (e.mayHaveChangedRef(ref)) fields |= isNamedRef(e, ref) ? allFields : tipCheckField;
563
+ }
564
+ if (value.upstream != null) {
565
+ const remoteRef = `refs/remotes/${value.upstream.name}`;
566
+ if (e.mayHaveChangedRef(remoteRef)) fields |= isNamedRef(e, remoteRef) ? branchField : tipCheckField;
567
+ const localRef = `refs/heads/${value.upstream.name}`;
568
+ if (e.mayHaveChangedRef(localRef)) fields |= isNamedRef(e, localRef) ? branchField : tipCheckField;
569
+ }
506
570
  let baseMoves;
507
571
  if ((fields & baseField) === 0) {
508
572
  for (const ref of value.baseDependsOn) {
509
573
  if (!e.mayHaveChangedRef(ref)) continue;
510
- const kind = getRefChangeKind(ref);
511
- if (!e.refs.has(ref) || kind == null || e.unnamedRefKinds.has(kind)) {
512
- fields |= baseField;
513
- baseMoves = void 0;
514
- break;
574
+ if (!isNamedRef(e, ref)) {
575
+ fields |= tipCheckField;
576
+ continue;
515
577
  }
516
578
  baseMoves ??= [];
517
579
  baseMoves.push(ref);
@@ -612,13 +674,16 @@ var WorktreeSummaryService = class {
612
674
  return true;
613
675
  }
614
676
  async run(entry, fields, baseMoves) {
615
- const { value, seed } = entry;
677
+ const { value, seed, tips } = entry;
616
678
  const previous = value ?? seed;
679
+ if (previous?.stale) fields |= 23;
680
+ const probed = {};
617
681
  let result;
618
682
  try {
619
683
  const repo = this.getRepository(entry.key);
620
684
  if (repo == null) throw new Error(`No repository found for '${entry.key}'`);
621
- result = await readSummary(repo, entry.key, fields, previous, entry.baseKeys, entry.baseConfigKey, entry.baseDefaultBranch, baseMoves, entry.abort.signal, this.verifyBaseRemeasure);
685
+ const signal = entry.abort.signal;
686
+ result = await readSummary(repo, entry.key, fields, previous, entry.baseKeys, entry.baseConfigKey, entry.baseDefaultBranch, baseMoves, signal, this.verifyBaseRemeasure, (due, moves) => this.probeRead(repo, previous, tips, due, moves, probed, signal));
622
687
  } catch (ex) {
623
688
  if (entry.disposed || isCancellationError(ex)) return;
624
689
  this.fail(entry, ex);
@@ -628,6 +693,7 @@ var WorktreeSummaryService = class {
628
693
  if (result.summary.stale && (previous == null || !previous.stale)) _logger.warn(`WorktreeSummaryService: reading the base of '${entry.key}' failed: ${String(result.baseError)}`);
629
694
  entry.error = void 0;
630
695
  entry.seed = void 0;
696
+ entry.tips = getReadTips(tips, probed.refs, result);
631
697
  entry.baseKeys = result.baseKeys;
632
698
  entry.baseConfigKey = entry.pending & baseConfigField ? void 0 : result.baseConfigKey;
633
699
  entry.baseDefaultBranch = result.baseDefaultBranch;
@@ -687,6 +753,7 @@ var WorktreeSummaryService = class {
687
753
  entry.baseKeys = void 0;
688
754
  entry.baseConfigKey = void 0;
689
755
  entry.baseDefaultBranch = void 0;
756
+ entry.tips = void 0;
690
757
  entry.pending = 0;
691
758
  entry.baseMoves = void 0;
692
759
  entry.running = void 0;
@@ -709,6 +776,7 @@ function dropSeed(entry) {
709
776
  entry.baseKeys = void 0;
710
777
  entry.baseConfigKey = void 0;
711
778
  entry.baseDefaultBranch = void 0;
779
+ entry.tips = void 0;
712
780
  }
713
781
  function clearDeferredDirty(entry) {
714
782
  entry.dirtyReadAt = void 0;
@@ -730,6 +798,7 @@ function createEntry(key) {
730
798
  baseKeys: void 0,
731
799
  baseConfigKey: void 0,
732
800
  baseDefaultBranch: void 0,
801
+ tips: void 0,
733
802
  error: void 0,
734
803
  pending: 0,
735
804
  baseMoves: void 0,
@@ -747,7 +816,7 @@ function createEntry(key) {
747
816
  * answer. A failed base read doesn't fail the rest: the summary comes back stale, keeping the previous
748
817
  * base and `baseDependsOn` only while the branch is the same.
749
818
  */
750
- async function readSummary(repo, key, fields, previous, previousBaseKeys, previousBaseConfigKey, previousBaseDefaultBranch, baseMoves, signal, verifyBaseRemeasure) {
819
+ async function readSummary(repo, key, fields, previous, previousBaseKeys, previousBaseConfigKey, previousBaseDefaultBranch, baseMoves, signal, verifyBaseRemeasure, probe) {
751
820
  if (previous == null) fields |= allFields;
752
821
  let dirtyReadAt;
753
822
  const startDirtyRead = () => {
@@ -755,6 +824,12 @@ async function readSummary(repo, key, fields, previous, previousBaseKeys, previo
755
824
  return readDirty(repo, signal);
756
825
  };
757
826
  let dirtyRead = fields & dirtyField ? startDirtyRead() : void 0;
827
+ let head;
828
+ if (probe != null && fields & 102) {
829
+ const probed = await probe(fields, baseMoves);
830
+ ({fields, baseMoves, head} = probed);
831
+ if (fields & dirtyField) dirtyRead ??= startDirtyRead();
832
+ }
758
833
  let branch = previous?.branch;
759
834
  let detached = previous?.detached ?? false;
760
835
  let sha = previous?.sha;
@@ -762,7 +837,7 @@ async function readSummary(repo, key, fields, previous, previousBaseKeys, previo
762
837
  let ahead = previous?.ahead ?? 0;
763
838
  let behind = previous?.behind ?? 0;
764
839
  if (fields & branchField) {
765
- const current = await repo.branches.getBranch(void 0, void 0, signal);
840
+ const current = head != null ? head.branch : await repo.branches.getBranch(void 0, void 0, signal);
766
841
  detached = current?.detached ?? false;
767
842
  branch = detached ? void 0 : current?.name || void 0;
768
843
  sha = current?.sha;
@@ -867,7 +942,8 @@ async function readSummary(repo, key, fields, previous, previousBaseKeys, previo
867
942
  baseConfigKey,
868
943
  baseDefaultBranch,
869
944
  baseError,
870
- dirtyReadAt
945
+ dirtyReadAt,
946
+ fields
871
947
  };
872
948
  }
873
949
  async function getGitDir(repo) {
@@ -878,6 +954,18 @@ async function getGitDir(repo) {
878
954
  return;
879
955
  }
880
956
  }
957
+ /**
958
+ * Reads the ref tips and the `HEAD` symrefs of `remotes` (every remote's when `undefined`), as core's caches answer
959
+ * them: one ref list shared by the repository's worktrees
960
+ */
961
+ async function probeRefs(repo, remotes, signal) {
962
+ const remoteHeads = /* @__PURE__ */ new Map();
963
+ const [tips] = await Promise.all([repo.refs.getRefTips(void 0, signal), readRemoteHeads(repo, remoteHeads, remotes, signal)]);
964
+ return {
965
+ tips: getTipsByName(tips),
966
+ remoteHeads
967
+ };
968
+ }
881
969
  /** Each ref list's tips by full name, built once per list, which core's cache shares across a repository's worktrees */
882
970
  const tipsByNameCache = /* @__PURE__ */ new WeakMap();
883
971
  function getTipsByName(tips) {
@@ -901,14 +989,10 @@ async function getMovedFields(repo, last, probe, probeDirty, signal) {
901
989
  const previous = last.result.summary;
902
990
  if (probe.branch !== inputs.branch || probe.detached !== inputs.detached || probe.sha !== inputs.sha) fields |= allFields;
903
991
  else {
992
+ fields |= getUpstreamFields(probe.current, previous);
904
993
  if (probe.upstream !== inputs.upstream) fields |= 18;
905
994
  else if (getUpstreamTips(probe.tips, probe.upstream) !== inputs.upstreamTips) fields |= branchField;
906
- for (const ref of previous.baseDependsOn) {
907
- const value = getBaseInput(probe, ref);
908
- if (value !== null && value === inputs.baseTips.get(ref)) continue;
909
- baseMoves ??= /* @__PURE__ */ new Set();
910
- baseMoves.add(ref);
911
- }
995
+ baseMoves = getMovedBaseRefs(probe, previous.baseDependsOn, inputs.baseTips);
912
996
  if (baseMoves != null) fields |= baseMoveField;
913
997
  if ((fields & baseConfigField) === 0 && last.result.baseConfigKey != null && repo.branches.getAheadOfBase != null && (probe.detached || probe.branch != null)) {
914
998
  const configKey = getBaseConfigKey(await readBaseConfig(repo, signal), previous);
@@ -921,6 +1005,61 @@ async function getMovedFields(repo, last, probe, probeDirty, signal) {
921
1005
  baseMoves
922
1006
  };
923
1007
  }
1008
+ /**
1009
+ * The read groups a tip check (see {@link tipCheckField}) finds moved since `previous` was read, with the refs the base
1010
+ * depends on as `tips` has them: everything when HEAD's branch or commit isn't the one `previous` has, else those
1011
+ * {@link getUpstreamFields} finds, and the base's refs that moved
1012
+ */
1013
+ function getTipCheckFields(probe, previous, tips) {
1014
+ if (probe.branch !== previous.branch || probe.detached !== previous.detached || probe.sha !== previous.sha) return {
1015
+ fields: allFields,
1016
+ baseMoves: void 0
1017
+ };
1018
+ let fields = getUpstreamFields(probe.current, previous);
1019
+ const baseMoves = getMovedBaseRefs(probe, previous.baseDependsOn, tips?.base);
1020
+ if (baseMoves != null) fields |= baseMoveField;
1021
+ return {
1022
+ fields,
1023
+ baseMoves
1024
+ };
1025
+ }
1026
+ /**
1027
+ * The read groups `current`, HEAD as `getBranch` answers it, finds moved in what `previous` has of the upstream: another
1028
+ * upstream reads the branch and the config inputs, which read the base again when the upstream's identity changed;
1029
+ * one gone or back, or other counts against it, the branch. Core drops its cached branches, counts and all, with its
1030
+ * ref list on any change to branches or remote-tracking refs, the changes a tip check follows, so a probe after one
1031
+ * answers them as of that change.
1032
+ */
1033
+ function getUpstreamFields(current, previous) {
1034
+ const upstream = current?.upstream;
1035
+ if (upstream?.name !== previous.upstream?.name) return 18;
1036
+ if (upstream?.missing !== previous.upstream?.missing || (upstream?.state.ahead ?? 0) !== previous.ahead || (upstream?.state.behind ?? 0) !== previous.behind) return branchField;
1037
+ return 0;
1038
+ }
1039
+ /**
1040
+ * The refs of `baseDependsOn` that `probe` finds moved since `baseTips`; `undefined` when none did. A tip that's unknown
1041
+ * (`null`, or not kept) moved.
1042
+ */
1043
+ function getMovedBaseRefs(probe, baseDependsOn, baseTips) {
1044
+ let baseMoves;
1045
+ for (const ref of baseDependsOn) {
1046
+ const value = getBaseInput(probe, ref);
1047
+ if (value !== null && baseTips?.has(ref) && value === baseTips.get(ref)) continue;
1048
+ baseMoves ??= /* @__PURE__ */ new Set();
1049
+ baseMoves.add(ref);
1050
+ }
1051
+ return baseMoves;
1052
+ }
1053
+ /**
1054
+ * The tips a subscribed run leaves its summary read from: from the refs its probe found (`refs`) when it read the base,
1055
+ * unknown when it read it without a probe, and else `last`'s
1056
+ */
1057
+ function getReadTips(last, refs, result) {
1058
+ const { summary, fields } = result;
1059
+ let base = last?.base;
1060
+ if (fields & 36) base = refs != null && !summary.stale ? getBaseTips(refs, summary.baseDependsOn) : void 0;
1061
+ return { base };
1062
+ }
924
1063
  /** The upstream's tips as a remote-tracking and as a local branch, since its short name doesn't say which */
925
1064
  function getUpstreamTips(tips, upstream) {
926
1065
  if (upstream == null) return void 0;
@@ -973,18 +1112,22 @@ function getBaseInput(probe, ref) {
973
1112
  }
974
1113
  /** The inputs `summary` was read from, as the probe before its read found them */
975
1114
  function toUnwatchedInputs(probe, summary) {
976
- const baseTips = /* @__PURE__ */ new Map();
977
- for (const ref of summary.baseDependsOn) baseTips.set(ref, getBaseInput(probe, ref));
978
1115
  return {
979
1116
  branch: probe.branch,
980
1117
  detached: probe.detached,
981
1118
  sha: probe.sha,
982
1119
  upstream: probe.upstream,
983
1120
  upstreamTips: getUpstreamTips(probe.tips, probe.upstream),
984
- baseTips,
1121
+ baseTips: getBaseTips(probe, summary.baseDependsOn),
985
1122
  index: probe.index
986
1123
  };
987
1124
  }
1125
+ /** What `refs` found of each of `baseDependsOn` (see {@link getBaseInput}) */
1126
+ function getBaseTips(refs, baseDependsOn) {
1127
+ const baseTips = /* @__PURE__ */ new Map();
1128
+ for (const ref of baseDependsOn) baseTips.set(ref, getBaseInput(refs, ref));
1129
+ return baseTips;
1130
+ }
988
1131
  async function readBaseConfig(repo, signal) {
989
1132
  try {
990
1133
  if (repo.branches.getAheadOfBaseConfigEntries != null) return await repo.branches.getAheadOfBaseConfigEntries(signal);
@@ -1076,6 +1219,11 @@ async function toSummaryUpstream(repo, upstream, signal) {
1076
1219
  missing
1077
1220
  };
1078
1221
  }
1222
+ /** Whether `e` names `ref` exactly, so it's known to be a ref that moved rather than one that may have */
1223
+ function isNamedRef(e, ref) {
1224
+ const kind = getRefChangeKind(ref);
1225
+ return kind != null && e.refs.has(ref) && !e.unnamedRefKinds.has(kind);
1226
+ }
1079
1227
  function upstreamsEqual(a, b) {
1080
1228
  return a === b || a != null && b != null && a.name === b.name && a.remote === b.remote && a.branch === b.branch && a.missing === b.missing;
1081
1229
  }