git-watchtower 1.14.3 → 1.14.5
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 +27 -1
- package/package.json +1 -1
- package/src/server/coordinator.js +13 -2
package/bin/git-watchtower.js
CHANGED
|
@@ -1958,6 +1958,8 @@ async function pollGitChanges() {
|
|
|
1958
1958
|
lastPrStatusFetch = Date.now();
|
|
1959
1959
|
prStatusFetchInFlight = false;
|
|
1960
1960
|
}).catch(() => {
|
|
1961
|
+
// gh/glab errored (unauthed, rate-limited, network). PR indicators
|
|
1962
|
+
// keep their last-known state; the next poll tick will retry.
|
|
1961
1963
|
prStatusFetchInFlight = false;
|
|
1962
1964
|
});
|
|
1963
1965
|
}
|
|
@@ -2207,7 +2209,12 @@ function createStaticServer() {
|
|
|
2207
2209
|
let realStaticDir;
|
|
2208
2210
|
try {
|
|
2209
2211
|
realStaticDir = fs.realpathSync(resolvedStaticDir);
|
|
2210
|
-
} catch {
|
|
2212
|
+
} catch (e) {
|
|
2213
|
+
// STATIC_DIR comes from our own package layout, so a realpath failure
|
|
2214
|
+
// means the install is broken (missing dir, permissions, etc.) — worth
|
|
2215
|
+
// diagnosing. Fall back to the unresolved path so the request still
|
|
2216
|
+
// gets its 403 rather than crashing.
|
|
2217
|
+
telemetry.captureError(e);
|
|
2211
2218
|
realStaticDir = resolvedStaticDir;
|
|
2212
2219
|
}
|
|
2213
2220
|
if (!resolvedPath.startsWith(realStaticDir + path.sep) && resolvedPath !== realStaticDir) {
|
|
@@ -2857,6 +2864,8 @@ function setupKeyboardInput() {
|
|
|
2857
2864
|
render();
|
|
2858
2865
|
}
|
|
2859
2866
|
}).catch(() => {
|
|
2867
|
+
// Async enrichment failed (no remote, gh/glab errored, etc.).
|
|
2868
|
+
// Drop the spinner so the modal shows what we have from phase 1.
|
|
2860
2869
|
if (store.get('actionMode') && store.get('actionData') && store.get('actionData').branch.name === branch.name) {
|
|
2861
2870
|
store.setState({ actionLoading: false });
|
|
2862
2871
|
render();
|
|
@@ -3529,6 +3538,23 @@ process.on('uncaughtException', async (err) => {
|
|
|
3529
3538
|
process.exit(1);
|
|
3530
3539
|
});
|
|
3531
3540
|
|
|
3541
|
+
// Mirror of uncaughtException for unhandled promise rejections. Without this,
|
|
3542
|
+
// Node 15+ crashes the process on a missed .catch() tail with no telemetry
|
|
3543
|
+
// and no terminal restore — leaving the TUI user in a broken terminal. Also
|
|
3544
|
+
// high-signal: an unhandled rejection reaching here means we missed a .catch()
|
|
3545
|
+
// somewhere and telemetry will tell us where.
|
|
3546
|
+
process.on('unhandledRejection', async (reason) => {
|
|
3547
|
+
isShuttingDown = true;
|
|
3548
|
+
|
|
3549
|
+
cleanupResources();
|
|
3550
|
+
|
|
3551
|
+
const err = reason instanceof Error ? reason : new Error(String(reason));
|
|
3552
|
+
try { telemetry.captureError(err); } catch (_) { /* telemetry must never prevent crash cleanup */ }
|
|
3553
|
+
console.error('Unhandled rejection:', reason);
|
|
3554
|
+
try { await telemetry.shutdown(); } catch (_) { /* telemetry must never prevent crash cleanup */ }
|
|
3555
|
+
process.exit(1);
|
|
3556
|
+
});
|
|
3557
|
+
|
|
3532
3558
|
// ============================================================================
|
|
3533
3559
|
// Startup
|
|
3534
3560
|
// ============================================================================
|
package/package.json
CHANGED
|
@@ -20,6 +20,7 @@ const fs = require('fs');
|
|
|
20
20
|
const path = require('path');
|
|
21
21
|
const os = require('os');
|
|
22
22
|
const crypto = require('crypto');
|
|
23
|
+
const telemetry = require('../telemetry');
|
|
23
24
|
|
|
24
25
|
/**
|
|
25
26
|
* Directory for watchtower runtime files
|
|
@@ -359,7 +360,12 @@ class Coordinator {
|
|
|
359
360
|
try {
|
|
360
361
|
const msg = JSON.parse(line);
|
|
361
362
|
this._handleWorkerMessage(socket, msg, (id) => { workerId = id; }, () => workerId);
|
|
362
|
-
} catch (e) {
|
|
363
|
+
} catch (e) {
|
|
364
|
+
// Both sides of this socket are our own code, so a JSON-parse
|
|
365
|
+
// failure indicates a protocol/version bug worth diagnosing.
|
|
366
|
+
telemetry.captureError(e);
|
|
367
|
+
/* skip malformed frame and keep reading */
|
|
368
|
+
}
|
|
363
369
|
}
|
|
364
370
|
}
|
|
365
371
|
});
|
|
@@ -517,7 +523,12 @@ class Worker {
|
|
|
517
523
|
try {
|
|
518
524
|
const msg = JSON.parse(line);
|
|
519
525
|
this._handleMessage(msg);
|
|
520
|
-
} catch (e) {
|
|
526
|
+
} catch (e) {
|
|
527
|
+
// Both sides of this socket are our own code, so a JSON-parse
|
|
528
|
+
// failure indicates a protocol/version bug worth diagnosing.
|
|
529
|
+
telemetry.captureError(e);
|
|
530
|
+
/* skip malformed frame and keep reading */
|
|
531
|
+
}
|
|
521
532
|
}
|
|
522
533
|
}
|
|
523
534
|
});
|