@delt/claude-alarm 1.3.0 → 1.4.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.
- package/dist/cli.js +178 -49
- package/dist/cli.js.map +1 -1
- package/dist/codex/main.js +161 -32
- package/dist/codex/main.js.map +1 -1
- package/dist/dashboard/index.html +77 -46
- package/dist/hub/server.js +56 -31
- package/dist/hub/server.js.map +1 -1
- package/dist/index.d.ts +8 -2
- package/dist/index.js +56 -31
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/dashboard/index.html +77 -46
package/dist/cli.js
CHANGED
|
@@ -301,7 +301,7 @@ var init_session_manager = __esm({
|
|
|
301
301
|
|
|
302
302
|
// src/hub/notifier.ts
|
|
303
303
|
import notifier from "node-notifier";
|
|
304
|
-
import { execFile } from "child_process";
|
|
304
|
+
import { execFile as execFile2 } from "child_process";
|
|
305
305
|
var Notifier;
|
|
306
306
|
var init_notifier = __esm({
|
|
307
307
|
"src/hub/notifier.ts"() {
|
|
@@ -362,7 +362,7 @@ var init_notifier = __esm({
|
|
|
362
362
|
}
|
|
363
363
|
checkWindowsNotifications() {
|
|
364
364
|
return new Promise((resolve) => {
|
|
365
|
-
|
|
365
|
+
execFile2(
|
|
366
366
|
"powershell",
|
|
367
367
|
["-Command", '(Get-ItemProperty -Path "HKCU:\\Software\\Microsoft\\Windows\\CurrentVersion\\PushNotifications" -Name ToastEnabled -ErrorAction SilentlyContinue).ToastEnabled'],
|
|
368
368
|
{ windowsHide: true },
|
|
@@ -383,7 +383,7 @@ var init_notifier = __esm({
|
|
|
383
383
|
logger.warn("Windows notifications are disabled. Opening notification settings...");
|
|
384
384
|
logger.warn("Please enable notifications for this app, then try again.");
|
|
385
385
|
if (process.platform === "win32") {
|
|
386
|
-
|
|
386
|
+
execFile2("powershell", ["-Command", "Start-Process ms-settings:notifications"], { windowsHide: true });
|
|
387
387
|
}
|
|
388
388
|
setTimeout(() => {
|
|
389
389
|
this.notificationSettingsOpened = false;
|
|
@@ -445,7 +445,7 @@ import { randomUUID as randomUUID2 } from "crypto";
|
|
|
445
445
|
function visibleLength(html) {
|
|
446
446
|
return html.replace(/<[^>]*>/g, "").replace(/&(?:amp|lt|gt);/g, "&").length;
|
|
447
447
|
}
|
|
448
|
-
var TELEGRAM_API, MAX_CHOICE_MESSAGES, MAX_SELECTIONS, MAX_VISIBLE_CHARS, TRUNCATED, MAX_PHOTO_BYTES, TelegramBot;
|
|
448
|
+
var TELEGRAM_API, MAX_CHOICE_MESSAGES, MAX_SELECTIONS, MAX_VISIBLE_CHARS, TRUNCATED, MAX_PHOTO_BYTES, NO_LONGER_CONNECTED, TelegramBot;
|
|
449
449
|
var init_telegram = __esm({
|
|
450
450
|
"src/hub/telegram.ts"() {
|
|
451
451
|
"use strict";
|
|
@@ -459,6 +459,7 @@ var init_telegram = __esm({
|
|
|
459
459
|
MAX_VISIBLE_CHARS = 4e3;
|
|
460
460
|
TRUNCATED = "\u2026(truncated)";
|
|
461
461
|
MAX_PHOTO_BYTES = 10 * 1024 * 1024;
|
|
462
|
+
NO_LONGER_CONNECTED = "the session is no longer connected";
|
|
462
463
|
TelegramBot = class _TelegramBot {
|
|
463
464
|
config;
|
|
464
465
|
offset = 0;
|
|
@@ -629,13 +630,7 @@ ${TRUNCATED}`);
|
|
|
629
630
|
this.selections.delete(latest);
|
|
630
631
|
const session = this.pendingSession(pending, parseInt(selectMatch[1], 10) - 1);
|
|
631
632
|
if (session) {
|
|
632
|
-
|
|
633
|
-
if (pending.photoFileId) {
|
|
634
|
-
delivered = await this.deliverPhotoToSessionByFileId(session.id, pending.photoFileId, pending.caption);
|
|
635
|
-
} else if (pending.text) {
|
|
636
|
-
this.deliverToSession(session.id, pending.text);
|
|
637
|
-
}
|
|
638
|
-
if (delivered) this.sendMessage(`Sent to [${this.getLabel(session)}]`);
|
|
633
|
+
if (await this.deliverPending(session.id, pending)) this.sendMessage(`Sent to [${this.getLabel(session)}]`);
|
|
639
634
|
} else {
|
|
640
635
|
this.sendMessage("Invalid session number.");
|
|
641
636
|
}
|
|
@@ -677,9 +672,13 @@ ${TRUNCATED}`);
|
|
|
677
672
|
this.sendMessage("Multiple sessions active. Select one:", void 0, { inline_keyboard: rows });
|
|
678
673
|
}
|
|
679
674
|
deliverToSession(sessionId2, content) {
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
675
|
+
const delivered = this.onMessageToSession?.(sessionId2, content) === true;
|
|
676
|
+
if (!delivered) void this.sendMessage(`Not delivered: ${NO_LONGER_CONNECTED}`);
|
|
677
|
+
return delivered;
|
|
678
|
+
}
|
|
679
|
+
async deliverPending(sessionId2, pending) {
|
|
680
|
+
if (pending.photoFileId) return this.deliverPhotoToSessionByFileId(sessionId2, pending.photoFileId, pending.caption);
|
|
681
|
+
return pending.text ? this.deliverToSession(sessionId2, pending.text) : false;
|
|
683
682
|
}
|
|
684
683
|
async deliverPhotoToSession(sessionId2, photos, caption) {
|
|
685
684
|
const largest = photos[photos.length - 1];
|
|
@@ -711,8 +710,19 @@ ${TRUNCATED}`);
|
|
|
711
710
|
const filePath = path6.join(UPLOADS_DIR, filename);
|
|
712
711
|
fs5.writeFileSync(filePath, buffer);
|
|
713
712
|
logger.info(`Telegram photo saved: ${filename} (${buffer.length} bytes)`);
|
|
714
|
-
|
|
715
|
-
|
|
713
|
+
let accepted = false;
|
|
714
|
+
try {
|
|
715
|
+
accepted = this.onImageToSession?.(sessionId2, filePath, mimeType, caption) === true;
|
|
716
|
+
} catch (err) {
|
|
717
|
+
logger.warn(`Telegram photo hand-off failed: ${err.message}`);
|
|
718
|
+
}
|
|
719
|
+
if (!accepted) {
|
|
720
|
+
try {
|
|
721
|
+
fs5.unlinkSync(filePath);
|
|
722
|
+
} catch {
|
|
723
|
+
}
|
|
724
|
+
this.photoNotDelivered(NO_LONGER_CONNECTED);
|
|
725
|
+
return false;
|
|
716
726
|
}
|
|
717
727
|
setTimeout(() => {
|
|
718
728
|
try {
|
|
@@ -720,7 +730,7 @@ ${TRUNCATED}`);
|
|
|
720
730
|
} catch {
|
|
721
731
|
}
|
|
722
732
|
}, 5 * 60 * 1e3).unref();
|
|
723
|
-
return
|
|
733
|
+
return true;
|
|
724
734
|
} catch (err) {
|
|
725
735
|
logger.warn(`Telegram photo download failed: ${err.message}`);
|
|
726
736
|
this.photoNotDelivered("the download failed");
|
|
@@ -915,15 +925,10 @@ ${label}`);
|
|
|
915
925
|
return;
|
|
916
926
|
}
|
|
917
927
|
this.selections.delete(selectionId);
|
|
918
|
-
if (pending
|
|
919
|
-
|
|
920
|
-
if (
|
|
921
|
-
|
|
922
|
-
if (query.message) await this.removeButtons(query.message.chat.id, query.message.message_id);
|
|
923
|
-
return;
|
|
924
|
-
}
|
|
925
|
-
} else if (pending.text) {
|
|
926
|
-
this.deliverToSession(session.id, pending.text);
|
|
928
|
+
if (!await this.deliverPending(session.id, pending)) {
|
|
929
|
+
await this.answerCallbackQuery(query.id, pending.photoFileId ? "Photo not delivered" : "Not delivered");
|
|
930
|
+
if (query.message) await this.removeButtons(query.message.chat.id, query.message.message_id);
|
|
931
|
+
return;
|
|
927
932
|
}
|
|
928
933
|
await this.answerCallbackQuery(query.id, `Sent to ${this.getLabel(session)}`);
|
|
929
934
|
if (query.message) {
|
|
@@ -1624,7 +1629,16 @@ var init_server = __esm({
|
|
|
1624
1629
|
this.sessions.updateActivity(msg.sessionId);
|
|
1625
1630
|
const notifySession = this.sessions.get(msg.sessionId);
|
|
1626
1631
|
const notifyLabel = this.getSessionLabel(notifySession);
|
|
1627
|
-
|
|
1632
|
+
const notifyTitle = `[${notifyLabel}] ${msg.title}`;
|
|
1633
|
+
if (msg.to === "api") {
|
|
1634
|
+
logger.info(`${notifyTitle}: ${msg.message}`);
|
|
1635
|
+
break;
|
|
1636
|
+
}
|
|
1637
|
+
if (msg.to === "telegram") {
|
|
1638
|
+
void this.telegramBot?.sendNotification(msg.sessionId, notifyLabel, notifyTitle, msg.message);
|
|
1639
|
+
break;
|
|
1640
|
+
}
|
|
1641
|
+
if (msg.to !== "dashboard") this.notifier.notifyWithSession(msg.sessionId, notifyLabel, notifyTitle, msg.message, msg.level ?? "info");
|
|
1628
1642
|
this.broadcastToDashboards({
|
|
1629
1643
|
type: "notification",
|
|
1630
1644
|
sessionId: msg.sessionId,
|
|
@@ -1826,6 +1840,11 @@ var init_server = __esm({
|
|
|
1826
1840
|
const channelWs = this.channelSockets.get(msg.sessionId);
|
|
1827
1841
|
if (channelWs?.readyState === WebSocket2.OPEN) {
|
|
1828
1842
|
channelWs.send(JSON.stringify({ ...msg, source: "dashboard" }));
|
|
1843
|
+
} else {
|
|
1844
|
+
const reason = "the session is not connected";
|
|
1845
|
+
logger.warn(`Message rejected for ${msg.sessionId}: ${reason}`);
|
|
1846
|
+
const rejected = { type: "message_rejected", sessionId: msg.sessionId, reason };
|
|
1847
|
+
if (ws.readyState === WebSocket2.OPEN) ws.send(JSON.stringify(rejected));
|
|
1829
1848
|
}
|
|
1830
1849
|
} else if (msg.type === "image_upload") {
|
|
1831
1850
|
this.handleImageUpload(ws, msg);
|
|
@@ -1951,19 +1970,25 @@ var init_server = __esm({
|
|
|
1951
1970
|
this.telegramBot.getSessions = () => this.sessions.getAll();
|
|
1952
1971
|
this.telegramBot.onMessageToSession = (sessionId2, content) => {
|
|
1953
1972
|
const channelWs = this.channelSockets.get(sessionId2);
|
|
1954
|
-
if (channelWs?.readyState
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
logger.info(`Telegram message forwarded to session: ${sessionId2}`);
|
|
1973
|
+
if (channelWs?.readyState !== WebSocket2.OPEN) {
|
|
1974
|
+
logger.warn(`Telegram message not delivered to ${sessionId2}: the session is not connected`);
|
|
1975
|
+
return false;
|
|
1958
1976
|
}
|
|
1977
|
+
const msg = { type: "message_to_session", sessionId: sessionId2, content, source: "telegram" };
|
|
1978
|
+
channelWs.send(JSON.stringify(msg));
|
|
1979
|
+
logger.info(`Telegram message forwarded to session: ${sessionId2}`);
|
|
1980
|
+
return true;
|
|
1959
1981
|
};
|
|
1960
1982
|
this.telegramBot.onImageToSession = (sessionId2, imagePath, mimeType, caption) => {
|
|
1961
1983
|
const channelWs = this.channelSockets.get(sessionId2);
|
|
1962
|
-
if (channelWs?.readyState
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
logger.info(`Telegram photo forwarded to session: ${sessionId2}`);
|
|
1984
|
+
if (channelWs?.readyState !== WebSocket2.OPEN) {
|
|
1985
|
+
logger.warn(`Telegram photo not delivered to ${sessionId2}: the session is not connected`);
|
|
1986
|
+
return false;
|
|
1966
1987
|
}
|
|
1988
|
+
const msg = { type: "image_to_session", sessionId: sessionId2, imagePath, mimeType, content: caption, source: "telegram" };
|
|
1989
|
+
channelWs.send(JSON.stringify(msg));
|
|
1990
|
+
logger.info(`Telegram photo forwarded to session: ${sessionId2}`);
|
|
1991
|
+
return true;
|
|
1967
1992
|
};
|
|
1968
1993
|
this.telegramBot.onPermissionVerdict = (sessionId2, requestId, behavior) => {
|
|
1969
1994
|
if (this.forwardPermissionResponse({ sessionId: sessionId2, requestId, behavior })) {
|
|
@@ -2627,7 +2652,7 @@ import { fileURLToPath as fileURLToPath2 } from "url";
|
|
|
2627
2652
|
|
|
2628
2653
|
// src/codex/transport.ts
|
|
2629
2654
|
init_logger();
|
|
2630
|
-
import { spawn } from "child_process";
|
|
2655
|
+
import { execFile, spawn } from "child_process";
|
|
2631
2656
|
import fs2 from "fs";
|
|
2632
2657
|
import path3 from "path";
|
|
2633
2658
|
import { Duplex } from "stream";
|
|
@@ -2657,14 +2682,116 @@ function findCodex(command, platform = process.platform, env = process.env) {
|
|
|
2657
2682
|
];
|
|
2658
2683
|
return candidates.find((file) => !!file && fs2.existsSync(file));
|
|
2659
2684
|
}
|
|
2685
|
+
var shellSpawns = /* @__PURE__ */ new WeakSet();
|
|
2686
|
+
var spawnedThroughShell = (child) => shellSpawns.has(child);
|
|
2660
2687
|
var defaultSpawn = (command, args) => {
|
|
2661
2688
|
const { file, shell } = resolveCommand(command);
|
|
2662
|
-
if (shell) return spawn(
|
|
2663
|
-
|
|
2689
|
+
if (!shell) return spawn(file, args, { stdio: "pipe", windowsHide: true });
|
|
2690
|
+
const child = spawn(`"${file}" ${args.join(" ")}`, { stdio: "pipe", windowsHide: true, shell: true });
|
|
2691
|
+
shellSpawns.add(child);
|
|
2692
|
+
return child;
|
|
2664
2693
|
};
|
|
2694
|
+
var queryProcesses = () => new Promise((resolve, reject) => {
|
|
2695
|
+
const script = "@(Get-CimInstance Win32_Process | ForEach-Object { [pscustomobject]@{ pid = [int]$_.ProcessId; parentPid = [int]$_.ParentProcessId; creationTime = $_.CreationDate.ToUniversalTime().ToString('o') } }) | ConvertTo-Json -Compress";
|
|
2696
|
+
execFile("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", script], { windowsHide: true, timeout: 5e3, maxBuffer: 4 * 1024 * 1024 }, (err, stdout) => {
|
|
2697
|
+
if (err) {
|
|
2698
|
+
reject(err);
|
|
2699
|
+
return;
|
|
2700
|
+
}
|
|
2701
|
+
try {
|
|
2702
|
+
const rows = JSON.parse(stdout);
|
|
2703
|
+
if (!Array.isArray(rows) || rows.some((row) => !Number.isInteger(row.pid) || !Number.isInteger(row.parentPid) || typeof row.creationTime !== "string")) {
|
|
2704
|
+
throw new Error("invalid process snapshot");
|
|
2705
|
+
}
|
|
2706
|
+
resolve(rows);
|
|
2707
|
+
} catch (error) {
|
|
2708
|
+
reject(error);
|
|
2709
|
+
}
|
|
2710
|
+
});
|
|
2711
|
+
});
|
|
2712
|
+
var runFile = (file, args, options, callback) => {
|
|
2713
|
+
execFile(file, args, options, (err) => callback(err));
|
|
2714
|
+
};
|
|
2715
|
+
function descendantsOf(rootPid, rows) {
|
|
2716
|
+
const root = rows.find((row) => row.pid === rootPid);
|
|
2717
|
+
if (!root) return void 0;
|
|
2718
|
+
const found = [];
|
|
2719
|
+
const seen = /* @__PURE__ */ new Set([root.pid]);
|
|
2720
|
+
let level = [root];
|
|
2721
|
+
for (let depth = 1; level.length; depth++) {
|
|
2722
|
+
const next = [];
|
|
2723
|
+
for (const parent of level) {
|
|
2724
|
+
for (const row of rows) {
|
|
2725
|
+
if (row.parentPid !== parent.pid || seen.has(row.pid) || row.creationTime < parent.creationTime) continue;
|
|
2726
|
+
seen.add(row.pid);
|
|
2727
|
+
next.push(row);
|
|
2728
|
+
found.push({ ...row, depth });
|
|
2729
|
+
}
|
|
2730
|
+
}
|
|
2731
|
+
level = next;
|
|
2732
|
+
}
|
|
2733
|
+
return found;
|
|
2734
|
+
}
|
|
2735
|
+
var exited = (child) => child.exitCode !== null || child.signalCode !== null;
|
|
2736
|
+
function treeKiller(platform = process.platform, run = runFile, query = queryProcesses, throughShell = spawnedThroughShell) {
|
|
2737
|
+
const recorded = /* @__PURE__ */ new WeakMap();
|
|
2738
|
+
const stop = (pid) => new Promise((resolve) => {
|
|
2739
|
+
run("taskkill", ["/PID", String(pid), "/F"], { windowsHide: true }, (err) => {
|
|
2740
|
+
if (err) logger.debug(`taskkill ${pid} failed: ${err.message}`);
|
|
2741
|
+
resolve();
|
|
2742
|
+
});
|
|
2743
|
+
});
|
|
2744
|
+
const stopDeepestFirst = async (descendants) => {
|
|
2745
|
+
for (const descendant of [...descendants].sort((a, b) => b.depth - a.depth)) await stop(descendant.pid);
|
|
2746
|
+
};
|
|
2747
|
+
const snapshot = async () => {
|
|
2748
|
+
try {
|
|
2749
|
+
return await query();
|
|
2750
|
+
} catch (err) {
|
|
2751
|
+
logger.debug(`codex process query failed: ${String(err)}`);
|
|
2752
|
+
return void 0;
|
|
2753
|
+
}
|
|
2754
|
+
};
|
|
2755
|
+
const isShellTree = (child) => platform === "win32" && child.pid !== void 0 && throughShell(child);
|
|
2756
|
+
const killer = async (child) => {
|
|
2757
|
+
if (!isShellTree(child)) {
|
|
2758
|
+
if (!exited(child)) child.kill();
|
|
2759
|
+
return;
|
|
2760
|
+
}
|
|
2761
|
+
if (!exited(child)) {
|
|
2762
|
+
const rows = await snapshot();
|
|
2763
|
+
if (!exited(child)) {
|
|
2764
|
+
const descendants2 = rows && descendantsOf(child.pid, rows);
|
|
2765
|
+
if (descendants2) await stopDeepestFirst(descendants2);
|
|
2766
|
+
child.kill();
|
|
2767
|
+
return;
|
|
2768
|
+
}
|
|
2769
|
+
}
|
|
2770
|
+
const descendants = await recorded.get(child) ?? [];
|
|
2771
|
+
if (!descendants.length) return;
|
|
2772
|
+
const current = await snapshot();
|
|
2773
|
+
if (!current) return;
|
|
2774
|
+
await stopDeepestFirst(descendants.filter((d) => current.some((row) => row.pid === d.pid && row.creationTime === d.creationTime)));
|
|
2775
|
+
};
|
|
2776
|
+
killer.track = async (child) => {
|
|
2777
|
+
if (!isShellTree(child) || exited(child)) return;
|
|
2778
|
+
const earlier = recorded.get(child);
|
|
2779
|
+
const latest = (async () => {
|
|
2780
|
+
const rows = await snapshot();
|
|
2781
|
+
const found = rows && !exited(child) ? descendantsOf(child.pid, rows) ?? [] : [];
|
|
2782
|
+
const before = await earlier ?? [];
|
|
2783
|
+
return [...before, ...found.filter((d) => !before.some((b) => b.pid === d.pid && b.creationTime === d.creationTime))];
|
|
2784
|
+
})();
|
|
2785
|
+
recorded.set(child, latest);
|
|
2786
|
+
await latest;
|
|
2787
|
+
};
|
|
2788
|
+
return killer;
|
|
2789
|
+
}
|
|
2790
|
+
var killTree = treeKiller();
|
|
2665
2791
|
var HANDSHAKE_TIMEOUT_MS = 1e4;
|
|
2666
|
-
function connectProxy(command, spawnFn = defaultSpawn, timeoutMs = HANDSHAKE_TIMEOUT_MS) {
|
|
2792
|
+
function connectProxy(command, spawnFn = defaultSpawn, timeoutMs = HANDSHAKE_TIMEOUT_MS, killTreeFn = killTree) {
|
|
2667
2793
|
const child = spawnFn(command, ["app-server", "proxy"]);
|
|
2794
|
+
void killTreeFn.track?.(child);
|
|
2668
2795
|
child.stdin?.on("error", () => {
|
|
2669
2796
|
});
|
|
2670
2797
|
child.stderr?.on("data", (d) => logger.debug(`codex proxy: ${String(d).trim()}`));
|
|
@@ -2691,10 +2818,12 @@ function connectProxy(command, spawnFn = defaultSpawn, timeoutMs = HANDSHAKE_TIM
|
|
|
2691
2818
|
const ws = new WebSocket("ws://localhost/", {
|
|
2692
2819
|
createConnection: (() => stream)
|
|
2693
2820
|
});
|
|
2694
|
-
|
|
2821
|
+
let closing;
|
|
2822
|
+
const close = () => closing ??= (async () => {
|
|
2695
2823
|
ws.terminate();
|
|
2696
|
-
child.
|
|
2697
|
-
|
|
2824
|
+
child.stdin?.end();
|
|
2825
|
+
await killTreeFn(child);
|
|
2826
|
+
})();
|
|
2698
2827
|
return new Promise((resolve, reject) => {
|
|
2699
2828
|
let settled = false;
|
|
2700
2829
|
const timer = setTimeout(() => fail(new Error(`codex daemon did not answer within ${timeoutMs / 1e3}s`)), timeoutMs);
|
|
@@ -2702,8 +2831,7 @@ function connectProxy(command, spawnFn = defaultSpawn, timeoutMs = HANDSHAKE_TIM
|
|
|
2702
2831
|
if (settled) return;
|
|
2703
2832
|
settled = true;
|
|
2704
2833
|
clearTimeout(timer);
|
|
2705
|
-
close();
|
|
2706
|
-
reject(err);
|
|
2834
|
+
void close().then(() => reject(err), () => reject(err));
|
|
2707
2835
|
};
|
|
2708
2836
|
child.on("error", fail);
|
|
2709
2837
|
child.once("exit", (code) => fail(new Error(`codex proxy exited (code ${code})`)));
|
|
@@ -2714,6 +2842,7 @@ function connectProxy(command, spawnFn = defaultSpawn, timeoutMs = HANDSHAKE_TIM
|
|
|
2714
2842
|
clearTimeout(timer);
|
|
2715
2843
|
child.on("error", (err) => logger.warn(`codex proxy error: ${err.message}`));
|
|
2716
2844
|
ws.on("error", (err) => logger.warn(`codex daemon socket error: ${err.message}`));
|
|
2845
|
+
void killTreeFn.track?.(child);
|
|
2717
2846
|
resolve({ ws, close });
|
|
2718
2847
|
});
|
|
2719
2848
|
});
|
|
@@ -3005,7 +3134,7 @@ async function runCodexTask(opts) {
|
|
|
3005
3134
|
};
|
|
3006
3135
|
} finally {
|
|
3007
3136
|
for (const t of timers) clearTimeout(t);
|
|
3008
|
-
conn.close();
|
|
3137
|
+
await conn.close();
|
|
3009
3138
|
}
|
|
3010
3139
|
}
|
|
3011
3140
|
var VALUE_FLAGS = {
|
|
@@ -3496,19 +3625,19 @@ async function hubStart(daemon) {
|
|
|
3496
3625
|
process.exit(1);
|
|
3497
3626
|
}
|
|
3498
3627
|
fs9.writeFileSync(PID_FILE, String(pid), "utf-8");
|
|
3499
|
-
let
|
|
3628
|
+
let exited2 = false;
|
|
3500
3629
|
child.once("exit", () => {
|
|
3501
|
-
|
|
3630
|
+
exited2 = true;
|
|
3502
3631
|
});
|
|
3503
3632
|
child.unref();
|
|
3504
3633
|
const startup = await waitForHub({
|
|
3505
3634
|
url: `http://${displayHost}:${port}/api/status`,
|
|
3506
3635
|
token: config2.hub.token,
|
|
3507
3636
|
pid,
|
|
3508
|
-
isAlive: () => !
|
|
3637
|
+
isAlive: () => !exited2
|
|
3509
3638
|
});
|
|
3510
3639
|
if (startup !== "ready") {
|
|
3511
|
-
if (!
|
|
3640
|
+
if (!exited2) child.kill();
|
|
3512
3641
|
if (fs9.existsSync(PID_FILE)) fs9.unlinkSync(PID_FILE);
|
|
3513
3642
|
console.error(startup === "exited" ? `Hub exited during startup. See ${LOG_FILE}` : `Hub did not answer at http://${displayHost}:${port} within ${HUB_START_TIMEOUT_MS / 1e3}s and was stopped. See ${LOG_FILE}`);
|
|
3514
3643
|
process.exit(1);
|