git-watchtower 1.5.0 → 1.6.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.
@@ -77,7 +77,7 @@ const { parseGitHubPr, parseGitLabMr, parseGitHubPrList, parseGitLabMrList, isBa
77
77
  // ============================================================================
78
78
  // Security & Validation (imported from src/git/branch.js and src/git/commands.js)
79
79
  // ============================================================================
80
- const { isValidBranchName, sanitizeBranchName } = require('../src/git/branch');
80
+ const { isValidBranchName, sanitizeBranchName, getGoneBranches, deleteGoneBranches } = require('../src/git/branch');
81
81
  const { isGitAvailable: checkGitAvailable } = require('../src/git/commands');
82
82
 
83
83
  // ============================================================================
@@ -1191,6 +1191,11 @@ function render() {
1191
1191
  renderer.renderErrorToast(state, write);
1192
1192
  }
1193
1193
 
1194
+ // Cleanup confirmation dialog
1195
+ if (state.cleanupConfirmMode) {
1196
+ renderer.renderCleanupConfirm(state, write);
1197
+ }
1198
+
1194
1199
  // Stash confirmation dialog renders on top of everything
1195
1200
  if (state.stashConfirmMode) {
1196
1201
  renderer.renderStashConfirm(state, write);
@@ -2329,6 +2334,59 @@ function setupKeyboardInput() {
2329
2334
  return; // Ignore other keys in action mode
2330
2335
  }
2331
2336
 
2337
+ // Handle cleanup confirmation dialog
2338
+ if (store.get('cleanupConfirmMode')) {
2339
+ const cleanupBranches = store.get('cleanupBranches') || [];
2340
+ const maxOptions = cleanupBranches.length > 0 ? 3 : 1;
2341
+ if (key === '\u001b[A' || key === 'k') { // Up
2342
+ const idx = store.get('cleanupSelectedIndex') || 0;
2343
+ if (idx > 0) {
2344
+ store.setState({ cleanupSelectedIndex: idx - 1 });
2345
+ render();
2346
+ }
2347
+ return;
2348
+ }
2349
+ if (key === '\u001b[B' || key === 'j') { // Down
2350
+ const idx = store.get('cleanupSelectedIndex') || 0;
2351
+ if (idx < maxOptions - 1) {
2352
+ store.setState({ cleanupSelectedIndex: idx + 1 });
2353
+ render();
2354
+ }
2355
+ return;
2356
+ }
2357
+ if (key === '\r' || key === '\n') { // Enter — execute selected option
2358
+ const idx = store.get('cleanupSelectedIndex') || 0;
2359
+ applyUpdates(actions.closeCleanupConfirm(getActionState()));
2360
+ render();
2361
+ if (cleanupBranches.length === 0 || idx === maxOptions - 1) {
2362
+ // Cancel or Close (no branches)
2363
+ return;
2364
+ }
2365
+ const force = idx === 1; // 0=safe delete, 1=force delete, 2=cancel
2366
+ addLog(`Cleaning up ${cleanupBranches.length} stale branch${cleanupBranches.length === 1 ? '' : 'es'}${force ? ' (force)' : ''}...`, 'update');
2367
+ render();
2368
+ const result = await deleteGoneBranches(cleanupBranches, { force });
2369
+ for (const name of result.deleted) {
2370
+ addLog(`Deleted branch: ${name}`, 'success');
2371
+ }
2372
+ for (const f of result.failed) {
2373
+ addLog(`Failed to delete ${f.name}: ${f.error}`, 'error');
2374
+ }
2375
+ if (result.deleted.length > 0) {
2376
+ addLog(`Cleaned up ${result.deleted.length} branch${result.deleted.length === 1 ? '' : 'es'}`, 'success');
2377
+ await pollGitChanges();
2378
+ }
2379
+ render();
2380
+ return;
2381
+ }
2382
+ if (key === '\u001b') { // Escape — cancel
2383
+ applyUpdates(actions.closeCleanupConfirm(getActionState()));
2384
+ render();
2385
+ return;
2386
+ }
2387
+ return; // Ignore other keys in cleanup mode
2388
+ }
2389
+
2332
2390
  // Handle stash confirmation dialog
2333
2391
  if (store.get('stashConfirmMode')) {
2334
2392
  if (key === '\u001b[A' || key === 'k') { // Up
@@ -2565,6 +2623,15 @@ function setupKeyboardInput() {
2565
2623
  break;
2566
2624
  }
2567
2625
 
2626
+ case 'd': { // Cleanup stale branches (remotes deleted)
2627
+ addLog('Scanning for stale branches...', 'info');
2628
+ render();
2629
+ const goneBranches = await getGoneBranches();
2630
+ applyUpdates(actions.openCleanupConfirm(actionState, goneBranches));
2631
+ render();
2632
+ break;
2633
+ }
2634
+
2568
2635
  // Number keys to set visible branch count
2569
2636
  case '1': case '2': case '3': case '4': case '5':
2570
2637
  case '6': case '7': case '8': case '9':
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "git-watchtower",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
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": {