@delt/claude-alarm 0.8.0 → 0.8.1
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/dist/cli.js +108 -31
- package/dist/cli.js.map +1 -1
- package/dist/hub/server.js +74 -10
- package/dist/hub/server.js.map +1 -1
- package/dist/index.js +74 -10
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/hub/server.ts
|
|
2
2
|
import http from "http";
|
|
3
|
-
import
|
|
3
|
+
import fs4 from "fs";
|
|
4
4
|
import path4 from "path";
|
|
5
5
|
import { fileURLToPath } from "url";
|
|
6
6
|
import { WebSocketServer, WebSocket } from "ws";
|
|
@@ -677,6 +677,54 @@ function setupMcpConfig(targetDir) {
|
|
|
677
677
|
return mcpPath;
|
|
678
678
|
}
|
|
679
679
|
|
|
680
|
+
// src/shared/crash-guard.ts
|
|
681
|
+
import fs3 from "fs";
|
|
682
|
+
var BURST_WINDOW_MS = 6e4;
|
|
683
|
+
var BURST_LIMIT = 10;
|
|
684
|
+
function appendToLog(text) {
|
|
685
|
+
try {
|
|
686
|
+
fs3.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
687
|
+
fs3.appendFileSync(LOG_FILE, text, "utf-8");
|
|
688
|
+
} catch {
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
function describe(err) {
|
|
692
|
+
if (err instanceof Error) return err.stack ?? `${err.name}: ${err.message}`;
|
|
693
|
+
try {
|
|
694
|
+
return JSON.stringify(err);
|
|
695
|
+
} catch {
|
|
696
|
+
return String(err);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
function installCrashGuard(context) {
|
|
700
|
+
let recent = [];
|
|
701
|
+
const handle = (kind, err) => {
|
|
702
|
+
const stack = describe(err);
|
|
703
|
+
appendToLog(`
|
|
704
|
+
[${(/* @__PURE__ */ new Date()).toISOString()}] ${kind} (${context})
|
|
705
|
+
${stack}
|
|
706
|
+
`);
|
|
707
|
+
logger.error(`${kind} caught by crash guard: ${stack}`);
|
|
708
|
+
const now = Date.now();
|
|
709
|
+
recent = recent.filter((t) => now - t < BURST_WINDOW_MS);
|
|
710
|
+
recent.push(now);
|
|
711
|
+
if (recent.length > BURST_LIMIT) {
|
|
712
|
+
const msg = `${recent.length} unhandled errors within ${BURST_WINDOW_MS / 1e3}s \u2014 exiting`;
|
|
713
|
+
appendToLog(`[${(/* @__PURE__ */ new Date()).toISOString()}] ${msg}
|
|
714
|
+
`);
|
|
715
|
+
logger.error(msg);
|
|
716
|
+
process.exit(1);
|
|
717
|
+
}
|
|
718
|
+
};
|
|
719
|
+
process.on("uncaughtException", (err) => handle("uncaughtException", err));
|
|
720
|
+
process.on("unhandledRejection", (reason) => handle("unhandledRejection", reason));
|
|
721
|
+
}
|
|
722
|
+
function logStartup(context) {
|
|
723
|
+
appendToLog(`
|
|
724
|
+
[${(/* @__PURE__ */ new Date()).toISOString()}] ${context} started (pid ${process.pid})
|
|
725
|
+
`);
|
|
726
|
+
}
|
|
727
|
+
|
|
680
728
|
// src/hub/server.ts
|
|
681
729
|
var __dirname = path4.dirname(fileURLToPath(import.meta.url));
|
|
682
730
|
var HubServer = class {
|
|
@@ -720,9 +768,12 @@ var HubServer = class {
|
|
|
720
768
|
this.httpServer = http.createServer((req, res) => this.handleHttp(req, res));
|
|
721
769
|
this.wssChannel = new WebSocketServer({ noServer: true });
|
|
722
770
|
this.wssChannel.on("connection", (ws, req) => this.handleChannelConnection(ws, req));
|
|
771
|
+
this.wssChannel.on("error", (err) => logger.warn(`Channel WebSocket server error: ${err.message}`));
|
|
723
772
|
this.wssDashboard = new WebSocketServer({ noServer: true });
|
|
724
773
|
this.wssDashboard.on("connection", (ws) => this.handleDashboardConnection(ws));
|
|
774
|
+
this.wssDashboard.on("error", (err) => logger.warn(`Dashboard WebSocket server error: ${err.message}`));
|
|
725
775
|
this.httpServer.on("upgrade", (req, socket, head) => {
|
|
776
|
+
socket.on("error", (err) => logger.debug(`Upgrade socket error: ${err.message}`));
|
|
726
777
|
const url = new URL(req.url, `http://${req.headers.host}`);
|
|
727
778
|
const pathname = url.pathname;
|
|
728
779
|
if (this.token && !this.isLocalRequest(req)) {
|
|
@@ -749,8 +800,11 @@ var HubServer = class {
|
|
|
749
800
|
this.cleanupUploads();
|
|
750
801
|
this.startHeartbeat();
|
|
751
802
|
return new Promise((resolve, reject) => {
|
|
752
|
-
|
|
803
|
+
const onStartupError = (err) => reject(err);
|
|
804
|
+
this.httpServer.once("error", onStartupError);
|
|
753
805
|
this.httpServer.listen(this.port, this.host, () => {
|
|
806
|
+
this.httpServer.removeListener("error", onStartupError);
|
|
807
|
+
this.httpServer.on("error", (err) => logger.error(`HTTP server error: ${err.message}`));
|
|
754
808
|
const displayHost = this.host === "0.0.0.0" ? "127.0.0.1" : this.host;
|
|
755
809
|
logger.info(`Hub server listening on http://${displayHost}:${this.port}`);
|
|
756
810
|
resolve();
|
|
@@ -871,8 +925,8 @@ var HubServer = class {
|
|
|
871
925
|
];
|
|
872
926
|
logger.debug(`Dashboard candidates: ${JSON.stringify(candidates)}`);
|
|
873
927
|
for (const candidate of candidates) {
|
|
874
|
-
if (
|
|
875
|
-
const html =
|
|
928
|
+
if (fs4.existsSync(candidate)) {
|
|
929
|
+
const html = fs4.readFileSync(candidate, "utf-8");
|
|
876
930
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
877
931
|
res.end(html);
|
|
878
932
|
return;
|
|
@@ -919,6 +973,10 @@ var HubServer = class {
|
|
|
919
973
|
handleChannelConnection(ws, req) {
|
|
920
974
|
const isLocal = this.isLocalRequest(req);
|
|
921
975
|
logger.info(`Channel server connected (local: ${isLocal})`);
|
|
976
|
+
ws.on("error", (err) => {
|
|
977
|
+
logger.warn(`Channel WebSocket error: ${err.message}`);
|
|
978
|
+
ws.terminate();
|
|
979
|
+
});
|
|
922
980
|
ws.on("pong", () => {
|
|
923
981
|
for (const [sessionId, sock] of this.channelSockets) {
|
|
924
982
|
if (sock === ws) {
|
|
@@ -1028,6 +1086,10 @@ var HubServer = class {
|
|
|
1028
1086
|
handleDashboardConnection(ws) {
|
|
1029
1087
|
this.dashboardSockets.add(ws);
|
|
1030
1088
|
logger.info(`Dashboard connected (total: ${this.dashboardSockets.size})`);
|
|
1089
|
+
ws.on("error", (err) => {
|
|
1090
|
+
logger.warn(`Dashboard WebSocket error: ${err.message}`);
|
|
1091
|
+
ws.terminate();
|
|
1092
|
+
});
|
|
1031
1093
|
const sessionsMsg = {
|
|
1032
1094
|
type: "sessions_list",
|
|
1033
1095
|
sessions: this.sessions.getAll()
|
|
@@ -1084,11 +1146,11 @@ var HubServer = class {
|
|
|
1084
1146
|
logger.warn("Image upload rejected: exceeds 10MB");
|
|
1085
1147
|
return;
|
|
1086
1148
|
}
|
|
1087
|
-
|
|
1149
|
+
fs4.mkdirSync(UPLOADS_DIR, { recursive: true });
|
|
1088
1150
|
const ext = mimeType.split("/")[1] === "jpeg" ? "jpg" : mimeType.split("/")[1];
|
|
1089
1151
|
const filename = `${randomUUID3()}.${ext}`;
|
|
1090
1152
|
const filePath = path4.join(UPLOADS_DIR, filename);
|
|
1091
|
-
|
|
1153
|
+
fs4.writeFileSync(filePath, buffer);
|
|
1092
1154
|
const forwardMsg = {
|
|
1093
1155
|
type: "image_to_session",
|
|
1094
1156
|
sessionId,
|
|
@@ -1101,7 +1163,7 @@ var HubServer = class {
|
|
|
1101
1163
|
logger.info(`Image saved and forwarded: ${filename} (${buffer.length} bytes)`);
|
|
1102
1164
|
setTimeout(() => {
|
|
1103
1165
|
try {
|
|
1104
|
-
|
|
1166
|
+
fs4.unlinkSync(filePath);
|
|
1105
1167
|
} catch {
|
|
1106
1168
|
}
|
|
1107
1169
|
}, 5 * 60 * 1e3);
|
|
@@ -1271,11 +1333,11 @@ var HubServer = class {
|
|
|
1271
1333
|
}
|
|
1272
1334
|
cleanupUploads() {
|
|
1273
1335
|
try {
|
|
1274
|
-
if (!
|
|
1275
|
-
const files =
|
|
1336
|
+
if (!fs4.existsSync(UPLOADS_DIR)) return;
|
|
1337
|
+
const files = fs4.readdirSync(UPLOADS_DIR);
|
|
1276
1338
|
for (const file of files) {
|
|
1277
1339
|
try {
|
|
1278
|
-
|
|
1340
|
+
fs4.unlinkSync(path4.join(UPLOADS_DIR, file));
|
|
1279
1341
|
} catch {
|
|
1280
1342
|
}
|
|
1281
1343
|
}
|
|
@@ -1319,6 +1381,8 @@ var HubServer = class {
|
|
|
1319
1381
|
}
|
|
1320
1382
|
};
|
|
1321
1383
|
if (process.argv[1] && (process.argv[1].endsWith("hub/server.js") || process.argv[1].endsWith("hub/server.ts"))) {
|
|
1384
|
+
installCrashGuard("hub daemon");
|
|
1385
|
+
logStartup("Hub daemon");
|
|
1322
1386
|
const config = loadConfig();
|
|
1323
1387
|
const hub = new HubServer(config);
|
|
1324
1388
|
hub.start().catch((err) => {
|