@llblab/pi-telegram 0.18.3 → 0.18.5
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/AGENTS.md +5 -3
- package/BACKLOG.md +6 -19
- package/CHANGELOG.md +14 -2
- package/README.md +1 -1
- package/docs/multi-instance-bus.md +3 -3
- package/index.ts +30 -1
- package/lib/bus-follower.ts +64 -16
- package/lib/bus-leader.ts +19 -20
- package/lib/bus-transport.ts +227 -0
- package/lib/bus.ts +170 -46
- package/lib/polling.ts +58 -5
- package/lib/preview.ts +20 -39
- package/lib/queue.ts +70 -0
- package/lib/runtime-log.ts +19 -1
- package/lib/status.ts +50 -0
- package/package.json +1 -1
package/lib/preview.ts
CHANGED
|
@@ -12,7 +12,6 @@ import {
|
|
|
12
12
|
} from "./target.ts";
|
|
13
13
|
import { shouldSuppressPreviewForVoice } from "./voice.ts";
|
|
14
14
|
|
|
15
|
-
const TELEGRAM_PREVIEW_THROTTLE_MS = 0;
|
|
16
15
|
const TELEGRAM_DRAFT_ID_MAX = 2_147_483_647;
|
|
17
16
|
const TELEGRAM_DRAFT_PREVIEW_MAX_CHARS = 4096;
|
|
18
17
|
|
|
@@ -26,7 +25,6 @@ export interface TelegramPreviewState {
|
|
|
26
25
|
}
|
|
27
26
|
|
|
28
27
|
export interface TelegramPreviewRuntimeState extends TelegramPreviewState {
|
|
29
|
-
flushTimer?: ReturnType<typeof setTimeout>;
|
|
30
28
|
flushPromise?: Promise<void>;
|
|
31
29
|
flushRequested?: boolean;
|
|
32
30
|
}
|
|
@@ -36,7 +34,6 @@ export type TelegramPreviewReplyMarkup = unknown;
|
|
|
36
34
|
export interface TelegramPreviewRuntimeDeps {
|
|
37
35
|
getState: () => TelegramPreviewRuntimeState | undefined;
|
|
38
36
|
setState: (state: TelegramPreviewRuntimeState | undefined) => void;
|
|
39
|
-
clearScheduledFlush: (state: TelegramPreviewRuntimeState) => void;
|
|
40
37
|
maxMessageLength: number;
|
|
41
38
|
getDraftSupport: () => TelegramDraftSupport;
|
|
42
39
|
setDraftSupport: (support: TelegramDraftSupport) => void;
|
|
@@ -132,13 +129,7 @@ export interface TelegramPreviewControllerDeps {
|
|
|
132
129
|
},
|
|
133
130
|
) => Promise<unknown>;
|
|
134
131
|
canSend?: () => boolean;
|
|
135
|
-
throttleMs?: number;
|
|
136
132
|
maxDraftId?: number;
|
|
137
|
-
setTimer?: (
|
|
138
|
-
callback: () => void,
|
|
139
|
-
ms: number,
|
|
140
|
-
) => ReturnType<typeof setTimeout>;
|
|
141
|
-
clearTimer?: (timer: ReturnType<typeof setTimeout>) => void;
|
|
142
133
|
recordRuntimeEvent?: (
|
|
143
134
|
category: string,
|
|
144
135
|
error: unknown,
|
|
@@ -154,7 +145,7 @@ export interface TelegramPreviewController {
|
|
|
154
145
|
resetState: () => void;
|
|
155
146
|
clear: (
|
|
156
147
|
chatId: number,
|
|
157
|
-
options?: { target?: TelegramTarget },
|
|
148
|
+
options?: { awaitFlush?: boolean; target?: TelegramTarget },
|
|
158
149
|
) => Promise<void>;
|
|
159
150
|
flush: (
|
|
160
151
|
chatId: number,
|
|
@@ -171,7 +162,8 @@ export interface TelegramPreviewController {
|
|
|
171
162
|
) => Promise<boolean>;
|
|
172
163
|
}
|
|
173
164
|
|
|
174
|
-
export type TelegramPreviewControllerRuntimeDeps =
|
|
165
|
+
export type TelegramPreviewControllerRuntimeDeps =
|
|
166
|
+
TelegramPreviewControllerDeps;
|
|
175
167
|
|
|
176
168
|
export function createTelegramPreviewControllerRuntime(
|
|
177
169
|
deps: TelegramPreviewControllerRuntimeDeps,
|
|
@@ -181,10 +173,7 @@ export function createTelegramPreviewControllerRuntime(
|
|
|
181
173
|
maxMessageLength: deps.maxMessageLength,
|
|
182
174
|
initialDraftSupport: deps.initialDraftSupport,
|
|
183
175
|
sendDraft: deps.sendDraft,
|
|
184
|
-
throttleMs: deps.throttleMs,
|
|
185
176
|
maxDraftId: deps.maxDraftId,
|
|
186
|
-
setTimer: deps.setTimer,
|
|
187
|
-
clearTimer: deps.clearTimer,
|
|
188
177
|
recordRuntimeEvent: deps.recordRuntimeEvent,
|
|
189
178
|
});
|
|
190
179
|
}
|
|
@@ -223,7 +212,7 @@ export function createTelegramNativeMarkdownPreviewFinalizer<
|
|
|
223
212
|
getState: () => TelegramPreviewRuntimeState | undefined;
|
|
224
213
|
clear: (
|
|
225
214
|
chatId: number,
|
|
226
|
-
options?: { target?: TelegramTarget },
|
|
215
|
+
options?: { awaitFlush?: boolean; target?: TelegramTarget },
|
|
227
216
|
) => Promise<void>;
|
|
228
217
|
discard?: () => void;
|
|
229
218
|
sendMarkdownReply: (
|
|
@@ -283,12 +272,6 @@ export function createTelegramPreviewController(
|
|
|
283
272
|
deps: TelegramPreviewControllerDeps,
|
|
284
273
|
): TelegramPreviewController {
|
|
285
274
|
let state: TelegramPreviewRuntimeState | undefined;
|
|
286
|
-
const clearTimer = deps.clearTimer ?? clearTimeout;
|
|
287
|
-
const setTimer =
|
|
288
|
-
deps.setTimer ??
|
|
289
|
-
((callback: () => void, ms: number): ReturnType<typeof setTimeout> =>
|
|
290
|
-
setTimeout(callback, ms));
|
|
291
|
-
const throttleMs = deps.throttleMs ?? TELEGRAM_PREVIEW_THROTTLE_MS;
|
|
292
275
|
const maxDraftId = deps.maxDraftId ?? TELEGRAM_DRAFT_ID_MAX;
|
|
293
276
|
const maxMessageLength =
|
|
294
277
|
deps.maxMessageLength ?? TELEGRAM_DRAFT_PREVIEW_MAX_CHARS;
|
|
@@ -299,11 +282,6 @@ export function createTelegramPreviewController(
|
|
|
299
282
|
setState: (nextState) => {
|
|
300
283
|
state = nextState;
|
|
301
284
|
},
|
|
302
|
-
clearScheduledFlush: (nextState) => {
|
|
303
|
-
if (!nextState.flushTimer) return;
|
|
304
|
-
clearTimer(nextState.flushTimer);
|
|
305
|
-
nextState.flushTimer = undefined;
|
|
306
|
-
},
|
|
307
285
|
maxMessageLength,
|
|
308
286
|
getDraftSupport: () => draftSupport,
|
|
309
287
|
setDraftSupport: (support) => {
|
|
@@ -334,15 +312,8 @@ export function createTelegramPreviewController(
|
|
|
334
312
|
flush: (chatId, options) =>
|
|
335
313
|
flushTelegramPreview(chatId, getRuntimeDeps(), options),
|
|
336
314
|
scheduleFlush: (chatId, options) => {
|
|
337
|
-
if (!state
|
|
338
|
-
|
|
339
|
-
void flushTelegramPreview(chatId, getRuntimeDeps(), options);
|
|
340
|
-
return;
|
|
341
|
-
}
|
|
342
|
-
state.flushTimer = setTimer(() => {
|
|
343
|
-
void flushTelegramPreview(chatId, getRuntimeDeps(), options);
|
|
344
|
-
}, throttleMs);
|
|
345
|
-
state.flushTimer.unref?.();
|
|
315
|
+
if (!state) return;
|
|
316
|
+
void flushTelegramPreview(chatId, getRuntimeDeps(), options);
|
|
346
317
|
},
|
|
347
318
|
finalize: (chatId, _replyToMessageId, options) =>
|
|
348
319
|
finalizeTelegramPreview(chatId, getRuntimeDeps(), options),
|
|
@@ -464,7 +435,6 @@ export async function clearTelegramPreview(
|
|
|
464
435
|
): Promise<void> {
|
|
465
436
|
const state = deps.getState();
|
|
466
437
|
if (!state) return;
|
|
467
|
-
deps.clearScheduledFlush(state);
|
|
468
438
|
if (state.flushPromise && options.awaitFlush !== false) {
|
|
469
439
|
state.flushRequested = false;
|
|
470
440
|
await state.flushPromise.catch(() => {});
|
|
@@ -699,6 +669,10 @@ function findSafeTelegramRichMarkdownDraftEnd(markdown: string): number {
|
|
|
699
669
|
return safeEnd;
|
|
700
670
|
}
|
|
701
671
|
|
|
672
|
+
function hasTelegramPreviewVisibleContent(markdown: string): boolean {
|
|
673
|
+
return /[\p{L}\p{N}]/u.test(markdown);
|
|
674
|
+
}
|
|
675
|
+
|
|
702
676
|
export function getSafeTelegramRichMarkdownDraftPrefix(
|
|
703
677
|
markdown: string,
|
|
704
678
|
maxMessageLength: number,
|
|
@@ -710,13 +684,21 @@ export function getSafeTelegramRichMarkdownDraftPrefix(
|
|
|
710
684
|
? source.slice(0, maxMessageLength)
|
|
711
685
|
: source;
|
|
712
686
|
const safeEnd = findSafeTelegramRichMarkdownDraftEnd(limited);
|
|
713
|
-
if (safeEnd > 0)
|
|
687
|
+
if (safeEnd > 0) {
|
|
688
|
+
const safePrefix = limited.slice(0, safeEnd).trimEnd();
|
|
689
|
+
return hasTelegramPreviewVisibleContent(safePrefix)
|
|
690
|
+
? safePrefix
|
|
691
|
+
: undefined;
|
|
692
|
+
}
|
|
714
693
|
let candidateEnd = limited.length;
|
|
715
694
|
while (candidateEnd > 0) {
|
|
716
695
|
candidateEnd = limited.lastIndexOf(" ", candidateEnd - 1);
|
|
717
696
|
if (candidateEnd <= 0) return undefined;
|
|
718
697
|
const candidate = limited.slice(0, candidateEnd).trimEnd();
|
|
719
|
-
if (
|
|
698
|
+
if (
|
|
699
|
+
hasTelegramPreviewVisibleContent(candidate) &&
|
|
700
|
+
findSafeTelegramRichMarkdownDraftEnd(candidate) === candidate.length
|
|
701
|
+
) {
|
|
720
702
|
return candidate || undefined;
|
|
721
703
|
}
|
|
722
704
|
}
|
|
@@ -795,7 +777,6 @@ export async function flushTelegramPreview(
|
|
|
795
777
|
await state.flushPromise;
|
|
796
778
|
return;
|
|
797
779
|
}
|
|
798
|
-
state.flushTimer = undefined;
|
|
799
780
|
state.flushPromise = (async () => {
|
|
800
781
|
do {
|
|
801
782
|
state.flushRequested = false;
|
package/lib/queue.ts
CHANGED
|
@@ -1920,6 +1920,76 @@ export function createTelegramDeferredQueueDispatchRuntime<TContext = unknown>(
|
|
|
1920
1920
|
};
|
|
1921
1921
|
}
|
|
1922
1922
|
|
|
1923
|
+
// --- Dispatch Watchdog Runtime ---
|
|
1924
|
+
|
|
1925
|
+
export interface TelegramQueueDispatchWatchdogRuntime<TContext = unknown> {
|
|
1926
|
+
start: (ctx: TContext) => void;
|
|
1927
|
+
stop: () => void;
|
|
1928
|
+
poke: () => void;
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
export interface TelegramQueueDispatchWatchdogRuntimeDeps<
|
|
1932
|
+
TContext = unknown,
|
|
1933
|
+
> extends TelegramRuntimeEventRecorderPort {
|
|
1934
|
+
hasQueuedItems: () => boolean;
|
|
1935
|
+
dispatchNextQueuedTelegramTurn: (ctx: TContext) => void;
|
|
1936
|
+
intervalMs?: number;
|
|
1937
|
+
setInterval?: (
|
|
1938
|
+
callback: () => void,
|
|
1939
|
+
ms: number,
|
|
1940
|
+
) => ReturnType<typeof setInterval>;
|
|
1941
|
+
clearInterval?: (timer: ReturnType<typeof setInterval>) => void;
|
|
1942
|
+
}
|
|
1943
|
+
|
|
1944
|
+
export function createTelegramQueueDispatchWatchdogRuntime<
|
|
1945
|
+
TContext = unknown,
|
|
1946
|
+
>(
|
|
1947
|
+
deps: TelegramQueueDispatchWatchdogRuntimeDeps<TContext>,
|
|
1948
|
+
): TelegramQueueDispatchWatchdogRuntime<TContext> {
|
|
1949
|
+
const intervalMs = deps.intervalMs ?? 1000;
|
|
1950
|
+
const setIntervalFn: NonNullable<
|
|
1951
|
+
TelegramQueueDispatchWatchdogRuntimeDeps<TContext>["setInterval"]
|
|
1952
|
+
> = deps.setInterval ?? ((callback, ms) => setInterval(callback, ms));
|
|
1953
|
+
const clearIntervalFn: NonNullable<
|
|
1954
|
+
TelegramQueueDispatchWatchdogRuntimeDeps<TContext>["clearInterval"]
|
|
1955
|
+
> = deps.clearInterval ?? ((timer) => clearInterval(timer));
|
|
1956
|
+
let ctx: TContext | undefined;
|
|
1957
|
+
let interval: ReturnType<typeof setInterval> | undefined;
|
|
1958
|
+
let dispatchInFlight = false;
|
|
1959
|
+
const tick = (): void => {
|
|
1960
|
+
if (ctx === undefined || dispatchInFlight || !deps.hasQueuedItems()) return;
|
|
1961
|
+
dispatchInFlight = true;
|
|
1962
|
+
try {
|
|
1963
|
+
deps.dispatchNextQueuedTelegramTurn(ctx);
|
|
1964
|
+
} catch (error) {
|
|
1965
|
+
deps.recordRuntimeEvent?.("dispatch", error, {
|
|
1966
|
+
phase: "queue-watchdog",
|
|
1967
|
+
});
|
|
1968
|
+
} finally {
|
|
1969
|
+
dispatchInFlight = false;
|
|
1970
|
+
}
|
|
1971
|
+
};
|
|
1972
|
+
const stop = (): void => {
|
|
1973
|
+
ctx = undefined;
|
|
1974
|
+
if (!interval) return;
|
|
1975
|
+
clearIntervalFn(interval);
|
|
1976
|
+
interval = undefined;
|
|
1977
|
+
};
|
|
1978
|
+
return {
|
|
1979
|
+
start: (nextCtx) => {
|
|
1980
|
+
ctx = nextCtx;
|
|
1981
|
+
if (!interval) {
|
|
1982
|
+
const nextInterval = setIntervalFn(tick, intervalMs);
|
|
1983
|
+
interval = nextInterval;
|
|
1984
|
+
nextInterval.unref?.();
|
|
1985
|
+
}
|
|
1986
|
+
tick();
|
|
1987
|
+
},
|
|
1988
|
+
stop,
|
|
1989
|
+
poke: tick,
|
|
1990
|
+
};
|
|
1991
|
+
}
|
|
1992
|
+
|
|
1923
1993
|
// --- Dispatch Runtime ---
|
|
1924
1994
|
|
|
1925
1995
|
export interface TelegramPromptDeliveryOptions {
|
package/lib/runtime-log.ts
CHANGED
|
@@ -4,7 +4,14 @@
|
|
|
4
4
|
* Owns session-local append-only runtime evidence for debugging without becoming routing state
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
copyFileSync,
|
|
9
|
+
existsSync,
|
|
10
|
+
mkdirSync,
|
|
11
|
+
statSync,
|
|
12
|
+
writeFileSync,
|
|
13
|
+
appendFile,
|
|
14
|
+
} from "node:fs";
|
|
8
15
|
import { homedir } from "node:os";
|
|
9
16
|
import { dirname, join, resolve } from "node:path";
|
|
10
17
|
|
|
@@ -17,6 +24,7 @@ export interface TelegramRuntimeJsonlEvent {
|
|
|
17
24
|
|
|
18
25
|
export interface TelegramRuntimeJsonlLogOptions {
|
|
19
26
|
path?: string;
|
|
27
|
+
previousPath?: string;
|
|
20
28
|
maxBytes?: number;
|
|
21
29
|
getNowMs?: () => number;
|
|
22
30
|
}
|
|
@@ -57,6 +65,8 @@ export function createTelegramRuntimeJsonlLog(
|
|
|
57
65
|
options: TelegramRuntimeJsonlLogOptions = {},
|
|
58
66
|
): TelegramRuntimeJsonlLog {
|
|
59
67
|
const path = options.path ?? getTelegramRuntimeLogPath();
|
|
68
|
+
const previousPath =
|
|
69
|
+
options.previousPath ?? path.replace(/\.jsonl$/u, ".previous.jsonl");
|
|
60
70
|
const maxBytes = options.maxBytes ?? DEFAULT_MAX_LOG_BYTES;
|
|
61
71
|
const getNowMs = options.getNowMs ?? Date.now;
|
|
62
72
|
let scopeKey: string | undefined;
|
|
@@ -66,8 +76,15 @@ export function createTelegramRuntimeJsonlLog(
|
|
|
66
76
|
mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
|
|
67
77
|
};
|
|
68
78
|
|
|
79
|
+
const preserveCurrentLog = () => {
|
|
80
|
+
if (!existsSync(path)) return;
|
|
81
|
+
mkdirSync(dirname(previousPath), { recursive: true, mode: 0o700 });
|
|
82
|
+
copyFileSync(path, previousPath);
|
|
83
|
+
};
|
|
84
|
+
|
|
69
85
|
const writeReset = (reason: string, scope?: Record<string, unknown>) => {
|
|
70
86
|
ensureParent();
|
|
87
|
+
preserveCurrentLog();
|
|
71
88
|
writeFileSync(
|
|
72
89
|
path,
|
|
73
90
|
safeJsonLine({
|
|
@@ -75,6 +92,7 @@ export function createTelegramRuntimeJsonlLog(
|
|
|
75
92
|
kind: "reset",
|
|
76
93
|
reason,
|
|
77
94
|
scope,
|
|
95
|
+
previousPath,
|
|
78
96
|
}) + "\n",
|
|
79
97
|
{ mode: 0o600 },
|
|
80
98
|
);
|
package/lib/status.ts
CHANGED
|
@@ -113,6 +113,17 @@ export interface TelegramBridgeStatusBusFollower {
|
|
|
113
113
|
status?: string;
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
export interface TelegramBridgeStatusLocalBus {
|
|
117
|
+
leaderSocketPath?: string;
|
|
118
|
+
leaderTransport?: "pipe" | "socket";
|
|
119
|
+
followerSocketPath?: string;
|
|
120
|
+
followerTransport?: "pipe" | "socket";
|
|
121
|
+
followerRegistered?: boolean;
|
|
122
|
+
followerTarget?: { chatId: number; threadId?: number };
|
|
123
|
+
followerSlot?: string;
|
|
124
|
+
followerThreadName?: string;
|
|
125
|
+
}
|
|
126
|
+
|
|
116
127
|
export interface TelegramBridgeStatusTopicTarget {
|
|
117
128
|
instanceId?: string;
|
|
118
129
|
status?: string;
|
|
@@ -187,6 +198,7 @@ export interface TelegramBridgeStatusLineState {
|
|
|
187
198
|
pendingModelSwitch: boolean;
|
|
188
199
|
queuedItems: Array<{ queueLane: TelegramStatusQueueLane }>;
|
|
189
200
|
busFollowers?: TelegramBridgeStatusBusFollower[];
|
|
201
|
+
localBus?: TelegramBridgeStatusLocalBus;
|
|
190
202
|
topicTargets?: TelegramBridgeStatusTopicTarget[];
|
|
191
203
|
threadReservations?: TelegramBridgeStatusThreadReservation[];
|
|
192
204
|
topicSyncObservations?: TelegramBridgeStatusSyncObservation[];
|
|
@@ -266,6 +278,7 @@ export interface TelegramBridgeStatusRuntimeDeps<
|
|
|
266
278
|
}
|
|
267
279
|
| undefined;
|
|
268
280
|
getBusFollowers?: () => TelegramBridgeStatusBusFollower[];
|
|
281
|
+
getLocalBus?: () => TelegramBridgeStatusLocalBus | undefined;
|
|
269
282
|
getTopicTargets?: () => TelegramBridgeStatusTopicTarget[];
|
|
270
283
|
getThreadReservations?: () => TelegramBridgeStatusThreadReservation[];
|
|
271
284
|
getTopicSyncObservations?: () => TelegramBridgeStatusSyncObservation[];
|
|
@@ -626,6 +639,7 @@ export function createTelegramBridgeStatusRuntime<
|
|
|
626
639
|
pendingModelSwitch: deps.hasPendingModelSwitch(),
|
|
627
640
|
queuedItems: deps.getQueuedItems(),
|
|
628
641
|
busFollowers: deps.getBusFollowers?.(),
|
|
642
|
+
localBus: deps.getLocalBus?.(),
|
|
629
643
|
topicTargets: deps.getTopicTargets?.(),
|
|
630
644
|
threadReservations: deps.getThreadReservations?.(),
|
|
631
645
|
topicSyncObservations: deps.getTopicSyncObservations?.(),
|
|
@@ -682,6 +696,7 @@ export function createTelegramStatusSnapshot(
|
|
|
682
696
|
},
|
|
683
697
|
liveRoster: {
|
|
684
698
|
busFollowers: state.busFollowers ?? [],
|
|
699
|
+
...(state.localBus ? { localBus: state.localBus } : {}),
|
|
685
700
|
topicTargets: state.topicTargets ?? [],
|
|
686
701
|
reservations: state.threadReservations ?? [],
|
|
687
702
|
syncObservations: state.topicSyncObservations ?? [],
|
|
@@ -824,6 +839,38 @@ function buildTelegramBusFollowerLines(
|
|
|
824
839
|
];
|
|
825
840
|
}
|
|
826
841
|
|
|
842
|
+
function buildTelegramLocalBusLines(
|
|
843
|
+
state: Pick<TelegramBridgeStatusLineState, "localBus">,
|
|
844
|
+
options: { verbose?: boolean } = {},
|
|
845
|
+
): string[] {
|
|
846
|
+
const localBus = state.localBus;
|
|
847
|
+
if (!localBus) return [];
|
|
848
|
+
const target = formatTelegramStatusTarget(localBus.followerTarget);
|
|
849
|
+
const label = formatTelegramThreadStatusLabel({
|
|
850
|
+
slot: localBus.followerSlot,
|
|
851
|
+
threadName: localBus.followerThreadName,
|
|
852
|
+
});
|
|
853
|
+
const followerLine = `- follower registered: ${localBus.followerRegistered ? "yes" : "no"}${label ? ` ${label}` : ""}${target}`;
|
|
854
|
+
const lines = ["", "local bus:", followerLine];
|
|
855
|
+
if (options.verbose) {
|
|
856
|
+
if (localBus.leaderSocketPath) {
|
|
857
|
+
const transport = localBus.leaderTransport
|
|
858
|
+
? ` [${localBus.leaderTransport}]`
|
|
859
|
+
: "";
|
|
860
|
+
lines.push(`- leader endpoint${transport}: ${localBus.leaderSocketPath}`);
|
|
861
|
+
}
|
|
862
|
+
if (localBus.followerSocketPath) {
|
|
863
|
+
const transport = localBus.followerTransport
|
|
864
|
+
? ` [${localBus.followerTransport}]`
|
|
865
|
+
: "";
|
|
866
|
+
lines.push(
|
|
867
|
+
`- follower endpoint${transport}: ${localBus.followerSocketPath}`,
|
|
868
|
+
);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
return lines;
|
|
872
|
+
}
|
|
873
|
+
|
|
827
874
|
function buildTelegramSyncSliceLines(
|
|
828
875
|
state: Pick<TelegramBridgeStatusLineState, "syncState">,
|
|
829
876
|
): string[] {
|
|
@@ -1038,6 +1085,8 @@ function buildTelegramBridgeCompactStatusLines(
|
|
|
1038
1085
|
: []),
|
|
1039
1086
|
...(state.pendingModelSwitch ? ["- pending model switch: yes"] : []),
|
|
1040
1087
|
...buildTelegramBridgeCompactThreadLines(state),
|
|
1088
|
+
...buildTelegramBusFollowerLines(state),
|
|
1089
|
+
...buildTelegramLocalBusLines(state),
|
|
1041
1090
|
...buildTelegramThreadReconciliationLines(state),
|
|
1042
1091
|
"",
|
|
1043
1092
|
"diagnostics:",
|
|
@@ -1100,6 +1149,7 @@ export function buildTelegramBridgeDiagnosticStatusLines(
|
|
|
1100
1149
|
`- queued turns: ${state.queuedItems.length}`,
|
|
1101
1150
|
`- lanes: control=${controlQueueCount}, priority=${priorityQueueCount}, default=${defaultQueueCount}`,
|
|
1102
1151
|
...buildTelegramBusFollowerLines(state),
|
|
1152
|
+
...buildTelegramLocalBusLines(state, { verbose: true }),
|
|
1103
1153
|
...buildTelegramTopicTargetDiagnosticLines(state),
|
|
1104
1154
|
...buildTelegramThreadReconciliationLines(state),
|
|
1105
1155
|
...buildTelegramSyncSliceLines(state),
|