git-watchtower 1.14.2 → 1.14.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.
package/bin/git-watchtower.js
CHANGED
|
@@ -654,7 +654,7 @@ async function loadAsyncActionData(branch, currentData) {
|
|
|
654
654
|
try {
|
|
655
655
|
const host = new URL(env.webUrlBase).hostname;
|
|
656
656
|
webUrl = buildBranchUrl(env.webUrlBase, host, branch.name);
|
|
657
|
-
} catch (e) { /*
|
|
657
|
+
} catch (e) { /* invalid webUrlBase — leave webUrl null, modal hides the link */ }
|
|
658
658
|
}
|
|
659
659
|
|
|
660
660
|
// Fetch session URL (local git, fast but async)
|
|
@@ -1963,7 +1963,7 @@ async function pollGitChanges() {
|
|
|
1963
1963
|
}
|
|
1964
1964
|
|
|
1965
1965
|
// Background ahead/behind fetch for visible branches
|
|
1966
|
-
fetchAheadBehindForBranches(pollFilteredBranches).catch(() => {});
|
|
1966
|
+
fetchAheadBehindForBranches(pollFilteredBranches).catch(() => { /* transient git/network error — next poll will retry */ });
|
|
1967
1967
|
|
|
1968
1968
|
// AUTO-PULL: If current branch has remote updates, pull automatically (if enabled)
|
|
1969
1969
|
const autoPullBranchName = store.get('currentBranch');
|
|
@@ -2447,7 +2447,7 @@ function setupKeyboardInput() {
|
|
|
2447
2447
|
store.setState({ actionData: fullData, actionLoading: false });
|
|
2448
2448
|
render();
|
|
2449
2449
|
}
|
|
2450
|
-
}).catch(() => {});
|
|
2450
|
+
}).catch(() => { /* PR was created; modal refresh is a nice-to-have, user can reopen */ });
|
|
2451
2451
|
} catch (e) {
|
|
2452
2452
|
const msg = (e && e.stderr) || (e && e.message) || String(e);
|
|
2453
2453
|
addLog(`Failed to create ${prLabel}: ${msg.split('\n')[0]}`, 'error');
|
|
@@ -2930,7 +2930,7 @@ function setupKeyboardInput() {
|
|
|
2930
2930
|
} else {
|
|
2931
2931
|
startWebDashboard(true).then(() => {
|
|
2932
2932
|
showFlash(`Web dashboard on :${WEB_PORT}`);
|
|
2933
|
-
}).catch(() => {});
|
|
2933
|
+
}).catch(() => { /* startWebDashboard surfaces its own errors via addLog/showErrorToast */ });
|
|
2934
2934
|
}
|
|
2935
2935
|
break;
|
|
2936
2936
|
}
|
|
@@ -3190,7 +3190,7 @@ async function startWebDashboard(openBrowser) {
|
|
|
3190
3190
|
// Resolve and cache the repo web URL for link building in the web UI
|
|
3191
3191
|
getRemoteWebUrl(null).then((url) => {
|
|
3192
3192
|
if (url) webDashboard.setRepoWebUrl(url);
|
|
3193
|
-
}).catch(() => {});
|
|
3193
|
+
}).catch(() => { /* no remote or unreachable — web UI falls back to branch names without links */ });
|
|
3194
3194
|
|
|
3195
3195
|
// Atomically try to claim the coordinator role. If another live instance
|
|
3196
3196
|
// already owns the lock, connect as a worker instead. This prevents a
|
|
@@ -3317,10 +3317,10 @@ async function startWebDashboard(openBrowser) {
|
|
|
3317
3317
|
webStateInterval = null;
|
|
3318
3318
|
}
|
|
3319
3319
|
if (webDashboard) {
|
|
3320
|
-
try { webDashboard.stop(); } catch (_) { /*
|
|
3320
|
+
try { webDashboard.stop(); } catch (_) { /* web server may not have bound yet — nothing to stop */ }
|
|
3321
3321
|
}
|
|
3322
3322
|
if (coordinator) {
|
|
3323
|
-
try { coordinator.stop(); } catch (_) { /*
|
|
3323
|
+
try { coordinator.stop(); } catch (_) { /* coordinator may not have started its IPC server */ }
|
|
3324
3324
|
}
|
|
3325
3325
|
removeLock();
|
|
3326
3326
|
removeSocket();
|
|
@@ -3387,7 +3387,7 @@ function restartProcess() {
|
|
|
3387
3387
|
// child can acquire it. The parent stays alive waiting on child.on('close'),
|
|
3388
3388
|
// so without this the child sees the parent as an active owner and refuses.
|
|
3389
3389
|
if (monitorLockFile) {
|
|
3390
|
-
try { monitorLock.release(monitorLockFile); } catch (_) { /*
|
|
3390
|
+
try { monitorLock.release(monitorLockFile); } catch (_) { /* lock file may have already been unlinked */ }
|
|
3391
3391
|
monitorLockFile = null;
|
|
3392
3392
|
}
|
|
3393
3393
|
|
|
@@ -3433,23 +3433,23 @@ function cleanupResources() {
|
|
|
3433
3433
|
|
|
3434
3434
|
// Restore terminal first so the user sees a clean prompt even if a
|
|
3435
3435
|
// later step throws.
|
|
3436
|
-
try { write(ansi.showCursor); } catch (_) { /*
|
|
3437
|
-
try { write(ansi.restoreScreen); } catch (_) { /*
|
|
3438
|
-
try { restoreTerminalTitle(); } catch (_) { /*
|
|
3439
|
-
try { if (process.stdin.isTTY) process.stdin.setRawMode(false); } catch (_) { /*
|
|
3440
|
-
try { process.stdin.pause(); } catch (_) { /*
|
|
3436
|
+
try { write(ansi.showCursor); } catch (_) { /* stdout may be closed during crash cleanup */ }
|
|
3437
|
+
try { write(ansi.restoreScreen); } catch (_) { /* stdout may be closed during crash cleanup */ }
|
|
3438
|
+
try { restoreTerminalTitle(); } catch (_) { /* stdout may be closed during crash cleanup */ }
|
|
3439
|
+
try { if (process.stdin.isTTY) process.stdin.setRawMode(false); } catch (_) { /* stdin may already be unraw or detached */ }
|
|
3440
|
+
try { process.stdin.pause(); } catch (_) { /* stdin may already be paused or destroyed */ }
|
|
3441
3441
|
|
|
3442
3442
|
if (pollIntervalId) {
|
|
3443
|
-
try { clearTimeout(pollIntervalId); } catch (_) { /*
|
|
3443
|
+
try { clearTimeout(pollIntervalId); } catch (_) { /* defensive — clearTimeout normally won't throw */ }
|
|
3444
3444
|
pollIntervalId = null;
|
|
3445
3445
|
}
|
|
3446
3446
|
|
|
3447
3447
|
if (periodicUpdateCheck) {
|
|
3448
|
-
try { periodicUpdateCheck.stop(); } catch (_) { /*
|
|
3448
|
+
try { periodicUpdateCheck.stop(); } catch (_) { /* interval handle may already be cleared */ }
|
|
3449
3449
|
}
|
|
3450
3450
|
|
|
3451
3451
|
if (fileWatcher) {
|
|
3452
|
-
try { fileWatcher.close(); } catch (_) { /*
|
|
3452
|
+
try { fileWatcher.close(); } catch (_) { /* watcher may already be closed by OS or previous cleanup */ }
|
|
3453
3453
|
fileWatcher = null;
|
|
3454
3454
|
}
|
|
3455
3455
|
|
|
@@ -3457,24 +3457,24 @@ function cleanupResources() {
|
|
|
3457
3457
|
if (SERVER_MODE === 'static') {
|
|
3458
3458
|
try {
|
|
3459
3459
|
clients.forEach((client) => {
|
|
3460
|
-
try { client.end(); } catch (_) { /*
|
|
3460
|
+
try { client.end(); } catch (_) { /* SSE client socket already closed */ }
|
|
3461
3461
|
});
|
|
3462
3462
|
clients.clear();
|
|
3463
|
-
} catch (_) { /*
|
|
3463
|
+
} catch (_) { /* clients set may have mutated mid-iteration during shutdown */ }
|
|
3464
3464
|
}
|
|
3465
3465
|
|
|
3466
3466
|
// User's dev-server process (command mode)
|
|
3467
3467
|
if (SERVER_MODE === 'command') {
|
|
3468
|
-
try { stopServerProcess(); } catch (_) { /*
|
|
3468
|
+
try { stopServerProcess(); } catch (_) { /* dev-server child may already be gone */ }
|
|
3469
3469
|
}
|
|
3470
3470
|
|
|
3471
3471
|
// Web dashboard + worker/coordinator (unlinks lock file + IPC socket)
|
|
3472
|
-
try { stopWebDashboard(); } catch (_) { /*
|
|
3472
|
+
try { stopWebDashboard(); } catch (_) { /* web dashboard may never have been started */ }
|
|
3473
3473
|
|
|
3474
3474
|
// Per-repo monitor lock — release last so the slot stays reserved for the
|
|
3475
3475
|
// entire lifetime of this process, including any errors in the steps above.
|
|
3476
3476
|
if (monitorLockFile) {
|
|
3477
|
-
try { monitorLock.release(monitorLockFile); } catch (_) { /*
|
|
3477
|
+
try { monitorLock.release(monitorLockFile); } catch (_) { /* lock file may have been unlinked externally */ }
|
|
3478
3478
|
monitorLockFile = null;
|
|
3479
3479
|
}
|
|
3480
3480
|
}
|
|
@@ -3523,9 +3523,9 @@ process.on('uncaughtException', async (err) => {
|
|
|
3523
3523
|
// if telemetry shutdown hangs or throws.
|
|
3524
3524
|
cleanupResources();
|
|
3525
3525
|
|
|
3526
|
-
try { telemetry.captureError(err); } catch (_) { /*
|
|
3526
|
+
try { telemetry.captureError(err); } catch (_) { /* telemetry must never prevent crash cleanup */ }
|
|
3527
3527
|
console.error('Uncaught exception:', err);
|
|
3528
|
-
try { await telemetry.shutdown(); } catch (_) { /*
|
|
3528
|
+
try { await telemetry.shutdown(); } catch (_) { /* telemetry must never prevent crash cleanup */ }
|
|
3529
3529
|
process.exit(1);
|
|
3530
3530
|
});
|
|
3531
3531
|
|
|
@@ -3652,11 +3652,11 @@ async function start() {
|
|
|
3652
3652
|
|
|
3653
3653
|
// Detect default branch for ahead/behind counts, then fetch initial data
|
|
3654
3654
|
detectDefaultBranch().then(() => {
|
|
3655
|
-
fetchAheadBehindForBranches(initBranches).catch(() => {});
|
|
3656
|
-
}).catch(() => {});
|
|
3655
|
+
fetchAheadBehindForBranches(initBranches).catch(() => { /* ahead/behind is background-only — stale counts are better than a noisy startup */ });
|
|
3656
|
+
}).catch(() => { /* no default branch detectable (no remote refs yet) — ahead/behind stays hidden */ });
|
|
3657
3657
|
|
|
3658
3658
|
// Load sparklines and action cache in background
|
|
3659
|
-
refreshAllSparklines().catch(() => {});
|
|
3659
|
+
refreshAllSparklines().catch(() => { /* sparkline cache stays empty — activity column just renders blank */ });
|
|
3660
3660
|
initActionCache().then(() => {
|
|
3661
3661
|
// Once env is known, kick off initial PR status fetch
|
|
3662
3662
|
fetchAllPrStatuses().then(map => {
|
|
@@ -3665,8 +3665,8 @@ async function start() {
|
|
|
3665
3665
|
lastPrStatusFetch = Date.now();
|
|
3666
3666
|
render();
|
|
3667
3667
|
}
|
|
3668
|
-
}).catch(() => {});
|
|
3669
|
-
}).catch(() => {});
|
|
3668
|
+
}).catch(() => { /* gh/glab unreachable — inline PR indicators stay hidden, poller will retry */ });
|
|
3669
|
+
}).catch(() => { /* cliEnv detection failed — PR actions fall back to web links where possible */ });
|
|
3670
3670
|
|
|
3671
3671
|
// Start server based on mode
|
|
3672
3672
|
const startBranchName = store.get('currentBranch');
|
|
@@ -3737,7 +3737,7 @@ async function start() {
|
|
|
3737
3737
|
addLog(`New version available: ${latestVersion} \u2192 npm i -g git-watchtower`, 'update');
|
|
3738
3738
|
render();
|
|
3739
3739
|
}
|
|
3740
|
-
}).catch(() => {});
|
|
3740
|
+
}).catch(() => { /* npm registry unreachable — periodic check will try again in 4h */ });
|
|
3741
3741
|
|
|
3742
3742
|
// Re-check for updates periodically (every 4 hours) while running.
|
|
3743
3743
|
// Assigned to module scope so the top-level exit handler can stop it.
|
package/package.json
CHANGED
package/src/git/remote.js
CHANGED
|
@@ -77,7 +77,7 @@ function detectPlatform(webUrl) {
|
|
|
77
77
|
if (host === 'gitlab.com' || parts.includes('gitlab')) return 'gitlab';
|
|
78
78
|
if (host === 'bitbucket.org' || parts.includes('bitbucket')) return 'bitbucket';
|
|
79
79
|
if (host === 'dev.azure.com' || host.endsWith('.visualstudio.com')) return 'azure';
|
|
80
|
-
} catch (e) { /*
|
|
80
|
+
} catch (e) { /* webUrl isn't a valid URL — fall through to the self-hosted default */ }
|
|
81
81
|
return 'github'; // default assumption for self-hosted
|
|
82
82
|
}
|
|
83
83
|
|
|
@@ -161,14 +161,14 @@ function finalizeLock(pid, port, socketPath) {
|
|
|
161
161
|
* Remove the lock file.
|
|
162
162
|
*/
|
|
163
163
|
function removeLock() {
|
|
164
|
-
try { fs.unlinkSync(LOCK_FILE); } catch (e) { /*
|
|
164
|
+
try { fs.unlinkSync(LOCK_FILE); } catch (e) { /* lock file may not exist */ }
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
/**
|
|
168
168
|
* Remove stale socket file.
|
|
169
169
|
*/
|
|
170
170
|
function removeSocket() {
|
|
171
|
-
try { fs.unlinkSync(SOCKET_PATH); } catch (e) { /*
|
|
171
|
+
try { fs.unlinkSync(SOCKET_PATH); } catch (e) { /* socket file may not exist */ }
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
/**
|
|
@@ -255,7 +255,7 @@ class Coordinator {
|
|
|
255
255
|
stop() {
|
|
256
256
|
// Close all worker sockets
|
|
257
257
|
for (const socket of this.workerSockets.values()) {
|
|
258
|
-
try { socket.destroy(); } catch (e) { /*
|
|
258
|
+
try { socket.destroy(); } catch (e) { /* socket may already be destroyed */ }
|
|
259
259
|
}
|
|
260
260
|
this.workerSockets.clear();
|
|
261
261
|
this.projects.clear();
|
|
@@ -359,7 +359,7 @@ class Coordinator {
|
|
|
359
359
|
try {
|
|
360
360
|
const msg = JSON.parse(line);
|
|
361
361
|
this._handleWorkerMessage(socket, msg, (id) => { workerId = id; }, () => workerId);
|
|
362
|
-
} catch (e) { /*
|
|
362
|
+
} catch (e) { /* malformed IPC frame from worker — skip it and keep reading */ }
|
|
363
363
|
}
|
|
364
364
|
}
|
|
365
365
|
});
|
|
@@ -445,7 +445,7 @@ class Coordinator {
|
|
|
445
445
|
_sendMessage(socket, msg) {
|
|
446
446
|
try {
|
|
447
447
|
socket.write(JSON.stringify(msg) + '\n');
|
|
448
|
-
} catch (e) { /*
|
|
448
|
+
} catch (e) { /* peer socket closed between iteration and write — peer will reconnect if it recovers */ }
|
|
449
449
|
}
|
|
450
450
|
|
|
451
451
|
/**
|
|
@@ -517,7 +517,7 @@ class Worker {
|
|
|
517
517
|
try {
|
|
518
518
|
const msg = JSON.parse(line);
|
|
519
519
|
this._handleMessage(msg);
|
|
520
|
-
} catch (e) { /*
|
|
520
|
+
} catch (e) { /* malformed IPC frame from coordinator — skip it and keep reading */ }
|
|
521
521
|
}
|
|
522
522
|
}
|
|
523
523
|
});
|
|
@@ -574,7 +574,7 @@ class Worker {
|
|
|
574
574
|
if (this.socket && this._connected) {
|
|
575
575
|
try {
|
|
576
576
|
this.socket.write(JSON.stringify(msg) + '\n');
|
|
577
|
-
} catch (e) { /*
|
|
577
|
+
} catch (e) { /* coordinator socket closed between isConnected() check and write */ }
|
|
578
578
|
}
|
|
579
579
|
}
|
|
580
580
|
|
package/src/server/web-ui/js.js
CHANGED
|
@@ -70,7 +70,7 @@ function getDashboardJs() {
|
|
|
70
70
|
function savePrefs(updates) {
|
|
71
71
|
const prefs = loadPrefs();
|
|
72
72
|
Object.keys(updates).forEach((k) => { prefs[k] = updates[k]; });
|
|
73
|
-
try { localStorage.setItem(PREFS_KEY, JSON.stringify(prefs)); } catch (e) { /*
|
|
73
|
+
try { localStorage.setItem(PREFS_KEY, JSON.stringify(prefs)); } catch (e) { /* localStorage quota exceeded or disabled (private mode) — prefs are best-effort */ }
|
|
74
74
|
return prefs;
|
|
75
75
|
}
|
|
76
76
|
const prefs = loadPrefs();
|
|
@@ -122,7 +122,7 @@ function getDashboardJs() {
|
|
|
122
122
|
try {
|
|
123
123
|
const n = new Notification(title, { body, tag: tag || 'git-watchtower', icon: '', silent: false });
|
|
124
124
|
setTimeout(() => n.close(), 8000);
|
|
125
|
-
} catch (e) { /*
|
|
125
|
+
} catch (e) { /* Notification constructor can throw on some browsers (e.g. permission revoked mid-session) */ }
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
function diffBranchesForNotifications(oldBranches, newBranches) {
|
|
@@ -232,14 +232,14 @@ function getDashboardJs() {
|
|
|
232
232
|
}
|
|
233
233
|
renderTabs();
|
|
234
234
|
render();
|
|
235
|
-
} catch (err) { /*
|
|
235
|
+
} catch (err) { /* malformed SSE state frame — skip this push, next one will re-render */ }
|
|
236
236
|
});
|
|
237
237
|
|
|
238
238
|
evtSource.addEventListener('flash', (e) => {
|
|
239
239
|
try {
|
|
240
240
|
const data = JSON.parse(e.data);
|
|
241
241
|
showFlash(data.text, data.type);
|
|
242
|
-
} catch (err) { /*
|
|
242
|
+
} catch (err) { /* malformed flash payload — not worth surfacing, skip */ }
|
|
243
243
|
});
|
|
244
244
|
|
|
245
245
|
evtSource.addEventListener('actionResult', (e) => {
|
|
@@ -251,7 +251,7 @@ function getDashboardJs() {
|
|
|
251
251
|
} else {
|
|
252
252
|
showToast(data.message, data.success ? 'success' : 'error');
|
|
253
253
|
}
|
|
254
|
-
} catch (err) { /*
|
|
254
|
+
} catch (err) { /* malformed actionResult payload — skip (the action already ran server-side) */ }
|
|
255
255
|
});
|
|
256
256
|
|
|
257
257
|
evtSource.onerror = () => {
|
|
@@ -434,7 +434,7 @@ function getDashboardJs() {
|
|
|
434
434
|
state.serverMode = pState.serverMode || 'none';
|
|
435
435
|
state.repoWebUrl = pState.repoWebUrl || null;
|
|
436
436
|
render();
|
|
437
|
-
} catch (err) { /*
|
|
437
|
+
} catch (err) { /* malformed per-project state response — keep current view until the next poll */ }
|
|
438
438
|
}
|
|
439
439
|
};
|
|
440
440
|
xhr.send();
|
|
@@ -804,8 +804,8 @@ ${pureFnBlock}
|
|
|
804
804
|
const btn = e.target.closest('.action-item');
|
|
805
805
|
if (!btn) return;
|
|
806
806
|
const key = btn.getAttribute('data-action-key');
|
|
807
|
-
|
|
808
|
-
try { data = JSON.parse(btn.getAttribute('data-action-data') || '{}'); } catch (err) { /*
|
|
807
|
+
let data = {};
|
|
808
|
+
try { data = JSON.parse(btn.getAttribute('data-action-data') || '{}'); } catch (err) { /* malformed data-action-data — fall through with empty object */ }
|
|
809
809
|
|
|
810
810
|
hideBranchActions();
|
|
811
811
|
|
package/src/server/web.js
CHANGED
|
@@ -272,7 +272,7 @@ class WebDashboardServer {
|
|
|
272
272
|
|
|
273
273
|
// Close all SSE connections
|
|
274
274
|
for (const client of this.clients) {
|
|
275
|
-
try { client.end(); } catch (e) { /*
|
|
275
|
+
try { client.end(); } catch (e) { /* SSE client may already be disconnected */ }
|
|
276
276
|
}
|
|
277
277
|
this.clients.clear();
|
|
278
278
|
|
|
@@ -293,7 +293,7 @@ class WebDashboardServer {
|
|
|
293
293
|
try {
|
|
294
294
|
client.write('event: flash\n');
|
|
295
295
|
client.write('data: ' + data + '\n\n');
|
|
296
|
-
} catch (e) { /*
|
|
296
|
+
} catch (e) { /* SSE client disconnected — will be pruned when its response closes */ }
|
|
297
297
|
}
|
|
298
298
|
}
|
|
299
299
|
|
|
@@ -307,7 +307,7 @@ class WebDashboardServer {
|
|
|
307
307
|
try {
|
|
308
308
|
client.write('event: preview\n');
|
|
309
309
|
client.write('data: ' + json + '\n\n');
|
|
310
|
-
} catch (e) { /*
|
|
310
|
+
} catch (e) { /* SSE client disconnected — will be pruned when its response closes */ }
|
|
311
311
|
}
|
|
312
312
|
}
|
|
313
313
|
|
|
@@ -321,7 +321,7 @@ class WebDashboardServer {
|
|
|
321
321
|
try {
|
|
322
322
|
client.write('event: actionResult\n');
|
|
323
323
|
client.write('data: ' + json + '\n\n');
|
|
324
|
-
} catch (e) { /*
|
|
324
|
+
} catch (e) { /* SSE client disconnected — will be pruned when its response closes */ }
|
|
325
325
|
}
|
|
326
326
|
}
|
|
327
327
|
|
|
@@ -100,7 +100,7 @@ function startPeriodicUpdateCheck(onUpdateFound, interval = UPDATE_CHECK_INTERVA
|
|
|
100
100
|
.then((latestVersion) => {
|
|
101
101
|
if (latestVersion) onUpdateFound(latestVersion);
|
|
102
102
|
})
|
|
103
|
-
.catch(() => {});
|
|
103
|
+
.catch(() => { /* npm registry unreachable — next scheduled tick will try again */ });
|
|
104
104
|
}, interval);
|
|
105
105
|
|
|
106
106
|
return { stop: () => clearInterval(timerId) };
|