git-watchtower 1.9.2 → 1.9.3

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.
@@ -82,6 +82,7 @@ const { parseGitHubPr, parseGitLabMr, parseGitHubPrList, parseGitLabMrList, isBa
82
82
  // Security & Validation (imported from src/git/branch.js and src/git/commands.js)
83
83
  // ============================================================================
84
84
  const { isValidBranchName, sanitizeBranchName, getGoneBranches, deleteGoneBranches } = require('../src/git/branch');
85
+ const { pruneStaleEntries } = require('../src/polling/engine');
85
86
  const { isGitAvailable: checkGitAvailable, execGit, execGitSilent, getDiffStats: getDiffStatsSafe, getAheadBehind, getDiffShortstat } = require('../src/git/commands');
86
87
 
87
88
  // Session stats (always-on, non-casino stats)
@@ -1817,6 +1818,16 @@ async function pollGitChanges() {
1817
1818
  }
1818
1819
  }
1819
1820
 
1821
+ // Prune stale entries: remove branches from tracking sets/caches
1822
+ // that no longer exist in git (deleted >30s ago or already gone)
1823
+ pruneStaleEntries({
1824
+ knownBranchNames,
1825
+ fetchedBranchNames,
1826
+ allBranches,
1827
+ caches: [previousBranchStates, prInfoCache, store.get('sparklineCache'), store.get('aheadBehindCache')],
1828
+ now,
1829
+ });
1830
+
1820
1831
  // Note: isNew flag is only cleared when branch becomes current (see below)
1821
1832
 
1822
1833
  // Keep deleted branches in the list (don't remove them)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "git-watchtower",
3
- "version": "1.9.2",
3
+ "version": "1.9.3",
4
4
  "description": "Terminal-based Git branch monitor with activity sparklines and optional dev server with live reload",
5
5
  "main": "bin/git-watchtower.js",
6
6
  "bin": {
@@ -147,6 +147,38 @@ function restoreSelection(branches, previousName, previousIndex) {
147
147
  return { selectedIndex: previousIndex, selectedBranchName: previousName };
148
148
  }
149
149
 
150
+ /**
151
+ * Prune stale entries from tracking sets and caches for branches
152
+ * that no longer exist in git.
153
+ * @param {Object} opts
154
+ * @param {Set<string>} opts.knownBranchNames - Known branch names (mutated)
155
+ * @param {Set<string>} opts.fetchedBranchNames - Currently fetched branch names
156
+ * @param {Array<{name: string, isDeleted?: boolean, deletedAt?: number}>} opts.allBranches - All branches including deleted
157
+ * @param {Map<string, *>[]} opts.caches - Maps to prune stale keys from
158
+ * @param {number} [opts.retentionMs=30000] - How long to keep deleted branches before pruning
159
+ * @param {number} [opts.now] - Current timestamp (defaults to Date.now())
160
+ * @returns {string[]} Names of pruned branches
161
+ */
162
+ function pruneStaleEntries({ knownBranchNames, fetchedBranchNames, allBranches, caches, retentionMs = 30000, now }) {
163
+ const timestamp = now ?? Date.now();
164
+ const pruned = [];
165
+ for (const knownName of [...knownBranchNames]) {
166
+ if (fetchedBranchNames.has(knownName)) continue;
167
+ const deletedBranch = allBranches.find(b => b.name === knownName && b.isDeleted);
168
+ const shouldPrune = deletedBranch
169
+ ? (deletedBranch.deletedAt && (timestamp - deletedBranch.deletedAt) > retentionMs)
170
+ : true; // Not in allBranches at all — stale entry
171
+ if (shouldPrune) {
172
+ knownBranchNames.delete(knownName);
173
+ for (const cache of caches) {
174
+ cache.delete(knownName);
175
+ }
176
+ pruned.push(knownName);
177
+ }
178
+ }
179
+ return pruned;
180
+ }
181
+
150
182
  module.exports = {
151
183
  detectNewBranches,
152
184
  detectDeletedBranches,
@@ -154,4 +186,5 @@ module.exports = {
154
186
  sortBranches,
155
187
  calculateAdaptiveInterval,
156
188
  restoreSelection,
189
+ pruneStaleEntries,
157
190
  };