@delt/claude-alarm 0.8.1 → 0.9.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 +14 -0
- package/dist/channel/server.js +69 -5
- package/dist/channel/server.js.map +1 -1
- package/dist/cli.js +176 -38
- package/dist/cli.js.map +1 -1
- package/dist/dashboard/index.html +279 -26
- package/dist/hub/server.js +77 -9
- package/dist/hub/server.js.map +1 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.js +81 -11
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
- package/src/dashboard/index.html +279 -26
package/dist/index.js
CHANGED
|
@@ -41,6 +41,12 @@ var WS_PATH_DASHBOARD = "/ws/dashboard";
|
|
|
41
41
|
var CHANNEL_SERVER_NAME = "claude-alarm";
|
|
42
42
|
var CHANNEL_SERVER_VERSION = "0.1.0";
|
|
43
43
|
|
|
44
|
+
// src/shared/peer-name.ts
|
|
45
|
+
var SAFE_PEER_NAME = /^[^\u0000-\u001f\u007f"\\[\]]{1,128}$/;
|
|
46
|
+
function isValidPeerName(name) {
|
|
47
|
+
return typeof name === "string" && name.trim() !== "" && SAFE_PEER_NAME.test(name);
|
|
48
|
+
}
|
|
49
|
+
|
|
44
50
|
// src/hub/session-manager.ts
|
|
45
51
|
var SessionManager = class {
|
|
46
52
|
sessions = /* @__PURE__ */ new Map();
|
|
@@ -64,7 +70,7 @@ var SessionManager = class {
|
|
|
64
70
|
} else {
|
|
65
71
|
session.displayName = baseName;
|
|
66
72
|
}
|
|
67
|
-
this.sessions.set(session.id, { ...session });
|
|
73
|
+
this.sessions.set(session.id, { ...session, peerName: isValidPeerName(session.peerName) ? session.peerName : void 0 });
|
|
68
74
|
}
|
|
69
75
|
unregister(sessionId) {
|
|
70
76
|
const session = this.sessions.get(sessionId);
|
|
@@ -79,6 +85,13 @@ var SessionManager = class {
|
|
|
79
85
|
}
|
|
80
86
|
return session;
|
|
81
87
|
}
|
|
88
|
+
setPeerName(sessionId, peerName) {
|
|
89
|
+
const session = this.sessions.get(sessionId);
|
|
90
|
+
if (session) {
|
|
91
|
+
session.peerName = isValidPeerName(peerName) ? peerName : void 0;
|
|
92
|
+
}
|
|
93
|
+
return session;
|
|
94
|
+
}
|
|
82
95
|
updateActivity(sessionId) {
|
|
83
96
|
const session = this.sessions.get(sessionId);
|
|
84
97
|
if (session) {
|
|
@@ -210,7 +223,7 @@ import fs from "fs";
|
|
|
210
223
|
import path2 from "path";
|
|
211
224
|
import { randomUUID } from "crypto";
|
|
212
225
|
var TELEGRAM_API = "https://api.telegram.org/bot";
|
|
213
|
-
var TelegramBot = class {
|
|
226
|
+
var TelegramBot = class _TelegramBot {
|
|
214
227
|
config;
|
|
215
228
|
offset = 0;
|
|
216
229
|
polling = false;
|
|
@@ -442,33 +455,45 @@ ${this.mdToHtml(message)}`;
|
|
|
442
455
|
}
|
|
443
456
|
/** Send a permission request with inline buttons */
|
|
444
457
|
async sendPermissionRequest(sessionId, sessionLabel, requestId, toolName, description, inputPreview) {
|
|
458
|
+
const isNotify = toolName.endsWith("__notify") || toolName === "notify";
|
|
445
459
|
let preview = inputPreview;
|
|
460
|
+
let kind = "code";
|
|
461
|
+
let lang = "";
|
|
446
462
|
let truncated = false;
|
|
447
463
|
try {
|
|
448
464
|
const p = JSON.parse(inputPreview);
|
|
449
|
-
if (p.command)
|
|
450
|
-
|
|
451
|
-
|
|
465
|
+
if (p.command) {
|
|
466
|
+
preview = `$ ${p.command}`;
|
|
467
|
+
lang = "bash";
|
|
468
|
+
} else if (p.title && p.message) {
|
|
469
|
+
preview = p.message;
|
|
470
|
+
kind = "prose";
|
|
471
|
+
} else if (p.file_path) {
|
|
452
472
|
preview = p.file_path;
|
|
473
|
+
lang = this.langOf(p.file_path);
|
|
453
474
|
if (p.content) {
|
|
454
475
|
preview += "\n" + p.content.slice(0, 3e3);
|
|
455
476
|
if (p.content.length > 500) truncated = true;
|
|
456
477
|
}
|
|
457
478
|
} else if (p.content && typeof p.content === "string") {
|
|
458
479
|
preview = p.content.slice(0, 3e3);
|
|
480
|
+
if (isNotify) kind = "prose";
|
|
459
481
|
if (p.content.length > 500) truncated = true;
|
|
460
482
|
}
|
|
461
483
|
} catch {
|
|
462
484
|
truncated = true;
|
|
463
485
|
const cmdMatch = inputPreview.match(/"command"\s*:\s*"((?:[^"\\]|\\.)*)"/);
|
|
464
486
|
const contentMatch = inputPreview.match(/"content"\s*:\s*"((?:[^"\\]|\\.)*)"/);
|
|
465
|
-
if (cmdMatch)
|
|
466
|
-
|
|
487
|
+
if (cmdMatch) {
|
|
488
|
+
preview = `$ ${cmdMatch[1]}`;
|
|
489
|
+
lang = "bash";
|
|
490
|
+
} else if (contentMatch) preview = contentMatch[1].slice(0, 3e3);
|
|
467
491
|
}
|
|
468
492
|
const truncNote = truncated ? "\n\n<i>...truncated</i>" : "";
|
|
469
493
|
const previewSlice = preview.slice(0, 3e3);
|
|
470
494
|
const isShort = !previewSlice.includes("\n") && previewSlice.length < 100;
|
|
471
|
-
const
|
|
495
|
+
const langAttr = lang ? ` class="language-${lang}"` : "";
|
|
496
|
+
const previewHtml = kind === "prose" ? this.mdToHtml(previewSlice) : isShort ? `<code>${this.escHtml(previewSlice)}</code>` : `<pre><code${langAttr}>${this.escHtml(previewSlice)}</code></pre>`;
|
|
472
497
|
let displayTool = toolName;
|
|
473
498
|
if ((toolName.endsWith("__notify") || toolName === "notify") && inputPreview) {
|
|
474
499
|
try {
|
|
@@ -568,6 +593,40 @@ ${label}`);
|
|
|
568
593
|
escHtml(s) {
|
|
569
594
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
570
595
|
}
|
|
596
|
+
static LANG_BY_EXT = {
|
|
597
|
+
js: "javascript",
|
|
598
|
+
mjs: "javascript",
|
|
599
|
+
cjs: "javascript",
|
|
600
|
+
jsx: "javascript",
|
|
601
|
+
ts: "typescript",
|
|
602
|
+
tsx: "typescript",
|
|
603
|
+
py: "python",
|
|
604
|
+
rb: "ruby",
|
|
605
|
+
go: "go",
|
|
606
|
+
java: "java",
|
|
607
|
+
kt: "kotlin",
|
|
608
|
+
rs: "rust",
|
|
609
|
+
php: "php",
|
|
610
|
+
cs: "csharp",
|
|
611
|
+
sh: "bash",
|
|
612
|
+
bash: "bash",
|
|
613
|
+
zsh: "bash",
|
|
614
|
+
ps1: "powershell",
|
|
615
|
+
json: "json",
|
|
616
|
+
yml: "yaml",
|
|
617
|
+
yaml: "yaml",
|
|
618
|
+
xml: "xml",
|
|
619
|
+
sql: "sql",
|
|
620
|
+
md: "markdown",
|
|
621
|
+
html: "html",
|
|
622
|
+
vue: "html",
|
|
623
|
+
css: "css",
|
|
624
|
+
scss: "scss"
|
|
625
|
+
};
|
|
626
|
+
langOf(path5) {
|
|
627
|
+
const m = /\.([a-z0-9]+)$/i.exec(path5 || "");
|
|
628
|
+
return m ? _TelegramBot.LANG_BY_EXT[m[1].toLowerCase()] ?? "" : "";
|
|
629
|
+
}
|
|
571
630
|
/** Convert markdown to Telegram HTML (escape first, then apply formatting) */
|
|
572
631
|
mdToHtml(s) {
|
|
573
632
|
let text = s.replace(
|
|
@@ -1019,7 +1078,7 @@ var HubServer = class {
|
|
|
1019
1078
|
this.sessions.register(session);
|
|
1020
1079
|
this.channelSockets.set(session.id, ws);
|
|
1021
1080
|
if (isLocal) this.localChannels.add(session.id);
|
|
1022
|
-
logger.info(`Session registered: ${session.id} (${session.name}, channel: ${session.channelEnabled ?? false})`);
|
|
1081
|
+
logger.info(`Session registered: ${session.id} (${session.name}, channel: ${session.channelEnabled ?? false}, peer: ${session.peerName ?? "-"})`);
|
|
1023
1082
|
this.broadcastToDashboards({
|
|
1024
1083
|
type: isReregister ? "session_updated" : "session_connected",
|
|
1025
1084
|
session
|
|
@@ -1033,6 +1092,15 @@ var HubServer = class {
|
|
|
1033
1092
|
}
|
|
1034
1093
|
break;
|
|
1035
1094
|
}
|
|
1095
|
+
case "peer_name": {
|
|
1096
|
+
if (this.channelSockets.get(msg.sessionId) !== ws) break;
|
|
1097
|
+
const updated = this.sessions.setPeerName(msg.sessionId, msg.peerName);
|
|
1098
|
+
if (updated) {
|
|
1099
|
+
logger.info(`Peer name for ${msg.sessionId}: ${msg.peerName ?? "-"}`);
|
|
1100
|
+
this.broadcastToDashboards({ type: "session_updated", session: updated });
|
|
1101
|
+
}
|
|
1102
|
+
break;
|
|
1103
|
+
}
|
|
1036
1104
|
case "notify": {
|
|
1037
1105
|
this.sessions.updateActivity(msg.sessionId);
|
|
1038
1106
|
const notifySession = this.sessions.get(msg.sessionId);
|
|
@@ -1399,12 +1467,13 @@ if (process.argv[1] && (process.argv[1].endsWith("hub/server.js") || process.arg
|
|
|
1399
1467
|
// src/channel/hub-client.ts
|
|
1400
1468
|
import WebSocket2 from "ws";
|
|
1401
1469
|
var HubClient = class {
|
|
1402
|
-
constructor(sessionId, sessionName, hubHost = DEFAULT_HUB_HOST, hubPort = DEFAULT_HUB_PORT, token) {
|
|
1470
|
+
constructor(sessionId, sessionName, hubHost = DEFAULT_HUB_HOST, hubPort = DEFAULT_HUB_PORT, token, getPeerName = () => void 0) {
|
|
1403
1471
|
this.sessionId = sessionId;
|
|
1404
1472
|
this.sessionName = sessionName;
|
|
1405
1473
|
this.hubHost = hubHost;
|
|
1406
1474
|
this.hubPort = hubPort;
|
|
1407
1475
|
this.token = token;
|
|
1476
|
+
this.getPeerName = getPeerName;
|
|
1408
1477
|
}
|
|
1409
1478
|
ws = null;
|
|
1410
1479
|
reconnectTimer = null;
|
|
@@ -1429,7 +1498,8 @@ var HubClient = class {
|
|
|
1429
1498
|
connectedAt: Date.now(),
|
|
1430
1499
|
lastActivity: Date.now(),
|
|
1431
1500
|
cwd: process.cwd(),
|
|
1432
|
-
channelEnabled: true
|
|
1501
|
+
channelEnabled: true,
|
|
1502
|
+
peerName: this.getPeerName()
|
|
1433
1503
|
}
|
|
1434
1504
|
};
|
|
1435
1505
|
this.ws.send(JSON.stringify(registration));
|