@delt/claude-alarm 1.0.0 → 1.0.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/README.md +7 -1
- package/dist/channel/server.js.map +1 -1
- package/dist/cli.js +115 -87
- package/dist/cli.js.map +1 -1
- package/dist/codex/main.js +7 -3
- package/dist/codex/main.js.map +1 -1
- package/dist/hub/server.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -75,6 +75,9 @@ function setCodexEnabled(enabled) {
|
|
|
75
75
|
saveConfig(config2);
|
|
76
76
|
return config2;
|
|
77
77
|
}
|
|
78
|
+
function shouldOfferCodex(config2, installed) {
|
|
79
|
+
return installed && config2.codex === void 0;
|
|
80
|
+
}
|
|
78
81
|
function setupMcpConfig(targetDir) {
|
|
79
82
|
const dir = targetDir ?? process.cwd();
|
|
80
83
|
const mcpPath = path2.join(dir, ".mcp.json");
|
|
@@ -143,11 +146,11 @@ var init_logger = __esm({
|
|
|
143
146
|
});
|
|
144
147
|
|
|
145
148
|
// src/shared/crash-guard.ts
|
|
146
|
-
import
|
|
149
|
+
import fs3 from "fs";
|
|
147
150
|
function appendToLog(text) {
|
|
148
151
|
try {
|
|
149
|
-
|
|
150
|
-
|
|
152
|
+
fs3.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
153
|
+
fs3.appendFileSync(LOG_FILE, text, "utf-8");
|
|
151
154
|
} catch {
|
|
152
155
|
}
|
|
153
156
|
}
|
|
@@ -410,8 +413,8 @@ var init_session_label = __esm({
|
|
|
410
413
|
});
|
|
411
414
|
|
|
412
415
|
// src/hub/telegram.ts
|
|
413
|
-
import
|
|
414
|
-
import
|
|
416
|
+
import fs4 from "fs";
|
|
417
|
+
import path4 from "path";
|
|
415
418
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
416
419
|
var TELEGRAM_API, TelegramBot;
|
|
417
420
|
var init_telegram = __esm({
|
|
@@ -630,17 +633,17 @@ ${this.mdToHtml(message)}`;
|
|
|
630
633
|
const buffer = Buffer.from(await imgRes.arrayBuffer());
|
|
631
634
|
const ext = fileData.result.file_path.split(".").pop() || "jpg";
|
|
632
635
|
const mimeType = ext === "png" ? "image/png" : ext === "gif" ? "image/gif" : ext === "webp" ? "image/webp" : "image/jpeg";
|
|
633
|
-
|
|
636
|
+
fs4.mkdirSync(UPLOADS_DIR, { recursive: true });
|
|
634
637
|
const filename = `${randomUUID2()}.${ext}`;
|
|
635
|
-
const filePath =
|
|
636
|
-
|
|
638
|
+
const filePath = path4.join(UPLOADS_DIR, filename);
|
|
639
|
+
fs4.writeFileSync(filePath, buffer);
|
|
637
640
|
logger.info(`Telegram photo saved: ${filename} (${buffer.length} bytes)`);
|
|
638
641
|
if (this.onImageToSession) {
|
|
639
642
|
this.onImageToSession(sessionId2, filePath, mimeType, caption);
|
|
640
643
|
}
|
|
641
644
|
setTimeout(() => {
|
|
642
645
|
try {
|
|
643
|
-
|
|
646
|
+
fs4.unlinkSync(filePath);
|
|
644
647
|
} catch {
|
|
645
648
|
}
|
|
646
649
|
}, 5 * 60 * 1e3);
|
|
@@ -823,8 +826,8 @@ ${label}`);
|
|
|
823
826
|
css: "css",
|
|
824
827
|
scss: "scss"
|
|
825
828
|
};
|
|
826
|
-
langOf(
|
|
827
|
-
const m = /\.([a-z0-9]+)$/i.exec(
|
|
829
|
+
langOf(path10) {
|
|
830
|
+
const m = /\.([a-z0-9]+)$/i.exec(path10 || "");
|
|
828
831
|
return m ? _TelegramBot.LANG_BY_EXT[m[1].toLowerCase()] ?? "" : "";
|
|
829
832
|
}
|
|
830
833
|
/** Convert markdown to Telegram HTML (escape first, then apply formatting) */
|
|
@@ -870,11 +873,11 @@ ${bodyLines.join("\n")}`;
|
|
|
870
873
|
});
|
|
871
874
|
|
|
872
875
|
// src/hub/codex-supervisor.ts
|
|
873
|
-
import { spawn } from "child_process";
|
|
874
|
-
import
|
|
875
|
-
import
|
|
876
|
+
import { spawn as spawn2 } from "child_process";
|
|
877
|
+
import fs5 from "fs";
|
|
878
|
+
import path5 from "path";
|
|
876
879
|
function resolveAdapterScript(baseDir) {
|
|
877
|
-
return [
|
|
880
|
+
return [path5.join(baseDir, "..", "codex", "main.js"), path5.join(baseDir, "codex", "main.js")].find((p) => fs5.existsSync(p));
|
|
878
881
|
}
|
|
879
882
|
var HEALTHY_RUN_MS, CodexSupervisor;
|
|
880
883
|
var init_codex_supervisor = __esm({
|
|
@@ -883,7 +886,7 @@ var init_codex_supervisor = __esm({
|
|
|
883
886
|
init_logger();
|
|
884
887
|
HEALTHY_RUN_MS = 6e4;
|
|
885
888
|
CodexSupervisor = class {
|
|
886
|
-
constructor(script, spawnFn =
|
|
889
|
+
constructor(script, spawnFn = spawn2, minDelayMs = 2e3, maxDelayMs = 6e4, stopGraceMs = 3e3) {
|
|
887
890
|
this.script = script;
|
|
888
891
|
this.spawnFn = spawnFn;
|
|
889
892
|
this.minDelayMs = minDelayMs;
|
|
@@ -1009,10 +1012,10 @@ __export(server_exports, {
|
|
|
1009
1012
|
HubServer: () => HubServer
|
|
1010
1013
|
});
|
|
1011
1014
|
import http from "http";
|
|
1012
|
-
import
|
|
1013
|
-
import
|
|
1015
|
+
import fs6 from "fs";
|
|
1016
|
+
import path6 from "path";
|
|
1014
1017
|
import { fileURLToPath } from "url";
|
|
1015
|
-
import { WebSocketServer, WebSocket } from "ws";
|
|
1018
|
+
import { WebSocketServer, WebSocket as WebSocket2 } from "ws";
|
|
1016
1019
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
1017
1020
|
var __dirname, MAX_WS_PAYLOAD, HubServer;
|
|
1018
1021
|
var init_server = __esm({
|
|
@@ -1028,7 +1031,7 @@ var init_server = __esm({
|
|
|
1028
1031
|
init_session_label();
|
|
1029
1032
|
init_crash_guard();
|
|
1030
1033
|
init_auth();
|
|
1031
|
-
__dirname =
|
|
1034
|
+
__dirname = path6.dirname(fileURLToPath(import.meta.url));
|
|
1032
1035
|
MAX_WS_PAYLOAD = 16 * 1024 * 1024;
|
|
1033
1036
|
HubServer = class {
|
|
1034
1037
|
httpServer;
|
|
@@ -1224,23 +1227,23 @@ var init_server = __esm({
|
|
|
1224
1227
|
return;
|
|
1225
1228
|
}
|
|
1226
1229
|
const candidates = [
|
|
1227
|
-
|
|
1230
|
+
path6.join(__dirname, "..", "dashboard", "index.html"),
|
|
1228
1231
|
// from dist/hub/
|
|
1229
|
-
|
|
1232
|
+
path6.join(__dirname, "dashboard", "index.html"),
|
|
1230
1233
|
// from dist/ (bundled index.js)
|
|
1231
|
-
|
|
1234
|
+
path6.join(__dirname, "..", "..", "src", "dashboard", "index.html"),
|
|
1232
1235
|
// from dist/hub/ -> src/
|
|
1233
|
-
|
|
1236
|
+
path6.join(__dirname, "..", "src", "dashboard", "index.html"),
|
|
1234
1237
|
// from dist/ -> src/
|
|
1235
|
-
|
|
1238
|
+
path6.join(process.cwd(), "dist", "dashboard", "index.html"),
|
|
1236
1239
|
// from cwd
|
|
1237
|
-
|
|
1240
|
+
path6.join(process.cwd(), "src", "dashboard", "index.html")
|
|
1238
1241
|
// from cwd/src
|
|
1239
1242
|
];
|
|
1240
1243
|
logger.debug(`Dashboard candidates: ${JSON.stringify(candidates)}`);
|
|
1241
1244
|
for (const candidate of candidates) {
|
|
1242
|
-
if (
|
|
1243
|
-
const html =
|
|
1245
|
+
if (fs6.existsSync(candidate)) {
|
|
1246
|
+
const html = fs6.readFileSync(candidate, "utf-8");
|
|
1244
1247
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
1245
1248
|
res.end(html);
|
|
1246
1249
|
return;
|
|
@@ -1275,7 +1278,7 @@ var init_server = __esm({
|
|
|
1275
1278
|
return;
|
|
1276
1279
|
}
|
|
1277
1280
|
const ws = this.channelSockets.get(sessionId2);
|
|
1278
|
-
if (!ws || ws.readyState !==
|
|
1281
|
+
if (!ws || ws.readyState !== WebSocket2.OPEN) {
|
|
1279
1282
|
this.jsonResponse(res, 404, { error: "Session not connected" });
|
|
1280
1283
|
return;
|
|
1281
1284
|
}
|
|
@@ -1452,14 +1455,14 @@ var init_server = __esm({
|
|
|
1452
1455
|
const msg = JSON.parse(data.toString());
|
|
1453
1456
|
if (msg.type === "message_to_session") {
|
|
1454
1457
|
const channelWs = this.channelSockets.get(msg.sessionId);
|
|
1455
|
-
if (channelWs?.readyState ===
|
|
1458
|
+
if (channelWs?.readyState === WebSocket2.OPEN) {
|
|
1456
1459
|
channelWs.send(JSON.stringify({ ...msg, source: "dashboard" }));
|
|
1457
1460
|
}
|
|
1458
1461
|
} else if (msg.type === "image_upload") {
|
|
1459
1462
|
this.handleImageUpload(msg);
|
|
1460
1463
|
} else if (msg.type === "permission_response") {
|
|
1461
1464
|
const channelWs = this.channelSockets.get(msg.sessionId);
|
|
1462
|
-
if (channelWs?.readyState ===
|
|
1465
|
+
if (channelWs?.readyState === WebSocket2.OPEN) {
|
|
1463
1466
|
channelWs.send(JSON.stringify(msg));
|
|
1464
1467
|
logger.info(`Permission verdict [${msg.requestId}]: ${msg.behavior} -> session ${msg.sessionId}`);
|
|
1465
1468
|
}
|
|
@@ -1477,7 +1480,7 @@ var init_server = __esm({
|
|
|
1477
1480
|
broadcastToDashboards(msg) {
|
|
1478
1481
|
const payload = JSON.stringify(msg);
|
|
1479
1482
|
for (const ws of this.dashboardSockets) {
|
|
1480
|
-
if (ws.readyState ===
|
|
1483
|
+
if (ws.readyState === WebSocket2.OPEN) {
|
|
1481
1484
|
ws.send(payload);
|
|
1482
1485
|
}
|
|
1483
1486
|
}
|
|
@@ -1489,7 +1492,7 @@ var init_server = __esm({
|
|
|
1489
1492
|
return;
|
|
1490
1493
|
}
|
|
1491
1494
|
const channelWs = this.channelSockets.get(sessionId2);
|
|
1492
|
-
if (!channelWs || channelWs.readyState !==
|
|
1495
|
+
if (!channelWs || channelWs.readyState !== WebSocket2.OPEN) return;
|
|
1493
1496
|
const allowedTypes = ["image/png", "image/jpeg", "image/gif", "image/webp"];
|
|
1494
1497
|
if (!allowedTypes.includes(mimeType)) return;
|
|
1495
1498
|
const base64Data = imageData.replace(/^data:image\/\w+;base64,/, "");
|
|
@@ -1498,11 +1501,11 @@ var init_server = __esm({
|
|
|
1498
1501
|
logger.warn("Image upload rejected: exceeds 10MB");
|
|
1499
1502
|
return;
|
|
1500
1503
|
}
|
|
1501
|
-
|
|
1504
|
+
fs6.mkdirSync(UPLOADS_DIR, { recursive: true });
|
|
1502
1505
|
const ext = mimeType.split("/")[1] === "jpeg" ? "jpg" : mimeType.split("/")[1];
|
|
1503
1506
|
const filename = `${randomUUID3()}.${ext}`;
|
|
1504
|
-
const filePath =
|
|
1505
|
-
|
|
1507
|
+
const filePath = path6.join(UPLOADS_DIR, filename);
|
|
1508
|
+
fs6.writeFileSync(filePath, buffer);
|
|
1506
1509
|
const forwardMsg = {
|
|
1507
1510
|
type: "image_to_session",
|
|
1508
1511
|
sessionId: sessionId2,
|
|
@@ -1515,7 +1518,7 @@ var init_server = __esm({
|
|
|
1515
1518
|
logger.info(`Image saved and forwarded: ${filename} (${buffer.length} bytes)`);
|
|
1516
1519
|
setTimeout(() => {
|
|
1517
1520
|
try {
|
|
1518
|
-
|
|
1521
|
+
fs6.unlinkSync(filePath);
|
|
1519
1522
|
} catch {
|
|
1520
1523
|
}
|
|
1521
1524
|
}, 5 * 60 * 1e3);
|
|
@@ -1542,7 +1545,7 @@ var init_server = __esm({
|
|
|
1542
1545
|
this.telegramBot.getSessions = () => this.sessions.getAll();
|
|
1543
1546
|
this.telegramBot.onMessageToSession = (sessionId2, content) => {
|
|
1544
1547
|
const channelWs = this.channelSockets.get(sessionId2);
|
|
1545
|
-
if (channelWs?.readyState ===
|
|
1548
|
+
if (channelWs?.readyState === WebSocket2.OPEN) {
|
|
1546
1549
|
const msg = { type: "message_to_session", sessionId: sessionId2, content, source: "telegram" };
|
|
1547
1550
|
channelWs.send(JSON.stringify(msg));
|
|
1548
1551
|
logger.info(`Telegram message forwarded to session: ${sessionId2}`);
|
|
@@ -1550,7 +1553,7 @@ var init_server = __esm({
|
|
|
1550
1553
|
};
|
|
1551
1554
|
this.telegramBot.onImageToSession = (sessionId2, imagePath, mimeType, caption) => {
|
|
1552
1555
|
const channelWs = this.channelSockets.get(sessionId2);
|
|
1553
|
-
if (channelWs?.readyState ===
|
|
1556
|
+
if (channelWs?.readyState === WebSocket2.OPEN) {
|
|
1554
1557
|
const msg = { type: "image_to_session", sessionId: sessionId2, imagePath, mimeType, content: caption };
|
|
1555
1558
|
channelWs.send(JSON.stringify(msg));
|
|
1556
1559
|
logger.info(`Telegram photo forwarded to session: ${sessionId2}`);
|
|
@@ -1558,7 +1561,7 @@ var init_server = __esm({
|
|
|
1558
1561
|
};
|
|
1559
1562
|
this.telegramBot.onPermissionVerdict = (sessionId2, requestId, behavior) => {
|
|
1560
1563
|
const channelWs = this.channelSockets.get(sessionId2);
|
|
1561
|
-
if (channelWs?.readyState ===
|
|
1564
|
+
if (channelWs?.readyState === WebSocket2.OPEN) {
|
|
1562
1565
|
const msg = { type: "permission_response", sessionId: sessionId2, requestId, behavior };
|
|
1563
1566
|
channelWs.send(JSON.stringify(msg));
|
|
1564
1567
|
logger.info(`Telegram permission verdict [${requestId}]: ${behavior} -> session ${sessionId2}`);
|
|
@@ -1696,11 +1699,11 @@ var init_server = __esm({
|
|
|
1696
1699
|
}
|
|
1697
1700
|
cleanupUploads() {
|
|
1698
1701
|
try {
|
|
1699
|
-
if (!
|
|
1700
|
-
const files =
|
|
1702
|
+
if (!fs6.existsSync(UPLOADS_DIR)) return;
|
|
1703
|
+
const files = fs6.readdirSync(UPLOADS_DIR);
|
|
1701
1704
|
for (const file of files) {
|
|
1702
1705
|
try {
|
|
1703
|
-
|
|
1706
|
+
fs6.unlinkSync(path6.join(UPLOADS_DIR, file));
|
|
1704
1707
|
} catch {
|
|
1705
1708
|
}
|
|
1706
1709
|
}
|
|
@@ -1773,7 +1776,7 @@ Content-Length: 0\r
|
|
|
1773
1776
|
});
|
|
1774
1777
|
|
|
1775
1778
|
// src/channel/hub-client.ts
|
|
1776
|
-
import
|
|
1779
|
+
import WebSocket3 from "ws";
|
|
1777
1780
|
var HubClient;
|
|
1778
1781
|
var init_hub_client = __esm({
|
|
1779
1782
|
"src/channel/hub-client.ts"() {
|
|
@@ -1802,7 +1805,7 @@ var init_hub_client = __esm({
|
|
|
1802
1805
|
const url = `ws://${this.hubHost}:${this.hubPort}${WS_PATH_CHANNEL}${tokenQuery}`;
|
|
1803
1806
|
logger.debug(`Connecting to hub at ${url}`);
|
|
1804
1807
|
try {
|
|
1805
|
-
const ws = new
|
|
1808
|
+
const ws = new WebSocket3(url);
|
|
1806
1809
|
this.ws = ws;
|
|
1807
1810
|
ws.on("open", () => {
|
|
1808
1811
|
if (this.ws !== ws) return;
|
|
@@ -1842,7 +1845,7 @@ var init_hub_client = __esm({
|
|
|
1842
1845
|
}
|
|
1843
1846
|
}
|
|
1844
1847
|
send(msg) {
|
|
1845
|
-
if (this.connected && this.ws?.readyState ===
|
|
1848
|
+
if (this.connected && this.ws?.readyState === WebSocket3.OPEN) {
|
|
1846
1849
|
this.ws.send(JSON.stringify(msg));
|
|
1847
1850
|
} else {
|
|
1848
1851
|
if (this.queue.length < 100) {
|
|
@@ -1867,7 +1870,7 @@ var init_hub_client = __esm({
|
|
|
1867
1870
|
this.connected = false;
|
|
1868
1871
|
}
|
|
1869
1872
|
reregister() {
|
|
1870
|
-
if (this.connected && this.ws?.readyState ===
|
|
1873
|
+
if (this.connected && this.ws?.readyState === WebSocket3.OPEN) {
|
|
1871
1874
|
this.ws.send(JSON.stringify(this.registration()));
|
|
1872
1875
|
}
|
|
1873
1876
|
}
|
|
@@ -1899,9 +1902,9 @@ var init_hub_client = __esm({
|
|
|
1899
1902
|
});
|
|
1900
1903
|
|
|
1901
1904
|
// src/channel/peer-name.ts
|
|
1902
|
-
import
|
|
1905
|
+
import fs7 from "fs";
|
|
1903
1906
|
import os2 from "os";
|
|
1904
|
-
import
|
|
1907
|
+
import path7 from "path";
|
|
1905
1908
|
function findPeerName(records, env) {
|
|
1906
1909
|
const valid = records.filter((r) => typeof r === "object" && r !== null);
|
|
1907
1910
|
const nameOf = (match) => {
|
|
@@ -1921,18 +1924,18 @@ function readPeerName(env = process.env) {
|
|
|
1921
1924
|
sessionId: env.CLAUDE_CODE_SESSION_ID
|
|
1922
1925
|
};
|
|
1923
1926
|
if (!lookup.messagingSocket && !lookup.sessionId) return void 0;
|
|
1924
|
-
const configDir = env.CLAUDE_CONFIG_DIR ||
|
|
1925
|
-
const dir =
|
|
1927
|
+
const configDir = env.CLAUDE_CONFIG_DIR || path7.join(os2.homedir(), ".claude");
|
|
1928
|
+
const dir = path7.join(configDir, "sessions");
|
|
1926
1929
|
let files;
|
|
1927
1930
|
try {
|
|
1928
|
-
files =
|
|
1931
|
+
files = fs7.readdirSync(dir).filter((f) => f.endsWith(".json"));
|
|
1929
1932
|
} catch {
|
|
1930
1933
|
return void 0;
|
|
1931
1934
|
}
|
|
1932
1935
|
const records = [];
|
|
1933
1936
|
for (const f of files) {
|
|
1934
1937
|
try {
|
|
1935
|
-
records.push(JSON.parse(
|
|
1938
|
+
records.push(JSON.parse(fs7.readFileSync(path7.join(dir, f), "utf8")));
|
|
1936
1939
|
} catch {
|
|
1937
1940
|
}
|
|
1938
1941
|
}
|
|
@@ -1955,7 +1958,7 @@ import {
|
|
|
1955
1958
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
1956
1959
|
import { z } from "zod";
|
|
1957
1960
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
1958
|
-
import
|
|
1961
|
+
import path8 from "path";
|
|
1959
1962
|
async function main() {
|
|
1960
1963
|
logger.info(`Starting MCP channel server (session: ${sessionId})`);
|
|
1961
1964
|
hubClient.connect();
|
|
@@ -2024,7 +2027,7 @@ var init_server2 = __esm({
|
|
|
2024
2027
|
init_hub_client();
|
|
2025
2028
|
init_peer_name2();
|
|
2026
2029
|
sessionId = randomUUID4();
|
|
2027
|
-
sessionName = process.env.CLAUDE_ALARM_SESSION_NAME ??
|
|
2030
|
+
sessionName = process.env.CLAUDE_ALARM_SESSION_NAME ?? path8.basename(process.cwd());
|
|
2028
2031
|
peerName = readPeerName();
|
|
2029
2032
|
server = new Server(
|
|
2030
2033
|
{
|
|
@@ -2200,15 +2203,35 @@ NOTIFICATIONS:
|
|
|
2200
2203
|
|
|
2201
2204
|
// src/cli.ts
|
|
2202
2205
|
init_config();
|
|
2206
|
+
import { spawn as spawn3 } from "child_process";
|
|
2207
|
+
import fs8 from "fs";
|
|
2208
|
+
import path9 from "path";
|
|
2209
|
+
import readline from "readline";
|
|
2210
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2211
|
+
|
|
2212
|
+
// src/codex/transport.ts
|
|
2213
|
+
init_logger();
|
|
2214
|
+
import { spawn } from "child_process";
|
|
2215
|
+
import fs2 from "fs";
|
|
2216
|
+
import path3 from "path";
|
|
2217
|
+
import { Duplex } from "stream";
|
|
2218
|
+
import WebSocket from "ws";
|
|
2219
|
+
function findOnPath(command, platform = process.platform, env = process.env) {
|
|
2220
|
+
const dirs = (env.PATH ?? env.Path ?? "").split(path3.delimiter).filter(Boolean);
|
|
2221
|
+
for (const ext of platform === "win32" ? [".exe", ".cmd"] : [""]) {
|
|
2222
|
+
for (const dir of dirs) {
|
|
2223
|
+
const file = path3.join(dir, command + ext);
|
|
2224
|
+
if (fs2.existsSync(file)) return file;
|
|
2225
|
+
}
|
|
2226
|
+
}
|
|
2227
|
+
return void 0;
|
|
2228
|
+
}
|
|
2229
|
+
|
|
2230
|
+
// src/cli.ts
|
|
2203
2231
|
init_constants();
|
|
2204
2232
|
init_logger();
|
|
2205
2233
|
init_crash_guard();
|
|
2206
|
-
|
|
2207
|
-
import fs7 from "fs";
|
|
2208
|
-
import path8 from "path";
|
|
2209
|
-
import readline from "readline";
|
|
2210
|
-
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2211
|
-
var __dirname2 = path8.dirname(fileURLToPath2(import.meta.url));
|
|
2234
|
+
var __dirname2 = path9.dirname(fileURLToPath2(import.meta.url));
|
|
2212
2235
|
function authHeaders(token) {
|
|
2213
2236
|
return token ? { Authorization: `Bearer ${token}` } : {};
|
|
2214
2237
|
}
|
|
@@ -2240,8 +2263,8 @@ Quick start:
|
|
|
2240
2263
|
}
|
|
2241
2264
|
async function checkForUpdates() {
|
|
2242
2265
|
try {
|
|
2243
|
-
const pkgPath =
|
|
2244
|
-
const pkg = JSON.parse(
|
|
2266
|
+
const pkgPath = path9.join(__dirname2, "..", "package.json");
|
|
2267
|
+
const pkg = JSON.parse(fs8.readFileSync(pkgPath, "utf-8"));
|
|
2245
2268
|
const currentVersion = pkg.version;
|
|
2246
2269
|
const res = await fetch("https://registry.npmjs.org/@delt/claude-alarm/latest", {
|
|
2247
2270
|
signal: AbortSignal.timeout(3e3)
|
|
@@ -2264,25 +2287,25 @@ async function hubStart(daemon) {
|
|
|
2264
2287
|
const port = config2.hub.port ?? DEFAULT_HUB_PORT;
|
|
2265
2288
|
const displayHost = host === "0.0.0.0" ? "127.0.0.1" : host;
|
|
2266
2289
|
checkForUpdates();
|
|
2267
|
-
if (
|
|
2268
|
-
const pid = parseInt(
|
|
2290
|
+
if (fs8.existsSync(PID_FILE)) {
|
|
2291
|
+
const pid = parseInt(fs8.readFileSync(PID_FILE, "utf-8").trim(), 10);
|
|
2269
2292
|
if (isProcessRunning(pid)) {
|
|
2270
2293
|
console.log(`Hub is already running (PID: ${pid}). Dashboard: ${loginLink(displayHost, port, config2.hub.token)}`);
|
|
2271
2294
|
return;
|
|
2272
2295
|
}
|
|
2273
|
-
|
|
2296
|
+
fs8.unlinkSync(PID_FILE);
|
|
2274
2297
|
}
|
|
2275
2298
|
if (daemon) {
|
|
2276
2299
|
ensureConfigDir();
|
|
2277
|
-
const logFd =
|
|
2278
|
-
const hubScript =
|
|
2279
|
-
const child =
|
|
2300
|
+
const logFd = fs8.openSync(LOG_FILE, "a");
|
|
2301
|
+
const hubScript = path9.join(__dirname2, "hub", "server.js");
|
|
2302
|
+
const child = spawn3(process.execPath, [hubScript], {
|
|
2280
2303
|
detached: true,
|
|
2281
2304
|
stdio: ["ignore", logFd, logFd],
|
|
2282
2305
|
env: { ...process.env }
|
|
2283
2306
|
});
|
|
2284
2307
|
if (child.pid) {
|
|
2285
|
-
|
|
2308
|
+
fs8.writeFileSync(PID_FILE, String(child.pid), "utf-8");
|
|
2286
2309
|
child.unref();
|
|
2287
2310
|
console.log(`Hub started as daemon (PID: ${child.pid})`);
|
|
2288
2311
|
console.log(`Dashboard: ${loginLink(displayHost, port, config2.hub.token)}`);
|
|
@@ -2303,11 +2326,11 @@ async function hubStart(daemon) {
|
|
|
2303
2326
|
const hub = new HubServer2(config2);
|
|
2304
2327
|
await hub.start();
|
|
2305
2328
|
ensureConfigDir();
|
|
2306
|
-
|
|
2329
|
+
fs8.writeFileSync(PID_FILE, String(process.pid), "utf-8");
|
|
2307
2330
|
const shutdown = async () => {
|
|
2308
2331
|
console.log("\nShutting down...");
|
|
2309
2332
|
await hub.stop();
|
|
2310
|
-
if (
|
|
2333
|
+
if (fs8.existsSync(PID_FILE)) fs8.unlinkSync(PID_FILE);
|
|
2311
2334
|
process.exit(0);
|
|
2312
2335
|
};
|
|
2313
2336
|
process.on("SIGINT", shutdown);
|
|
@@ -2315,18 +2338,18 @@ async function hubStart(daemon) {
|
|
|
2315
2338
|
}
|
|
2316
2339
|
}
|
|
2317
2340
|
function hubStop() {
|
|
2318
|
-
if (!
|
|
2341
|
+
if (!fs8.existsSync(PID_FILE)) {
|
|
2319
2342
|
console.log("Hub is not running (no PID file found)");
|
|
2320
2343
|
return;
|
|
2321
2344
|
}
|
|
2322
|
-
const pid = parseInt(
|
|
2345
|
+
const pid = parseInt(fs8.readFileSync(PID_FILE, "utf-8").trim(), 10);
|
|
2323
2346
|
try {
|
|
2324
2347
|
process.kill(pid, "SIGTERM");
|
|
2325
2348
|
console.log(`Hub stopped (PID: ${pid})`);
|
|
2326
2349
|
} catch {
|
|
2327
2350
|
console.log("Hub process not found (may have already stopped)");
|
|
2328
2351
|
}
|
|
2329
|
-
|
|
2352
|
+
fs8.unlinkSync(PID_FILE);
|
|
2330
2353
|
}
|
|
2331
2354
|
async function hubStatus() {
|
|
2332
2355
|
const config2 = loadConfig();
|
|
@@ -2334,8 +2357,8 @@ async function hubStatus() {
|
|
|
2334
2357
|
const port = config2.hub.port ?? DEFAULT_HUB_PORT;
|
|
2335
2358
|
const displayHost = host === "0.0.0.0" ? "127.0.0.1" : host;
|
|
2336
2359
|
let pidInfo = "not running";
|
|
2337
|
-
if (
|
|
2338
|
-
const pid = parseInt(
|
|
2360
|
+
if (fs8.existsSync(PID_FILE)) {
|
|
2361
|
+
const pid = parseInt(fs8.readFileSync(PID_FILE, "utf-8").trim(), 10);
|
|
2339
2362
|
if (isProcessRunning(pid)) {
|
|
2340
2363
|
pidInfo = `running (PID: ${pid})`;
|
|
2341
2364
|
} else {
|
|
@@ -2407,7 +2430,7 @@ function ask(question) {
|
|
|
2407
2430
|
}
|
|
2408
2431
|
async function init() {
|
|
2409
2432
|
const dir = process.cwd();
|
|
2410
|
-
const projectName =
|
|
2433
|
+
const projectName = path9.basename(dir);
|
|
2411
2434
|
console.log(`
|
|
2412
2435
|
claude-alarm init for "${projectName}"
|
|
2413
2436
|
`);
|
|
@@ -2427,11 +2450,11 @@ claude-alarm init for "${projectName}"
|
|
|
2427
2450
|
if (port) env.CLAUDE_ALARM_HUB_PORT = port;
|
|
2428
2451
|
if (token) env.CLAUDE_ALARM_HUB_TOKEN = token;
|
|
2429
2452
|
}
|
|
2430
|
-
const mcpPath =
|
|
2453
|
+
const mcpPath = path9.join(dir, ".mcp.json");
|
|
2431
2454
|
let mcpConfig = {};
|
|
2432
|
-
if (
|
|
2455
|
+
if (fs8.existsSync(mcpPath)) {
|
|
2433
2456
|
try {
|
|
2434
|
-
mcpConfig = JSON.parse(
|
|
2457
|
+
mcpConfig = JSON.parse(fs8.readFileSync(mcpPath, "utf-8"));
|
|
2435
2458
|
} catch {
|
|
2436
2459
|
mcpConfig = {};
|
|
2437
2460
|
}
|
|
@@ -2442,7 +2465,7 @@ claude-alarm init for "${projectName}"
|
|
|
2442
2465
|
args: ["-y", "@delt/claude-alarm", "serve"],
|
|
2443
2466
|
env
|
|
2444
2467
|
};
|
|
2445
|
-
|
|
2468
|
+
fs8.writeFileSync(mcpPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
|
|
2446
2469
|
console.log(`
|
|
2447
2470
|
\u2713 Created ${mcpPath}`);
|
|
2448
2471
|
if (remote.toLowerCase() !== "y") {
|
|
@@ -2463,6 +2486,11 @@ claude-alarm init for "${projectName}"
|
|
|
2463
2486
|
console.log(` claude-alarm hub start`);
|
|
2464
2487
|
}
|
|
2465
2488
|
console.log(` Dashboard: http://${displayHost}:${port}`);
|
|
2489
|
+
if (shouldOfferCodex(config2, findOnPath("codex") !== void 0)) {
|
|
2490
|
+
const answer = await ask("\nCodex is installed. Show Codex conversations on the dashboard too? (y/N): ");
|
|
2491
|
+
if (answer.toLowerCase() === "y") codexEnable(true);
|
|
2492
|
+
else setCodexEnabled(false);
|
|
2493
|
+
}
|
|
2466
2494
|
}
|
|
2467
2495
|
console.log(`
|
|
2468
2496
|
Next step:`);
|
|
@@ -2488,8 +2516,8 @@ function isProcessRunning(pid) {
|
|
|
2488
2516
|
}
|
|
2489
2517
|
}
|
|
2490
2518
|
function readCodexPid() {
|
|
2491
|
-
if (!
|
|
2492
|
-
const pid = parseInt(
|
|
2519
|
+
if (!fs8.existsSync(CODEX_PID_FILE)) return void 0;
|
|
2520
|
+
const pid = parseInt(fs8.readFileSync(CODEX_PID_FILE, "utf-8").trim(), 10);
|
|
2493
2521
|
return Number.isNaN(pid) ? void 0 : pid;
|
|
2494
2522
|
}
|
|
2495
2523
|
function codexEnable(enabled) {
|
|
@@ -2503,8 +2531,8 @@ function codexStart() {
|
|
|
2503
2531
|
return;
|
|
2504
2532
|
}
|
|
2505
2533
|
ensureConfigDir();
|
|
2506
|
-
const logFd =
|
|
2507
|
-
const child =
|
|
2534
|
+
const logFd = fs8.openSync(CODEX_LOG_FILE, "a");
|
|
2535
|
+
const child = spawn3(process.execPath, [path9.join(__dirname2, "codex", "main.js")], {
|
|
2508
2536
|
detached: true,
|
|
2509
2537
|
stdio: ["ignore", logFd, logFd],
|
|
2510
2538
|
env: { ...process.env }
|
|
@@ -2525,7 +2553,7 @@ function codexStop() {
|
|
|
2525
2553
|
console.log("Codex adapter process not found (may have already stopped)");
|
|
2526
2554
|
}
|
|
2527
2555
|
try {
|
|
2528
|
-
|
|
2556
|
+
fs8.unlinkSync(CODEX_PID_FILE);
|
|
2529
2557
|
} catch {
|
|
2530
2558
|
}
|
|
2531
2559
|
}
|