blun-king-cli 9.1.404 → 9.1.405
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/LIESMICH.txt +9 -5
- package/README.md +9 -5
- package/bin/telegram-console-status-policy.cjs +102 -0
- package/bin/telegram-remote-status-policy.cjs +47 -4
- package/blun.mjs +24 -0
- package/package.json +1 -1
- package/telegram-plugin/dist/bridge.mjs +30 -5
package/LIESMICH.txt
CHANGED
|
@@ -307,11 +307,15 @@ Rechner aus Telegram prüfen
|
|
|
307
307
|
----------------------------
|
|
308
308
|
Der Telegram-Befehl /status prüft die lokale Verbindung ohne Modellaufruf. Er
|
|
309
309
|
zeigt den Rechnernamen, die installierte BLUN-Version, die Laufzeit der
|
|
310
|
-
Telegram-Brücke, die Verbindung
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
310
|
+
Telegram-Brücke, die Verbindung und Laufzeit der Konsole, den aktuellen
|
|
311
|
+
Zustellweg, den Konsolen-Herzschlag, den letzten Warteschlangen-Fortschritt sowie
|
|
312
|
+
den aktuellen Arbeitsschritt. Die Warteschlange wird als tatsächlich ungelesener
|
|
313
|
+
Anteil und Gesamtgröße gemessen; ein Prüfpunkt wird nur für exakt dieselbe
|
|
314
|
+
Warteschlangendatei akzeptiert. Damit bleibt der Zustand auch dann abfragbar,
|
|
315
|
+
wenn die Konsole hängt oder der Modellanbieter ausgelastet ist. Die Ausgabe
|
|
316
|
+
enthält keine Chat-IDs, Dateipfade, Zugangsdaten, Nachrichteninhalte oder
|
|
317
|
+
vollständigen Aufgabenlisten. Nicht verbundene Absender erhalten weiterhin nur
|
|
318
|
+
die Kopplungsanweisung.
|
|
315
319
|
|
|
316
320
|
Nachweisbare Arbeitsabläufe
|
|
317
321
|
---------------------------
|
package/README.md
CHANGED
|
@@ -313,11 +313,15 @@ Sicherheitsgründen als normale Chatnachrichten behandelt.
|
|
|
313
313
|
|
|
314
314
|
Der Telegram-Befehl `/status` prüft die lokale Verbindung ohne Modellaufruf.
|
|
315
315
|
Er zeigt den Rechnernamen, die installierte BLUN-Version, die Laufzeit der
|
|
316
|
-
Telegram-Brücke, die Verbindung
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
316
|
+
Telegram-Brücke, die Verbindung und Laufzeit der Konsole, den aktuellen
|
|
317
|
+
Zustellweg, den Konsolen-Herzschlag, den letzten Warteschlangen-Fortschritt sowie
|
|
318
|
+
den aktuellen Arbeitsschritt. Die Warteschlange wird als tatsächlich ungelesener
|
|
319
|
+
Anteil und Gesamtgröße gemessen; ein Prüfpunkt wird nur für exakt dieselbe
|
|
320
|
+
Warteschlangendatei akzeptiert. Damit bleibt der Zustand auch dann abfragbar,
|
|
321
|
+
wenn die Konsole hängt oder der Modellanbieter ausgelastet ist. Die Ausgabe
|
|
322
|
+
enthält keine Chat-IDs, Dateipfade, Zugangsdaten, Nachrichteninhalte oder
|
|
323
|
+
vollständigen Aufgabenlisten. Nicht verbundene Absender erhalten weiterhin nur
|
|
324
|
+
die Kopplungsanweisung.
|
|
321
325
|
|
|
322
326
|
Beim ersten Start werden das Telegram-Plugin und die mitgelieferten Skills
|
|
323
327
|
eingerichtet. Die Anmeldung erfolgt anschließend in der
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } = require('node:fs');
|
|
4
|
+
const { join } = require('node:path');
|
|
5
|
+
|
|
6
|
+
const STATUS_FILE = 'telegram-console-status.json';
|
|
7
|
+
const MAX_STATUS_BYTES = 16_384;
|
|
8
|
+
const MAX_TASK_CHARS = 240;
|
|
9
|
+
|
|
10
|
+
function validInstant(value) {
|
|
11
|
+
if (typeof value !== 'string' || value.length === 0) return undefined;
|
|
12
|
+
return Number.isFinite(Date.parse(value)) ? value : undefined;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function boundedTask(value) {
|
|
16
|
+
if (typeof value !== 'string') return undefined;
|
|
17
|
+
const title = value.replace(/\s+/gu, ' ').trim();
|
|
18
|
+
return title.length > 0 ? title.slice(0, MAX_TASK_CHARS) : undefined;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function buildTelegramConsoleStatus(input = {}) {
|
|
22
|
+
const capturedAt = validInstant(input.capturedAt);
|
|
23
|
+
const processStartedAt = validInstant(input.processStartedAt);
|
|
24
|
+
const pid = Number.isSafeInteger(input.pid) && input.pid > 1 ? input.pid : undefined;
|
|
25
|
+
const step = Number.isSafeInteger(input.step) && input.step >= 0 ? input.step : 0;
|
|
26
|
+
if (capturedAt === undefined || processStartedAt === undefined || pid === undefined
|
|
27
|
+
|| typeof input.turnActive !== 'boolean') {
|
|
28
|
+
throw new TypeError('invalid Telegram console status');
|
|
29
|
+
}
|
|
30
|
+
const activeTask = input.turnActive
|
|
31
|
+
? boundedTask(input.todos?.find((todo) => todo?.status === 'in_progress')?.title)
|
|
32
|
+
: undefined;
|
|
33
|
+
return {
|
|
34
|
+
version: 1,
|
|
35
|
+
pid,
|
|
36
|
+
capturedAt,
|
|
37
|
+
processStartedAt,
|
|
38
|
+
turnActive: input.turnActive,
|
|
39
|
+
step,
|
|
40
|
+
...(activeTask === undefined ? {} : { activeTask }),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function parseTelegramConsoleStatus(value, options = {}) {
|
|
45
|
+
try {
|
|
46
|
+
const text = typeof value === 'string' ? value : JSON.stringify(value);
|
|
47
|
+
if (text.length === 0 || Buffer.byteLength(text, 'utf8') > MAX_STATUS_BYTES) return undefined;
|
|
48
|
+
const parsed = typeof value === 'string' ? JSON.parse(value) : value;
|
|
49
|
+
if (parsed?.version !== 1 || !Number.isSafeInteger(parsed.pid) || parsed.pid <= 1
|
|
50
|
+
|| (options.expectedPid !== undefined && parsed.pid !== options.expectedPid)
|
|
51
|
+
|| validInstant(parsed.capturedAt) === undefined
|
|
52
|
+
|| validInstant(parsed.processStartedAt) === undefined
|
|
53
|
+
|| typeof parsed.turnActive !== 'boolean'
|
|
54
|
+
|| !Number.isSafeInteger(parsed.step) || parsed.step < 0) return undefined;
|
|
55
|
+
const activeTask = boundedTask(parsed.activeTask);
|
|
56
|
+
return {
|
|
57
|
+
version: 1,
|
|
58
|
+
pid: parsed.pid,
|
|
59
|
+
capturedAt: parsed.capturedAt,
|
|
60
|
+
processStartedAt: parsed.processStartedAt,
|
|
61
|
+
turnActive: parsed.turnActive,
|
|
62
|
+
step: parsed.step,
|
|
63
|
+
...(parsed.turnActive && activeTask !== undefined ? { activeTask } : {}),
|
|
64
|
+
};
|
|
65
|
+
} catch {
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function writeTelegramConsoleStatus(input = {}) {
|
|
71
|
+
const status = buildTelegramConsoleStatus(input);
|
|
72
|
+
const directory = input.directory;
|
|
73
|
+
if (typeof directory !== 'string' || directory.length === 0) {
|
|
74
|
+
throw new TypeError('invalid Telegram console status directory');
|
|
75
|
+
}
|
|
76
|
+
mkdirSync(directory, { recursive: true, mode: 0o700 });
|
|
77
|
+
const target = join(directory, STATUS_FILE);
|
|
78
|
+
const temporary = join(directory, `.telegram-console-status.${status.pid}.${Date.now()}.tmp`);
|
|
79
|
+
try {
|
|
80
|
+
writeFileSync(temporary, `${JSON.stringify(status)}\n`, { encoding: 'utf8', mode: 0o600 });
|
|
81
|
+
renameSync(temporary, target);
|
|
82
|
+
} finally {
|
|
83
|
+
rmSync(temporary, { force: true });
|
|
84
|
+
}
|
|
85
|
+
return status;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function readTelegramConsoleStatus(directory, options = {}) {
|
|
89
|
+
try {
|
|
90
|
+
return parseTelegramConsoleStatus(readFileSync(join(directory, STATUS_FILE), 'utf8'), options);
|
|
91
|
+
} catch {
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
module.exports = {
|
|
97
|
+
STATUS_FILE,
|
|
98
|
+
buildTelegramConsoleStatus,
|
|
99
|
+
parseTelegramConsoleStatus,
|
|
100
|
+
readTelegramConsoleStatus,
|
|
101
|
+
writeTelegramConsoleStatus,
|
|
102
|
+
};
|
|
@@ -23,8 +23,35 @@ function formatDuration(seconds) {
|
|
|
23
23
|
function formatBytes(bytes) {
|
|
24
24
|
const value = Math.max(0, Number(bytes) || 0);
|
|
25
25
|
if (value < 1024) return `${Math.round(value)} B`;
|
|
26
|
-
if (value < 1024 * 1024) return `${(value / 1024).toFixed(1)} KB`;
|
|
27
|
-
return `${(value / (1024 * 1024)).toFixed(1)} MB`;
|
|
26
|
+
if (value < 1024 * 1024) return `${(value / 1024).toFixed(1).replace('.', ',')} KB`;
|
|
27
|
+
return `${(value / (1024 * 1024)).toFixed(1).replace('.', ',')} MB`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function formatAge(value, capturedAt) {
|
|
31
|
+
const then = Date.parse(value);
|
|
32
|
+
const now = Date.parse(capturedAt);
|
|
33
|
+
if (!Number.isFinite(then) || !Number.isFinite(now) || then > now) return undefined;
|
|
34
|
+
const seconds = Math.floor((now - then) / 1000);
|
|
35
|
+
return seconds < 60 ? `vor ${seconds} s` : `vor ${formatDuration(seconds)}`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function resolveTelegramQueueSnapshot(input = {}) {
|
|
39
|
+
const totalBytes = Number.isSafeInteger(input.queueBytes) && input.queueBytes >= 0
|
|
40
|
+
? input.queueBytes
|
|
41
|
+
: 0;
|
|
42
|
+
const checkpoint = input.checkpoint;
|
|
43
|
+
const checkpointValid = checkpoint?.version === 1
|
|
44
|
+
&& typeof input.queueFileId === 'string'
|
|
45
|
+
&& input.queueFileId.length > 0
|
|
46
|
+
&& checkpoint.fileId === input.queueFileId
|
|
47
|
+
&& Number.isSafeInteger(checkpoint.offset)
|
|
48
|
+
&& checkpoint.offset >= 0
|
|
49
|
+
&& checkpoint.offset <= totalBytes;
|
|
50
|
+
return {
|
|
51
|
+
totalBytes,
|
|
52
|
+
unreadBytes: checkpointValid ? totalBytes - checkpoint.offset : undefined,
|
|
53
|
+
checkpointValid,
|
|
54
|
+
};
|
|
28
55
|
}
|
|
29
56
|
|
|
30
57
|
function buildTelegramRemoteStatus(input) {
|
|
@@ -34,11 +61,23 @@ function buildTelegramRemoteStatus(input) {
|
|
|
34
61
|
|
|
35
62
|
const username = input.username ? `@${String(input.username).replace(/^@/u, '')}` : 'verbundener Nutzer';
|
|
36
63
|
const tui = input.tuiFresh
|
|
37
|
-
? `verbunden${Number.isInteger(input.tuiPid) ? ` (PID ${input.tuiPid}
|
|
64
|
+
? `verbunden${Number.isInteger(input.tuiPid) ? ` (PID ${input.tuiPid}${input.consoleStatus?.processStartedAt
|
|
65
|
+
? `, ${formatDuration((Date.parse(input.capturedAt) - Date.parse(input.consoleStatus.processStartedAt)) / 1000)}`
|
|
66
|
+
: ''})` : ''}`
|
|
38
67
|
: 'nicht verbunden';
|
|
39
68
|
const delivery = input.deliveryTarget === 'tui'
|
|
40
69
|
? 'Konsolen-Warteschlange'
|
|
41
70
|
: 'Brücke ohne Konsole';
|
|
71
|
+
const heartbeatAge = formatAge(input.tuiHeartbeatAt, input.capturedAt);
|
|
72
|
+
const checkpointAge = formatAge(input.queueCheckpointAt, input.capturedAt);
|
|
73
|
+
const workLines = input.consoleStatus === undefined
|
|
74
|
+
? ['Arbeitsstatus: nicht verfügbar']
|
|
75
|
+
: input.consoleStatus.turnActive
|
|
76
|
+
? [
|
|
77
|
+
`Arbeitsstatus: aktiv, Schritt ${input.consoleStatus.step}`,
|
|
78
|
+
...(input.consoleStatus.activeTask === undefined ? [] : [`Aktive Aufgabe: ${input.consoleStatus.activeTask}`]),
|
|
79
|
+
]
|
|
80
|
+
: ['Arbeitsstatus: Leerlauf'];
|
|
42
81
|
return [
|
|
43
82
|
`BLUN-Fernstatus für ${username}`,
|
|
44
83
|
`Rechner: ${input.machineName || 'unbekannt'}`,
|
|
@@ -46,7 +85,10 @@ function buildTelegramRemoteStatus(input) {
|
|
|
46
85
|
`Brücke: aktiv (PID ${input.bridgePid}, ${formatDuration(input.bridgeUptimeSeconds)})`,
|
|
47
86
|
`Konsole: ${tui}`,
|
|
48
87
|
`Zustellung: ${delivery}`,
|
|
49
|
-
`Warteschlange: ${formatBytes(input.queueBytes)}`,
|
|
88
|
+
`Warteschlange: ${input.queueUnreadBytes === undefined ? 'unbekannt' : `${formatBytes(input.queueUnreadBytes)} ungelesen`} (${formatBytes(input.queueBytes)} gesamt)`,
|
|
89
|
+
...(heartbeatAge === undefined ? [] : [`Konsolen-Herzschlag: ${heartbeatAge}`]),
|
|
90
|
+
...(checkpointAge === undefined ? [] : [`Warteschlangen-Fortschritt: ${checkpointAge}`]),
|
|
91
|
+
...workLines,
|
|
50
92
|
`Gemessen: ${input.capturedAt}`,
|
|
51
93
|
].join('\n');
|
|
52
94
|
}
|
|
@@ -55,5 +97,6 @@ module.exports = {
|
|
|
55
97
|
buildTelegramRemoteStatus,
|
|
56
98
|
formatBytes,
|
|
57
99
|
formatDuration,
|
|
100
|
+
resolveTelegramQueueSnapshot,
|
|
58
101
|
resolveTelegramRemoteVersion,
|
|
59
102
|
};
|
package/blun.mjs
CHANGED
|
@@ -5,6 +5,7 @@ import { dirname as __cjsShimDirname } from 'node:path';
|
|
|
5
5
|
const __filename = __cjsShimFileURLToPath(import.meta.url);
|
|
6
6
|
const __dirname = __cjsShimDirname(__filename);
|
|
7
7
|
import { createRequire } from "node:module";
|
|
8
|
+
import telegramConsoleStatusPolicy from "./bin/telegram-console-status-policy.cjs";
|
|
8
9
|
import crypto$1, { createHash, randomBytes, randomInt, randomUUID, timingSafeEqual } from "node:crypto";
|
|
9
10
|
import * as fs$16 from "node:fs";
|
|
10
11
|
import Kt, { accessSync, appendFileSync, chmodSync, closeSync, constants, copyFileSync, createReadStream, createWriteStream, existsSync, fsyncSync, linkSync, lstatSync, mkdirSync, openSync, promises, readFileSync, readSync, readdirSync, realpathSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
|
|
@@ -34,6 +35,7 @@ import * as posixPath from "node:path/posix";
|
|
|
34
35
|
import * as win32Path from "node:path/win32";
|
|
35
36
|
import { createServer } from "node:http";
|
|
36
37
|
import { pipeline as pipeline$1 } from "node:stream/promises";
|
|
38
|
+
const { writeTelegramConsoleStatus } = telegramConsoleStatusPolicy;
|
|
37
39
|
import { EventEmitter as EventEmitter$1 } from "node:events";
|
|
38
40
|
import { StringDecoder } from "node:string_decoder";
|
|
39
41
|
import co from "node:assert";
|
|
@@ -511029,6 +511031,8 @@ var StreamingUIController = class {
|
|
|
511029
511031
|
pendingToolCallFlushIds = /* @__PURE__ */ new Set();
|
|
511030
511032
|
_currentTurnId = void 0;
|
|
511031
511033
|
_currentStep = 0;
|
|
511034
|
+
_remoteTodos = [];
|
|
511035
|
+
_remoteProcessStartedAt = new Date(Date.now() - process.uptime() * 1e3).toISOString();
|
|
511032
511036
|
_liveTurnStartedAtMs = void 0;
|
|
511033
511037
|
_liveOutputTokens = new LiveOutputTokenCounter();
|
|
511034
511038
|
_countedToolCallIds = /* @__PURE__ */ new Set();
|
|
@@ -511054,9 +511058,25 @@ var StreamingUIController = class {
|
|
|
511054
511058
|
}
|
|
511055
511059
|
setTurnId(turnId) {
|
|
511056
511060
|
this._currentTurnId = turnId;
|
|
511061
|
+
this.publishTelegramConsoleStatus();
|
|
511057
511062
|
}
|
|
511058
511063
|
setStep(step) {
|
|
511059
511064
|
this._currentStep = step;
|
|
511065
|
+
this.publishTelegramConsoleStatus();
|
|
511066
|
+
}
|
|
511067
|
+
publishTelegramConsoleStatus() {
|
|
511068
|
+
if (!telegramChannelAttachEnabled()) return;
|
|
511069
|
+
try {
|
|
511070
|
+
writeTelegramConsoleStatus({
|
|
511071
|
+
directory: telegramStateDir(),
|
|
511072
|
+
capturedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
511073
|
+
pid: process.pid,
|
|
511074
|
+
processStartedAt: this._remoteProcessStartedAt,
|
|
511075
|
+
step: this._currentStep,
|
|
511076
|
+
todos: this._remoteTodos,
|
|
511077
|
+
turnActive: this._currentTurnId !== void 0
|
|
511078
|
+
});
|
|
511079
|
+
} catch {}
|
|
511060
511080
|
}
|
|
511061
511081
|
hasActiveTurn() {
|
|
511062
511082
|
return this._currentTurnId !== void 0;
|
|
@@ -511364,8 +511384,10 @@ var StreamingUIController = class {
|
|
|
511364
511384
|
this._pendingReadGroup = null;
|
|
511365
511385
|
this._currentTurnId = void 0;
|
|
511366
511386
|
this._currentStep = 0;
|
|
511387
|
+
this._remoteTodos = [];
|
|
511367
511388
|
this._streamingToolCallArguments.clear();
|
|
511368
511389
|
this.pendingToolCallFlushIds.clear();
|
|
511390
|
+
this.publishTelegramConsoleStatus();
|
|
511369
511391
|
this.host.state.ui.requestRender();
|
|
511370
511392
|
}
|
|
511371
511393
|
disposeActiveThinkingComponent() {
|
|
@@ -511627,9 +511649,11 @@ var StreamingUIController = class {
|
|
|
511627
511649
|
}
|
|
511628
511650
|
setTodoList(todos) {
|
|
511629
511651
|
const { state } = this.host;
|
|
511652
|
+
this._remoteTodos = todos;
|
|
511630
511653
|
state.todoPanel.setTodos(todos);
|
|
511631
511654
|
state.todoPanelContainer.clear();
|
|
511632
511655
|
if (!state.todoPanel.isEmpty()) state.todoPanelContainer.addChild(state.todoPanel);
|
|
511656
|
+
this.publishTelegramConsoleStatus();
|
|
511633
511657
|
state.ui.requestRender();
|
|
511634
511658
|
}
|
|
511635
511659
|
beginCompaction(instruction) {
|
package/package.json
CHANGED
|
@@ -7,9 +7,11 @@ import { Readable, Writable } from "node:stream";
|
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
8
|
import { hostname } from "node:os";
|
|
9
9
|
import remoteStatusPolicy from "../../bin/telegram-remote-status-policy.cjs";
|
|
10
|
+
import consoleStatusPolicy from "../../bin/telegram-console-status-policy.cjs";
|
|
10
11
|
import telegramApprovalRelay from "../../bin/telegram-approval-relay.cjs";
|
|
11
12
|
import privateConversationPolicy from "../bin/telegram-private-conversation-policy.cjs";
|
|
12
|
-
const { buildTelegramRemoteStatus, resolveTelegramRemoteVersion } = remoteStatusPolicy;
|
|
13
|
+
const { buildTelegramRemoteStatus, resolveTelegramQueueSnapshot, resolveTelegramRemoteVersion } = remoteStatusPolicy;
|
|
14
|
+
const { parseTelegramConsoleStatus } = consoleStatusPolicy;
|
|
13
15
|
const { buildTelegramApprovalCard, isAuthorizedTelegramApprovalCallback, listPendingTelegramApprovals, markTelegramApprovalSent, parseTelegramApprovalCallback, resolveTelegramApprovalTarget, wasTelegramApprovalSent, writeTelegramApprovalResponse } = telegramApprovalRelay;
|
|
14
16
|
const { findDuplicateReplyWithoutNewInbound, isPrivateInternalStatusReply, sanitizePrivateConversationReply } = privateConversationPolicy;
|
|
15
17
|
//#region ../../node_modules/pathe/dist/shared/pathe.M-eThtNZ.mjs
|
|
@@ -4759,26 +4761,49 @@ bot.command("status", async (ctx) => {
|
|
|
4759
4761
|
if (access.allowFrom.includes(senderId)) {
|
|
4760
4762
|
let version = "unbekannt";
|
|
4761
4763
|
let tuiPid;
|
|
4762
|
-
let
|
|
4764
|
+
let tuiHeartbeatAt;
|
|
4765
|
+
let queueStats;
|
|
4766
|
+
let checkpoint;
|
|
4767
|
+
let queueCheckpointAt;
|
|
4768
|
+
let consoleStatus;
|
|
4769
|
+
const capturedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4763
4770
|
try {
|
|
4764
4771
|
version = JSON.parse(readFileSync(join(dirname(KING_ENTRY), "package.json"), "utf8")).version ?? version;
|
|
4765
4772
|
} catch {}
|
|
4766
4773
|
try {
|
|
4767
4774
|
tuiPid = parseInt(readFileSync(tuiPidFile(), "utf8"), 10);
|
|
4775
|
+
tuiHeartbeatAt = statSync(tuiPidFile()).mtime.toISOString();
|
|
4768
4776
|
} catch {}
|
|
4769
4777
|
try {
|
|
4770
|
-
|
|
4778
|
+
queueStats = statSync(tuiInboundQueueFile());
|
|
4771
4779
|
} catch {}
|
|
4780
|
+
try {
|
|
4781
|
+
const checkpointFile = join(stateDir(), "inbound-queue.checkpoint.json");
|
|
4782
|
+
checkpoint = JSON.parse(readFileSync(checkpointFile, "utf8"));
|
|
4783
|
+
queueCheckpointAt = statSync(checkpointFile).mtime.toISOString();
|
|
4784
|
+
} catch {}
|
|
4785
|
+
if (Number.isInteger(tuiPid)) try {
|
|
4786
|
+
consoleStatus = parseTelegramConsoleStatus(readFileSync(join(stateDir(), "telegram-console-status.json"), "utf8"), { expectedPid: tuiPid });
|
|
4787
|
+
} catch {}
|
|
4788
|
+
const queueSnapshot = resolveTelegramQueueSnapshot({
|
|
4789
|
+
checkpoint,
|
|
4790
|
+
queueBytes: queueStats?.size,
|
|
4791
|
+
queueFileId: queueStats === void 0 ? void 0 : `${queueStats.dev}:${queueStats.ino}:${queueStats.birthtimeMs}`
|
|
4792
|
+
});
|
|
4772
4793
|
await ctx.reply(buildTelegramRemoteStatus({
|
|
4773
4794
|
access,
|
|
4774
4795
|
bridgePid: process.pid,
|
|
4775
4796
|
bridgeUptimeSeconds: process.uptime(),
|
|
4776
|
-
capturedAt
|
|
4797
|
+
capturedAt,
|
|
4798
|
+
consoleStatus,
|
|
4777
4799
|
deliveryTarget: deliveryTarget(),
|
|
4778
4800
|
machineName: hostname(),
|
|
4779
|
-
queueBytes,
|
|
4801
|
+
queueBytes: queueSnapshot.totalBytes,
|
|
4802
|
+
queueCheckpointAt,
|
|
4803
|
+
queueUnreadBytes: queueSnapshot.unreadBytes,
|
|
4780
4804
|
senderId,
|
|
4781
4805
|
tuiFresh: isTuiLeaseFresh(),
|
|
4806
|
+
tuiHeartbeatAt,
|
|
4782
4807
|
tuiPid: Number.isInteger(tuiPid) ? tuiPid : void 0,
|
|
4783
4808
|
username: ctx.from?.username,
|
|
4784
4809
|
version: resolveTelegramRemoteVersion({
|