@delt/claude-alarm 1.1.1 → 1.2.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/README.md +17 -10
- package/dist/channel/server.js.map +1 -1
- package/dist/cli.js +906 -67
- package/dist/cli.js.map +1 -1
- package/dist/codex/main.js +380 -63
- package/dist/codex/main.js.map +1 -1
- package/dist/dashboard/index.html +162 -1
- package/dist/hub/server.js +165 -8
- package/dist/hub/server.js.map +1 -1
- package/dist/index.d.ts +60 -2
- package/dist/index.js +166 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/dashboard/index.html +162 -1
package/dist/index.d.ts
CHANGED
|
@@ -29,6 +29,7 @@ interface SessionInfo {
|
|
|
29
29
|
peerName?: string;
|
|
30
30
|
agentKind?: AgentKind;
|
|
31
31
|
title?: string;
|
|
32
|
+
closable?: boolean;
|
|
32
33
|
}
|
|
33
34
|
/** Messages sent between channel server and hub */
|
|
34
35
|
type ChannelMessage = {
|
|
@@ -71,6 +72,7 @@ type ChannelMessage = {
|
|
|
71
72
|
mimeType: string;
|
|
72
73
|
originalName?: string;
|
|
73
74
|
content?: string;
|
|
75
|
+
source?: MessageSource;
|
|
74
76
|
} | {
|
|
75
77
|
type: 'sessions_list';
|
|
76
78
|
sessions: SessionInfo[];
|
|
@@ -118,10 +120,51 @@ type ChannelMessage = {
|
|
|
118
120
|
} | {
|
|
119
121
|
type: 'permission_pending';
|
|
120
122
|
requests: PendingChoiceRequest[];
|
|
123
|
+
} | {
|
|
124
|
+
type: 'codex_adapters';
|
|
125
|
+
adapters: CodexAdapterInfo[];
|
|
126
|
+
} | {
|
|
127
|
+
type: 'codex_close';
|
|
128
|
+
sessionId: string;
|
|
121
129
|
} | {
|
|
122
130
|
type: 'error';
|
|
123
131
|
message: string;
|
|
124
132
|
};
|
|
133
|
+
interface CodexAdapterInfo {
|
|
134
|
+
id: string;
|
|
135
|
+
host: string;
|
|
136
|
+
ready: boolean;
|
|
137
|
+
isLocal: boolean;
|
|
138
|
+
}
|
|
139
|
+
type CodexCall = {
|
|
140
|
+
kind: 'folders';
|
|
141
|
+
} | {
|
|
142
|
+
kind: 'create';
|
|
143
|
+
cwd: string;
|
|
144
|
+
};
|
|
145
|
+
/** Messages on the per-adapter socket between the Codex adapter and the hub */
|
|
146
|
+
type CodexLinkMessage = {
|
|
147
|
+
type: 'adapter_hello';
|
|
148
|
+
adapter: {
|
|
149
|
+
id: string;
|
|
150
|
+
host: string;
|
|
151
|
+
ready: boolean;
|
|
152
|
+
};
|
|
153
|
+
} | {
|
|
154
|
+
type: 'adapter_call';
|
|
155
|
+
requestId: string;
|
|
156
|
+
call: CodexCall;
|
|
157
|
+
} | {
|
|
158
|
+
type: 'adapter_result';
|
|
159
|
+
requestId: string;
|
|
160
|
+
ok: true;
|
|
161
|
+
data: unknown;
|
|
162
|
+
} | {
|
|
163
|
+
type: 'adapter_result';
|
|
164
|
+
requestId: string;
|
|
165
|
+
ok: false;
|
|
166
|
+
error: string;
|
|
167
|
+
};
|
|
125
168
|
type NotifyLevel = 'info' | 'warning' | 'error' | 'success';
|
|
126
169
|
/** Webhook configuration */
|
|
127
170
|
interface WebhookConfig {
|
|
@@ -184,7 +227,14 @@ declare class HubServer {
|
|
|
184
227
|
private token?;
|
|
185
228
|
private codexEnabled;
|
|
186
229
|
private codexSupervisor?;
|
|
187
|
-
|
|
230
|
+
private wssCodex;
|
|
231
|
+
private codexAdapters;
|
|
232
|
+
private codexAlive;
|
|
233
|
+
private codexCallTimeoutMs;
|
|
234
|
+
private codexCalls;
|
|
235
|
+
constructor(config?: Partial<AppConfig>, options?: {
|
|
236
|
+
codexCallTimeoutMs?: number;
|
|
237
|
+
});
|
|
188
238
|
start(): Promise<void>;
|
|
189
239
|
stop(): Promise<void>;
|
|
190
240
|
private handleHttp;
|
|
@@ -194,6 +244,13 @@ declare class HubServer {
|
|
|
194
244
|
private handleApiNotify;
|
|
195
245
|
private handleChannelConnection;
|
|
196
246
|
private handleChannelMessage;
|
|
247
|
+
private handleCodexConnection;
|
|
248
|
+
private callCodexAdapter;
|
|
249
|
+
private handleCodexFolders;
|
|
250
|
+
private handleCodexCreate;
|
|
251
|
+
private handleCodexClose;
|
|
252
|
+
private codexAdapterList;
|
|
253
|
+
private broadcastCodexAdapters;
|
|
197
254
|
private handleDashboardConnection;
|
|
198
255
|
private forwardPermissionResponse;
|
|
199
256
|
private resolveChoice;
|
|
@@ -355,7 +412,8 @@ declare const CODEX_PID_FILE: string;
|
|
|
355
412
|
declare const CODEX_LOG_FILE: string;
|
|
356
413
|
declare const WS_PATH_CHANNEL = "/ws/channel";
|
|
357
414
|
declare const WS_PATH_DASHBOARD = "/ws/dashboard";
|
|
415
|
+
declare const WS_PATH_CODEX = "/ws/codex";
|
|
358
416
|
declare const CHANNEL_SERVER_NAME = "claude-alarm";
|
|
359
417
|
declare const CHANNEL_SERVER_VERSION = "0.1.0";
|
|
360
418
|
|
|
361
|
-
export { type AgentKind, type AppConfig, CHANNEL_SERVER_NAME, CHANNEL_SERVER_VERSION, CODEX_LOG_FILE, CODEX_PID_FILE, CONFIG_DIR, CONFIG_FILE, type ChannelMessage, type CodexConfig, DEFAULT_HUB_HOST, DEFAULT_HUB_PORT, HubClient, HubServer, type HubStatus, LOG_FILE, type MessageSource, Notifier, type NotifyLevel, PID_FILE, type PendingChoiceRequest, type PermissionChoice, type SessionInfo, SessionManager, type SessionStatus, type TelegramConfig, UPLOADS_DIR, WS_PATH_CHANNEL, WS_PATH_DASHBOARD, type WebhookConfig, loadConfig, logger, saveConfig, setupMcpConfig };
|
|
419
|
+
export { type AgentKind, type AppConfig, CHANNEL_SERVER_NAME, CHANNEL_SERVER_VERSION, CODEX_LOG_FILE, CODEX_PID_FILE, CONFIG_DIR, CONFIG_FILE, type ChannelMessage, type CodexAdapterInfo, type CodexCall, type CodexConfig, type CodexLinkMessage, DEFAULT_HUB_HOST, DEFAULT_HUB_PORT, HubClient, HubServer, type HubStatus, LOG_FILE, type MessageSource, Notifier, type NotifyLevel, PID_FILE, type PendingChoiceRequest, type PermissionChoice, type SessionInfo, SessionManager, type SessionStatus, type TelegramConfig, UPLOADS_DIR, WS_PATH_CHANNEL, WS_PATH_CODEX, WS_PATH_DASHBOARD, type WebhookConfig, loadConfig, logger, saveConfig, setupMcpConfig };
|
package/dist/index.js
CHANGED
|
@@ -40,6 +40,7 @@ var CODEX_PID_FILE = path.join(CONFIG_DIR, "codex.pid");
|
|
|
40
40
|
var CODEX_LOG_FILE = path.join(CONFIG_DIR, "codex.log");
|
|
41
41
|
var WS_PATH_CHANNEL = "/ws/channel";
|
|
42
42
|
var WS_PATH_DASHBOARD = "/ws/dashboard";
|
|
43
|
+
var WS_PATH_CODEX = "/ws/codex";
|
|
43
44
|
var CHANNEL_SERVER_NAME = "claude-alarm";
|
|
44
45
|
var CHANNEL_SERVER_VERSION = "0.1.0";
|
|
45
46
|
|
|
@@ -175,6 +176,7 @@ var Notifier = class {
|
|
|
175
176
|
execFile(
|
|
176
177
|
"powershell",
|
|
177
178
|
["-Command", '(Get-ItemProperty -Path "HKCU:\\Software\\Microsoft\\Windows\\CurrentVersion\\PushNotifications" -Name ToastEnabled -ErrorAction SilentlyContinue).ToastEnabled'],
|
|
179
|
+
{ windowsHide: true },
|
|
178
180
|
(err, stdout) => {
|
|
179
181
|
if (err) {
|
|
180
182
|
resolve(true);
|
|
@@ -192,7 +194,7 @@ var Notifier = class {
|
|
|
192
194
|
logger.warn("Windows notifications are disabled. Opening notification settings...");
|
|
193
195
|
logger.warn("Please enable notifications for this app, then try again.");
|
|
194
196
|
if (process.platform === "win32") {
|
|
195
|
-
execFile("powershell", ["-Command", "Start-Process ms-settings:notifications"]);
|
|
197
|
+
execFile("powershell", ["-Command", "Start-Process ms-settings:notifications"], { windowsHide: true });
|
|
196
198
|
}
|
|
197
199
|
setTimeout(() => {
|
|
198
200
|
this.notificationSettingsOpened = false;
|
|
@@ -944,6 +946,21 @@ function logStartup(context) {
|
|
|
944
946
|
`);
|
|
945
947
|
}
|
|
946
948
|
|
|
949
|
+
// src/shared/entry.ts
|
|
950
|
+
function isEntryScript(argv1, suffixes) {
|
|
951
|
+
if (!argv1) return false;
|
|
952
|
+
const normalized = argv1.replace(/\\/g, "/");
|
|
953
|
+
return suffixes.some((suffix) => normalized.endsWith(suffix));
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
// src/shared/hub-url.ts
|
|
957
|
+
import net from "net";
|
|
958
|
+
function hubUrlHost(host) {
|
|
959
|
+
if (host === "" || host === "0.0.0.0") return "127.0.0.1";
|
|
960
|
+
if (host === "::") return "[::1]";
|
|
961
|
+
return net.isIPv6(host) ? `[${host}]` : host;
|
|
962
|
+
}
|
|
963
|
+
|
|
947
964
|
// src/hub/auth.ts
|
|
948
965
|
import crypto from "crypto";
|
|
949
966
|
var SESSION_COOKIE = "ca_session";
|
|
@@ -1009,6 +1026,7 @@ function validChoices(choices) {
|
|
|
1009
1026
|
const valid = choices.filter((c) => typeof c?.id === "string" && typeof c?.label === "string");
|
|
1010
1027
|
return valid.length ? valid : void 0;
|
|
1011
1028
|
}
|
|
1029
|
+
var nonEmpty = (v) => typeof v === "string" && v.trim() !== "";
|
|
1012
1030
|
var HubServer = class {
|
|
1013
1031
|
httpServer;
|
|
1014
1032
|
wssChannel;
|
|
@@ -1034,7 +1052,13 @@ var HubServer = class {
|
|
|
1034
1052
|
token;
|
|
1035
1053
|
codexEnabled;
|
|
1036
1054
|
codexSupervisor;
|
|
1037
|
-
|
|
1055
|
+
wssCodex;
|
|
1056
|
+
codexAdapters = /* @__PURE__ */ new Map();
|
|
1057
|
+
codexAlive = /* @__PURE__ */ new WeakMap();
|
|
1058
|
+
codexCallTimeoutMs;
|
|
1059
|
+
codexCalls = /* @__PURE__ */ new Map();
|
|
1060
|
+
constructor(config, options = {}) {
|
|
1061
|
+
this.codexCallTimeoutMs = options.codexCallTimeoutMs ?? 6e4;
|
|
1038
1062
|
this.host = config?.hub?.host ?? DEFAULT_HUB_HOST;
|
|
1039
1063
|
this.port = config?.hub?.port ?? DEFAULT_HUB_PORT;
|
|
1040
1064
|
this.token = config?.hub?.token;
|
|
@@ -1047,7 +1071,7 @@ var HubServer = class {
|
|
|
1047
1071
|
if (config?.webhooks) {
|
|
1048
1072
|
this.notifier.configure({ webhooks: config.webhooks });
|
|
1049
1073
|
}
|
|
1050
|
-
const displayHost = this.host
|
|
1074
|
+
const displayHost = hubUrlHost(this.host);
|
|
1051
1075
|
this.notifier.configure({ dashboardUrl: `http://${displayHost}:${this.port}` });
|
|
1052
1076
|
const fullConfig = loadConfig();
|
|
1053
1077
|
if (fullConfig.telegram?.enabled && fullConfig.telegram.botToken && fullConfig.telegram.chatId) {
|
|
@@ -1060,6 +1084,9 @@ var HubServer = class {
|
|
|
1060
1084
|
this.wssDashboard = new WebSocketServer({ noServer: true, maxPayload: MAX_WS_PAYLOAD });
|
|
1061
1085
|
this.wssDashboard.on("connection", (ws) => this.handleDashboardConnection(ws));
|
|
1062
1086
|
this.wssDashboard.on("error", (err) => logger.warn(`Dashboard WebSocket server error: ${err.message}`));
|
|
1087
|
+
this.wssCodex = new WebSocketServer({ noServer: true, maxPayload: MAX_WS_PAYLOAD });
|
|
1088
|
+
this.wssCodex.on("connection", (ws, req) => this.handleCodexConnection(ws, req));
|
|
1089
|
+
this.wssCodex.on("error", (err) => logger.warn(`Codex WebSocket server error: ${err.message}`));
|
|
1063
1090
|
this.httpServer.on("upgrade", (req, socket, head) => {
|
|
1064
1091
|
socket.on("error", (err) => logger.debug(`Upgrade socket error: ${err.message}`));
|
|
1065
1092
|
const url = new URL(req.url ?? "/", "http://hub");
|
|
@@ -1080,6 +1107,10 @@ var HubServer = class {
|
|
|
1080
1107
|
this.wssDashboard.handleUpgrade(req, socket, head, (ws) => {
|
|
1081
1108
|
this.wssDashboard.emit("connection", ws, req);
|
|
1082
1109
|
});
|
|
1110
|
+
} else if (pathname === WS_PATH_CODEX) {
|
|
1111
|
+
this.wssCodex.handleUpgrade(req, socket, head, (ws) => {
|
|
1112
|
+
this.wssCodex.emit("connection", ws, req);
|
|
1113
|
+
});
|
|
1083
1114
|
} else {
|
|
1084
1115
|
socket.destroy();
|
|
1085
1116
|
}
|
|
@@ -1094,7 +1125,7 @@ var HubServer = class {
|
|
|
1094
1125
|
this.httpServer.listen(this.port, this.host, () => {
|
|
1095
1126
|
this.httpServer.removeListener("error", onStartupError);
|
|
1096
1127
|
this.httpServer.on("error", (err) => logger.error(`HTTP server error: ${err.message}`));
|
|
1097
|
-
const displayHost = this.host
|
|
1128
|
+
const displayHost = hubUrlHost(this.host);
|
|
1098
1129
|
logger.info(`Hub server listening on http://${displayHost}:${this.port}`);
|
|
1099
1130
|
this.startCodexAdapter();
|
|
1100
1131
|
resolve();
|
|
@@ -1109,10 +1140,12 @@ var HubServer = class {
|
|
|
1109
1140
|
if (this.telegramBot) this.telegramBot.stopPolling();
|
|
1110
1141
|
for (const ws of this.channelSockets.values()) ws.terminate();
|
|
1111
1142
|
for (const ws of this.dashboardSockets) ws.terminate();
|
|
1143
|
+
for (const { ws } of this.codexAdapters.values()) ws.terminate();
|
|
1112
1144
|
this.channelSockets.clear();
|
|
1113
1145
|
this.dashboardSockets.clear();
|
|
1114
1146
|
this.wssChannel.close();
|
|
1115
1147
|
this.wssDashboard.close();
|
|
1148
|
+
this.wssCodex.close();
|
|
1116
1149
|
this.httpServer.close(() => {
|
|
1117
1150
|
logger.info("Hub server stopped");
|
|
1118
1151
|
resolve();
|
|
@@ -1177,6 +1210,12 @@ var HubServer = class {
|
|
|
1177
1210
|
this.handleApiSend(req, res);
|
|
1178
1211
|
} else if (url.pathname === "/api/notify" && req.method === "POST") {
|
|
1179
1212
|
this.handleApiNotify(req, res);
|
|
1213
|
+
} else if (url.pathname === "/api/codex/folders" && req.method === "GET") {
|
|
1214
|
+
this.handleCodexFolders(url, res);
|
|
1215
|
+
} else if (url.pathname === "/api/codex/threads" && req.method === "POST") {
|
|
1216
|
+
this.handleCodexCreate(req, res);
|
|
1217
|
+
} else if (url.pathname === "/api/codex/threads/close" && req.method === "POST") {
|
|
1218
|
+
this.handleCodexClose(req, res);
|
|
1180
1219
|
} else if (url.pathname === "/api/webhooks" && req.method === "GET") {
|
|
1181
1220
|
const config = loadConfig();
|
|
1182
1221
|
this.jsonResponse(res, 200, { webhooks: config.webhooks || [] });
|
|
@@ -1440,6 +1479,114 @@ var HubServer = class {
|
|
|
1440
1479
|
}
|
|
1441
1480
|
}
|
|
1442
1481
|
}
|
|
1482
|
+
handleCodexConnection(ws, req) {
|
|
1483
|
+
const isLocal = this.isLocalRequest(req);
|
|
1484
|
+
let adapterId;
|
|
1485
|
+
ws.on("error", (err) => {
|
|
1486
|
+
logger.warn(`Codex adapter WebSocket error: ${err.message}`);
|
|
1487
|
+
ws.terminate();
|
|
1488
|
+
});
|
|
1489
|
+
ws.on("pong", () => this.codexAlive.set(ws, true));
|
|
1490
|
+
ws.on("message", (data) => {
|
|
1491
|
+
let msg;
|
|
1492
|
+
try {
|
|
1493
|
+
msg = JSON.parse(data.toString());
|
|
1494
|
+
if (msg === null || typeof msg !== "object") {
|
|
1495
|
+
logger.warn("Invalid message from Codex adapter");
|
|
1496
|
+
return;
|
|
1497
|
+
}
|
|
1498
|
+
} catch {
|
|
1499
|
+
logger.warn("Invalid message from Codex adapter");
|
|
1500
|
+
return;
|
|
1501
|
+
}
|
|
1502
|
+
if (msg.type === "adapter_hello") {
|
|
1503
|
+
const a = msg.adapter;
|
|
1504
|
+
if (typeof a?.id !== "string" || !a.id || typeof a.host !== "string") return;
|
|
1505
|
+
if (adapterId && adapterId !== a.id) return;
|
|
1506
|
+
const holder = this.codexAdapters.get(a.id);
|
|
1507
|
+
if (holder && holder.ws !== ws) holder.ws.terminate();
|
|
1508
|
+
if (!adapterId) logger.info(`Codex adapter connected: ${a.host} (${a.id}, local: ${isLocal})`);
|
|
1509
|
+
adapterId = a.id;
|
|
1510
|
+
this.codexAdapters.set(a.id, { ws, info: { id: a.id, host: a.host, ready: a.ready === true, isLocal } });
|
|
1511
|
+
this.broadcastCodexAdapters();
|
|
1512
|
+
} else if (msg.type === "adapter_result" && adapterId) {
|
|
1513
|
+
const call = this.codexCalls.get(msg.requestId);
|
|
1514
|
+
if (!call || call.adapterId !== adapterId) return;
|
|
1515
|
+
call.settle(msg.ok ? { status: 200, body: msg.data } : { status: 422, body: { error: String(msg.error) } });
|
|
1516
|
+
}
|
|
1517
|
+
});
|
|
1518
|
+
ws.on("close", () => {
|
|
1519
|
+
if (!adapterId || this.codexAdapters.get(adapterId)?.ws !== ws) return;
|
|
1520
|
+
this.codexAdapters.delete(adapterId);
|
|
1521
|
+
for (const call of [...this.codexCalls.values()]) {
|
|
1522
|
+
if (call.adapterId === adapterId) call.settle({ status: 502, body: { error: "Codex adapter disconnected" } });
|
|
1523
|
+
}
|
|
1524
|
+
logger.info(`Codex adapter disconnected: ${adapterId}`);
|
|
1525
|
+
this.broadcastCodexAdapters();
|
|
1526
|
+
});
|
|
1527
|
+
}
|
|
1528
|
+
callCodexAdapter(adapterId, call) {
|
|
1529
|
+
const adapter = this.codexAdapters.get(adapterId);
|
|
1530
|
+
if (!adapter || adapter.ws.readyState !== WebSocket.OPEN) {
|
|
1531
|
+
return Promise.resolve({ status: 404, body: { error: "Codex adapter is not connected" } });
|
|
1532
|
+
}
|
|
1533
|
+
const requestId = randomUUID3();
|
|
1534
|
+
return new Promise((resolve) => {
|
|
1535
|
+
const timer = setTimeout(
|
|
1536
|
+
() => settle({ status: 504, body: { error: "Codex did not respond in time. The conversation may still appear." } }),
|
|
1537
|
+
this.codexCallTimeoutMs
|
|
1538
|
+
);
|
|
1539
|
+
const settle = (outcome) => {
|
|
1540
|
+
clearTimeout(timer);
|
|
1541
|
+
this.codexCalls.delete(requestId);
|
|
1542
|
+
resolve(outcome);
|
|
1543
|
+
};
|
|
1544
|
+
this.codexCalls.set(requestId, { adapterId, settle });
|
|
1545
|
+
adapter.ws.send(JSON.stringify({ type: "adapter_call", requestId, call }));
|
|
1546
|
+
});
|
|
1547
|
+
}
|
|
1548
|
+
async handleCodexFolders(url, res) {
|
|
1549
|
+
const adapterId = url.searchParams.get("adapterId");
|
|
1550
|
+
if (!nonEmpty(adapterId)) {
|
|
1551
|
+
this.jsonResponse(res, 400, { error: "adapterId is required" });
|
|
1552
|
+
return;
|
|
1553
|
+
}
|
|
1554
|
+
const out = await this.callCodexAdapter(adapterId, { kind: "folders" });
|
|
1555
|
+
this.jsonResponse(res, out.status, out.body);
|
|
1556
|
+
}
|
|
1557
|
+
async handleCodexCreate(req, res) {
|
|
1558
|
+
const body = await this.readBody(req);
|
|
1559
|
+
const adapterId = body?.adapterId;
|
|
1560
|
+
const cwd = body?.cwd;
|
|
1561
|
+
if (!nonEmpty(adapterId) || !nonEmpty(cwd)) {
|
|
1562
|
+
this.jsonResponse(res, 400, { error: "adapterId and cwd are required" });
|
|
1563
|
+
return;
|
|
1564
|
+
}
|
|
1565
|
+
const out = await this.callCodexAdapter(adapterId, { kind: "create", cwd });
|
|
1566
|
+
this.jsonResponse(res, out.status, out.body);
|
|
1567
|
+
}
|
|
1568
|
+
async handleCodexClose(req, res) {
|
|
1569
|
+
const body = await this.readBody(req);
|
|
1570
|
+
const sessionId = body?.sessionId;
|
|
1571
|
+
if (!nonEmpty(sessionId)) {
|
|
1572
|
+
this.jsonResponse(res, 400, { error: "sessionId is required" });
|
|
1573
|
+
return;
|
|
1574
|
+
}
|
|
1575
|
+
const session = this.sessions.get(sessionId);
|
|
1576
|
+
const ws = this.channelSockets.get(sessionId);
|
|
1577
|
+
if (session?.agentKind !== "codex" || !session.closable || ws?.readyState !== WebSocket.OPEN) {
|
|
1578
|
+
this.jsonResponse(res, 404, { error: "No closable Codex conversation" });
|
|
1579
|
+
return;
|
|
1580
|
+
}
|
|
1581
|
+
ws.send(JSON.stringify({ type: "codex_close", sessionId }));
|
|
1582
|
+
this.jsonResponse(res, 200, { ok: true });
|
|
1583
|
+
}
|
|
1584
|
+
codexAdapterList() {
|
|
1585
|
+
return [...this.codexAdapters.values()].map((a) => a.info);
|
|
1586
|
+
}
|
|
1587
|
+
broadcastCodexAdapters() {
|
|
1588
|
+
this.broadcastToDashboards({ type: "codex_adapters", adapters: this.codexAdapterList() });
|
|
1589
|
+
}
|
|
1443
1590
|
// --- Dashboard WebSocket ---
|
|
1444
1591
|
handleDashboardConnection(ws) {
|
|
1445
1592
|
this.dashboardSockets.add(ws);
|
|
@@ -1458,6 +1605,7 @@ var HubServer = class {
|
|
|
1458
1605
|
requests: [...this.choiceRequests.values()].map((c) => c.request)
|
|
1459
1606
|
};
|
|
1460
1607
|
ws.send(JSON.stringify(pendingMsg));
|
|
1608
|
+
ws.send(JSON.stringify({ type: "codex_adapters", adapters: this.codexAdapterList() }));
|
|
1461
1609
|
ws.on("message", (data) => {
|
|
1462
1610
|
try {
|
|
1463
1611
|
const msg = JSON.parse(data.toString());
|
|
@@ -1545,7 +1693,8 @@ var HubServer = class {
|
|
|
1545
1693
|
imagePath: filePath,
|
|
1546
1694
|
mimeType,
|
|
1547
1695
|
originalName,
|
|
1548
|
-
content
|
|
1696
|
+
content,
|
|
1697
|
+
source: "dashboard"
|
|
1549
1698
|
};
|
|
1550
1699
|
channelWs.send(JSON.stringify(forwardMsg));
|
|
1551
1700
|
logger.info(`Image saved and forwarded: ${filename} (${buffer.length} bytes)`);
|
|
@@ -1554,7 +1703,7 @@ var HubServer = class {
|
|
|
1554
1703
|
fs5.unlinkSync(filePath);
|
|
1555
1704
|
} catch {
|
|
1556
1705
|
}
|
|
1557
|
-
}, 5 * 60 * 1e3);
|
|
1706
|
+
}, 5 * 60 * 1e3).unref();
|
|
1558
1707
|
}
|
|
1559
1708
|
async handleWebhookSave(req, res) {
|
|
1560
1709
|
const body = await this.readBody(req);
|
|
@@ -1587,7 +1736,7 @@ var HubServer = class {
|
|
|
1587
1736
|
this.telegramBot.onImageToSession = (sessionId, imagePath, mimeType, caption) => {
|
|
1588
1737
|
const channelWs = this.channelSockets.get(sessionId);
|
|
1589
1738
|
if (channelWs?.readyState === WebSocket.OPEN) {
|
|
1590
|
-
const msg = { type: "image_to_session", sessionId, imagePath, mimeType, content: caption };
|
|
1739
|
+
const msg = { type: "image_to_session", sessionId, imagePath, mimeType, content: caption, source: "telegram" };
|
|
1591
1740
|
channelWs.send(JSON.stringify(msg));
|
|
1592
1741
|
logger.info(`Telegram photo forwarded to session: ${sessionId}`);
|
|
1593
1742
|
}
|
|
@@ -1730,6 +1879,14 @@ var HubServer = class {
|
|
|
1730
1879
|
this.channelAlive.set(sessionId, false);
|
|
1731
1880
|
ws.ping();
|
|
1732
1881
|
}
|
|
1882
|
+
for (const { ws } of this.codexAdapters.values()) {
|
|
1883
|
+
if (this.codexAlive.get(ws) === false) {
|
|
1884
|
+
ws.terminate();
|
|
1885
|
+
continue;
|
|
1886
|
+
}
|
|
1887
|
+
this.codexAlive.set(ws, false);
|
|
1888
|
+
ws.ping();
|
|
1889
|
+
}
|
|
1733
1890
|
}, 3e4);
|
|
1734
1891
|
}
|
|
1735
1892
|
cleanupUploads() {
|
|
@@ -1792,7 +1949,7 @@ Content-Length: 0\r
|
|
|
1792
1949
|
});
|
|
1793
1950
|
}
|
|
1794
1951
|
};
|
|
1795
|
-
if (process.argv[1]
|
|
1952
|
+
if (isEntryScript(process.argv[1], ["/hub/server.js", "/hub/server.ts"])) {
|
|
1796
1953
|
installCrashGuard("hub daemon");
|
|
1797
1954
|
logStartup("Hub daemon");
|
|
1798
1955
|
const config = loadConfig();
|
|
@@ -1942,6 +2099,7 @@ export {
|
|
|
1942
2099
|
SessionManager,
|
|
1943
2100
|
UPLOADS_DIR,
|
|
1944
2101
|
WS_PATH_CHANNEL,
|
|
2102
|
+
WS_PATH_CODEX,
|
|
1945
2103
|
WS_PATH_DASHBOARD,
|
|
1946
2104
|
loadConfig,
|
|
1947
2105
|
logger,
|