/** * Regression tests for Telegram status helpers * Covers runtime diagnostics lines and recent-event redaction/ring-buffer behavior */ import assert from "node:assert/strict"; import test from "node:test"; import { buildTelegramBridgeStatusLines, buildTelegramRuntimeEventLines, buildTelegramStatusBarText, clearTelegramStatusLineProviders, createTelegramBridgeStatusRuntime, createTelegramRuntimeDiagnosticsSnapshotScheduler, createTelegramRuntimeEventRecorder, createTelegramRuntimeLogScope, createTelegramStatusHtmlBuilder, createTelegramStatusSnapshot, createTelegramStatusRuntime, getTelegramStatusBarProcessingStatus, recordStructuredTelegramRuntimeEvent, recordTelegramRuntimeEvent, registerTelegramStatusLineProvider, type TelegramRuntimeEvent, } from "../lib/status.ts"; test("Status helpers build runtime log scope and persisted snapshot projections", () => { const state = { busRole: "leader" as const, botThreadMode: "enabled" as const, botThreadModeUpdatedAtMs: 10, botThreadModeAction: "probe", instanceSlot: "A", instanceThreadName: "Axial", pollingActive: true, lockState: "active-here", pendingDispatch: true, compactionInProgress: false, activeToolExecutions: 1, pendingModelSwitch: false, queuedItems: [], busFollowers: [{ instanceId: "follower", lastHeartbeatMs: 5 }], topicTargets: [{ instanceId: "leader", status: "active" }], threadReservations: [{ slot: "B", reason: "startup" }], topicSyncObservations: [{ syncStatus: "open", observedAtMs: 9 }], syncState: { pairing: { status: "fresh" } }, recentRuntimeEvents: [], }; assert.deepEqual( createTelegramRuntimeLogScope({ state, instanceId: "instance-1" }), { instanceId: "instance-1", role: "leader", slot: "A", threadName: "Axial", lockState: "active-here", }, ); assert.deepEqual(createTelegramStatusSnapshot(state), { runtime: { busRole: "leader", botThreadMode: "enabled", botThreadModeUpdatedAtMs: 10, botThreadModeAction: "probe", instanceSlot: "A", instanceThreadName: "Axial", pollingActive: true, lockState: "active-here", }, liveRoster: { busFollowers: [{ instanceId: "follower", lastHeartbeatMs: 5 }], topicTargets: [{ instanceId: "leader", status: "active" }], reservations: [{ slot: "B", reason: "startup" }], syncObservations: [{ syncStatus: "open", observedAtMs: 9 }], }, diagnostics: { pendingDispatch: true, compactionInProgress: false, activeToolExecutions: 1, pendingModelSwitch: false, syncState: { pairing: { status: "fresh" } }, threadReconciliation: undefined, recentRuntimeEvents: [], }, }); }); test("Status runtime diagnostics scheduler coalesces snapshot persists", async () => { let scheduled: (() => void) | undefined; let persistCount = 0; const errors: unknown[] = []; const schedule = createTelegramRuntimeDiagnosticsSnapshotScheduler({ persistSnapshot: async () => { persistCount += 1; }, recordError: (error) => errors.push(error), setTimer(callback) { scheduled = callback as () => void; return { unref() {} } as ReturnType; }, }); schedule(); schedule(); scheduled?.(); await Promise.resolve(); assert.equal(persistCount, 1); assert.deepEqual(errors, []); }); const statusBarTheme = { fg: (token: string, text: string) => `<${token}>${text}`, }; function plainStatusText(text: string): string { return text.replace(/<\/?[a-z]+>/g, ""); } function escapeRegExp(text: string): string { return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } test("Status bar text keeps the label, state color and queue for every connection state", () => { const base = { hasBotToken: true, pollingActive: true, paired: true, compactionInProgress: false, processing: false, queuedStatus: "", }; const cases: Array<{ state: Partial[1]>; label: string; token: string; word: string; queued?: string; }> = [ { state: { hasBotToken: false, pollingActive: false, paired: false }, label: "telegram", token: "muted", word: "not configured" }, { state: { processing: true, queuedStatus: " +1" }, label: "telegram", token: "warning", word: "active", queued: " +1" }, { state: { processing: true, processingStatus: "dispatching", queuedStatus: " +1" }, label: "telegram", token: "warning", word: "active", queued: " +1" }, { state: { processing: true, processingStatus: "active" }, label: "telegram", token: "warning", word: "active" }, { state: { compactionInProgress: true }, label: "telegram", token: "success", word: "connected" }, { state: { compactionInProgress: true, processing: true, processingStatus: "active" }, label: "telegram", token: "warning", word: "active" }, { state: { pollingActive: false, instanceThreadName: "Aurora", processing: true, processingStatus: "queued", queuedStatus: " +2" }, label: "telegram", token: "muted", word: "disconnected", queued: " +2" }, { state: { pollingActive: false, busRole: "follower" }, label: "telegram", token: "success", word: "follower" }, { state: { pollingActive: false, busRole: "follower", instanceThreadName: "Amber", processing: true, processingStatus: "active" }, label: "Amber", token: "warning", word: "active" }, { state: { pollingActive: false, busRole: "follower", busLifecyclePhase: "electing" }, label: "telegram", token: "warning", word: "electing" }, { state: { pollingActive: false, busLifecyclePhase: "electing" }, label: "telegram", token: "warning", word: "electing" }, { state: { pollingActive: false, busRole: "follower", instanceThreadName: "Follower" }, label: "telegram", token: "success", word: "follower" }, { state: { pollingActive: false, busRole: "follower", instanceThreadName: "Lname" }, label: "Lname", token: "success", word: "follower" }, { state: { pollingActive: false, busRole: "follower", instanceSlot: "O", instanceThreadName: "extensions Follower" }, label: "extensions Follower", token: "success", word: "follower" }, { state: { pollingActive: false, busRole: "follower", instanceSlot: "O", instanceThreadName: "Oname" }, label: "Oname", token: "success", word: "follower" }, { state: { busRole: "leader" }, label: "telegram", token: "success", word: "leader" }, { state: { busRole: "leader", instanceThreadName: "๐ŸŒ™ A-identity" }, label: "๐ŸŒ™ A-identity", token: "success", word: "leader" }, { state: { paired: false, processing: true, processingStatus: "queued", queuedStatus: " +1" }, label: "telegram", token: "warning", word: "awaiting pairing", queued: " +1" }, ]; for (const { state, label, token, word, queued } of cases) { const text = buildTelegramStatusBarText(statusBarTheme, { ...base, ...state }); const expected = new RegExp( `^${escapeRegExp(label)} <${token}>\\S+ ${word}${queued ? `${escapeRegExp(queued)}` : ""}`, ); assert.match(text, expected, JSON.stringify(state)); } assert.match( buildTelegramStatusBarText(statusBarTheme, { ...base, error: "typing failed", }), /^telegram<\/accent> \S+ error<\/error> typing failed<\/muted>$/, ); }); test("Status bar shows bot, message counters and last activity only while the bridge is up", () => { const lastAtMs = new Date(2026, 9, 1, 14, 32).getTime(); const connected = { hasBotToken: true, pollingActive: true, paired: true, compactionInProgress: false, processing: false, queuedStatus: "", botUsername: "demo_bot", traffic: { received: 12, sent: 11, lastAtMs }, }; const up = plainStatusText(buildTelegramStatusBarText(statusBarTheme, connected)); assert.match(up, /connected/); assert.match(up, /@demo_bot/); assert.match(up, /12 \S*11/); assert.match(up, /14:32/); const withoutActivity = plainStatusText( buildTelegramStatusBarText(statusBarTheme, { ...connected, traffic: { received: 0, sent: 0 }, }), ); assert.match(withoutActivity, /0 \S*0/); assert.doesNotMatch(withoutActivity, /\d\d:\d\d/); const working = plainStatusText( buildTelegramStatusBarText(statusBarTheme, { ...connected, processing: true, processingStatus: "active", }), ); assert.match(working, /active/); assert.match(working, /@demo_bot/); assert.match(working, /12 \S*11/); const offline = plainStatusText( buildTelegramStatusBarText(statusBarTheme, { ...connected, pollingActive: false }), ); assert.doesNotMatch(offline, /@demo_bot|14:32/); assert.match(offline, /disconnected/); }); test("Status bar tells the operator how to leave a non-working state", () => { const base = { hasBotToken: true, pollingActive: false, paired: true, compactionInProgress: false, processing: false, queuedStatus: "", }; assert.match( plainStatusText(buildTelegramStatusBarText(statusBarTheme, { ...base, hasBotToken: false, paired: false })), /\/telegram-setup/, ); const pairing = plainStatusText( buildTelegramStatusBarText(statusBarTheme, { ...base, paired: false, botUsername: "demo_bot" }), ); assert.match(pairing, /\/start/); assert.match(pairing, /@demo_bot/); assert.match( plainStatusText(buildTelegramStatusBarText(statusBarTheme, base)), /\/telegram-connect/, ); }); test("Status bar follows the host symbol preset and falls back without one", () => { const state = { hasBotToken: true, pollingActive: true, paired: true, compactionInProgress: false, processing: false, queuedStatus: "", botUsername: "demo_bot", traffic: { received: 3, sent: 2, lastAtMs: new Date(2026, 9, 1, 9, 5).getTime() }, }; const ascii = plainStatusText( buildTelegramStatusBarText( { ...statusBarTheme, status: { enabled: "[x]" }, sep: { dot: " - " }, icon: { input: "in:", output: "out:", time: "t:" }, }, state, ), ); assert.equal(ascii, "telegram [x] connected - @demo_bot - in:3 out:2 - t: 09:05"); const fallback = plainStatusText(buildTelegramStatusBarText(statusBarTheme, state)); assert.match(fallback, /^telegram \S+ connected ยท @demo_bot ยท \S*3 \S*2 ยท \S+ 09:05$/u); }); test("Status runtime updates the status bar and exposes bridge lines", () => { const events: string[] = []; const ctx = { ui: { theme: { fg: (token: string, text: string) => `<${token}>${text}`, }, setStatus: (key: string, text: string) => { events.push(`${key}:${text}`); }, }, }; const runtime = createTelegramStatusRuntime({ getStatusBarState: (_ctx, error) => ({ hasBotToken: true, pollingActive: true, paired: true, compactionInProgress: false, processing: false, queuedStatus: "", error, }), getBridgeStatusLineState: () => ({ botUsername: "demo_bot", allowedUserId: 7, lockState: "active here", pollingActive: true, lastUpdateId: 10, pendingDispatch: false, compactionInProgress: false, activeToolExecutions: 0, pendingModelSwitch: false, queuedItems: [], recentRuntimeEvents: [], }), }); runtime.updateStatus(ctx, "demo error"); assert.match( events[0], /^telegram:telegram<\/accent> \S+ error<\/error> demo error<\/muted>$/, ); assert.deepEqual(runtime.getStatusLines().slice(0, 3), [ "connection:", "- bot: @demo_bot", "- user: 7", ]); }); test("Status lines expose thread reconciliation state", () => { const lines = buildTelegramBridgeStatusLines({ botUsername: "demo_bot", allowedUserId: 7, pollingActive: true, lastUpdateId: 10, pendingDispatch: false, compactionInProgress: false, activeToolExecutions: 0, pendingModelSwitch: false, queuedItems: [], threadReconciliation: { phase: "cleanup-required", event: "cleanup-required", atMs: 1000, leaderEpoch: 3, pendingProvisionCount: 1, syncActionCount: 2, cleanupActionCount: 1, }, recentRuntimeEvents: [], }); assert.ok(lines.includes("reconciliation:")); assert.ok( lines.includes("- phase: cleanup-required event=cleanup-required epoch=3"), ); assert.ok(lines.includes("- counts: pending=1, sync=2, cleanup=1")); }); test("Status runtime propagates status update failures to safety wrappers", () => { const runtime = createTelegramStatusRuntime({ getStatusBarState: () => ({ hasBotToken: true, pollingActive: true, paired: true, compactionInProgress: false, processing: false, queuedStatus: "", }), getBridgeStatusLineState: () => ({ botUsername: undefined, allowedUserId: undefined, pollingActive: false, lastUpdateId: undefined, pendingDispatch: false, compactionInProgress: false, activeToolExecutions: 0, pendingModelSwitch: false, queuedItems: [], recentRuntimeEvents: [], }), }); assert.throws( () => runtime.updateStatus({ ui: { theme: { fg: (_token: string, text: string) => text }, setStatus: () => { throw new Error("ctx is stale after session reload"); }, }, }), /stale after session/, ); }); test("Status bar processing labels prefer the most specific live state", () => { assert.equal( getTelegramStatusBarProcessingStatus({ hasActiveTurn: true, hasPendingDispatch: true, hasPendingModelSwitch: true, activeToolExecutions: 1, queuedItems: 1, }), "model", ); assert.equal( getTelegramStatusBarProcessingStatus({ hasActiveTurn: true, hasPendingDispatch: false, hasPendingModelSwitch: false, activeToolExecutions: 1, queuedItems: 1, }), "active", ); assert.equal( getTelegramStatusBarProcessingStatus({ hasActiveTurn: false, hasPendingDispatch: false, hasPendingModelSwitch: false, activeToolExecutions: 1, queuedItems: 1, }), "active", ); assert.equal( getTelegramStatusBarProcessingStatus({ hasActiveTurn: false, hasPendingDispatch: true, hasPendingModelSwitch: false, activeToolExecutions: 0, queuedItems: 1, }), "dispatching", ); assert.equal( getTelegramStatusBarProcessingStatus({ hasActiveTurn: false, hasPendingDispatch: false, hasPendingModelSwitch: false, activeToolExecutions: 0, queuedItems: 1, }), "queued", ); }); test("Bridge status runtime stays active while tools run after queue changes", () => { const events: string[] = []; const runtime = createTelegramBridgeStatusRuntime({ getConfig: () => ({ botToken: "token", botUsername: "demo_bot", allowedUserId: 7, }), isPollingActive: () => true, getActiveSourceMessageIds: () => undefined, hasActiveTurn: () => false, hasDispatchPending: () => false, isCompactionInProgress: () => false, getActiveToolExecutions: () => 1, hasPendingModelSwitch: () => false, getQueuedItems: () => [], formatQueuedStatus: () => "", getRecentRuntimeEvents: () => [], }); runtime.updateStatus({ ui: { theme: { fg: (token: string, text: string) => `<${token}>${text}`, }, setStatus: (key: string, text: string) => { events.push(`${key}:${text}`); }, }, }); assert.match( events[0], /^telegram:telegram<\/accent> \S+ active<\/warning>/, ); }); test("Bridge status runtime builds status state from live ports", () => { const events: string[] = []; const runtime = createTelegramBridgeStatusRuntime({ getConfig: () => ({ botToken: "token", botUsername: "demo_bot", allowedUserId: 7, lastUpdateId: 99, }), isPollingActive: () => true, getActiveSourceMessageIds: () => [1, 2], hasActiveTurn: () => false, hasDispatchPending: () => true, isCompactionInProgress: () => false, getActiveToolExecutions: () => 3, hasPendingModelSwitch: () => true, getQueuedItems: () => [{ queueLane: "control" as const }], formatQueuedStatus: () => " +1", getRecentRuntimeEvents: () => [ { at: 1000, category: "api", message: "ok" }, ], getRuntimeLockState: () => "active here", }); runtime.updateStatus({ ui: { theme: { fg: (token: string, text: string) => `<${token}>${text}`, }, setStatus: (key: string, text: string) => { events.push(`${key}:${text}`); }, }, }); assert.match( events[0], /^telegram:telegram<\/accent> \S+ active<\/warning> \+1<\/success>/, ); assert.deepEqual(runtime.getStatusLines(), [ "connection:", "- bot: @demo_bot", "- user: 7", "- owner: active here", "", "health:", "- polling: running", "- state: pending dispatch", "- queued turns: 1 (control=1, priority=0, default=0)", "- active tools: 3", "- pending model switch: yes", "", "diagnostics:", "- state: ~/.pi/agent/tmp/telegram/state.json", "- logs: ~/.pi/agent/tmp/telegram/logs.jsonl", "- full dump: /telegram-status --debug", ]); }); test("Bridge status lines render named-profile diagnostic paths", () => { const lines = buildTelegramBridgeStatusLines({ activeProfileName: "work", botUsername: "work_bot", pollingActive: false, pendingDispatch: false, compactionInProgress: false, activeToolExecutions: 0, pendingModelSwitch: false, queuedItems: [], recentRuntimeEvents: [], }); assert.ok( lines.includes("- state: ~/.pi/agent/tmp/telegram/state.work.json"), ); assert.ok( lines.includes("- logs: ~/.pi/agent/tmp/telegram/logs.work.jsonl"), ); }); test("Bridge status lines distinguish unknown bot identity from missing config", () => { const base = { allowedUserId: 42, pollingActive: true, lastUpdateId: 100, pendingDispatch: false, compactionInProgress: false, activeToolExecutions: 0, pendingModelSwitch: false, queuedItems: [], recentRuntimeEvents: [], }; assert.equal( buildTelegramBridgeStatusLines({ ...base, hasBotToken: true })[1], "- bot: unknown", ); assert.equal( buildTelegramBridgeStatusLines({ ...base, hasBotToken: false })[1], "- bot: not configured", ); }); test("Bridge status lines include role and instance thread name", () => { const lines = buildTelegramBridgeStatusLines({ botUsername: "demo_bot", allowedUserId: 42, busRole: "leader", instanceSlot: "A", instanceThreadName: "A-identity", pollingActive: true, lastUpdateId: 100, pendingDispatch: false, compactionInProgress: false, activeToolExecutions: 0, pendingModelSwitch: false, queuedItems: [], recentRuntimeEvents: [], }); assert.deepEqual(lines.slice(0, 5), [ "connection:", "- bot: @demo_bot", "- user: 42", "- role: leader", "- instance: A-identity", ]); }); test("Bridge status lines include sync slice diagnostics", () => { const lines = buildTelegramBridgeStatusLines( { botUsername: "demo_bot", allowedUserId: 42, pollingActive: true, lastUpdateId: 100, pendingDispatch: false, compactionInProgress: false, activeToolExecutions: 0, pendingModelSwitch: false, queuedItems: [], syncState: { "topic-state": { status: "fresh", updatedAtMs: 2000, lastReconcileAction: "topic-lifecycle", }, "transport-health": { status: "suspect", suspectAtMs: 3000, reason: "rate limited", }, }, recentRuntimeEvents: [], }, { verbose: true }, ); assert.ok(lines.includes("sync:")); assert.ok(lines.includes("- topic-state: fresh reconcile=topic-lifecycle")); assert.ok(lines.includes("- transport-health: suspect reason=rate limited")); }); test("Bridge status lines include bot thread capability diagnostics", () => { const lines = buildTelegramBridgeStatusLines( { botUsername: "demo_bot", allowedUserId: 42, botThreadMode: "disabled", botThreadModeAction: "thread-mode-unavailable", pollingActive: true, lastUpdateId: 100, pendingDispatch: false, compactionInProgress: false, activeToolExecutions: 0, pendingModelSwitch: false, queuedItems: [], recentRuntimeEvents: [], }, { verbose: true }, ); assert.ok( lines.includes("- thread mode: disabled reconcile=thread-mode-unavailable"), ); }); test("Bridge status lines include topic binding diagnostics", () => { const lines = buildTelegramBridgeStatusLines( { botUsername: "demo_bot", allowedUserId: 42, pollingActive: true, lastUpdateId: 100, pendingDispatch: false, compactionInProgress: false, activeToolExecutions: 0, pendingModelSwitch: false, queuedItems: [], topicTargets: [ { instanceId: "inst-a", status: "active", target: { chatId: 42, threadId: 10 }, slot: "B", threadName: "Beacon", syncStatus: "open", lastSyncObservedAtMs: 1000, lastSyncProbeAtMs: 2000, lastReconcileAction: "leader-startup-probe", }, { instanceId: "inst-a", status: "starting", target: { chatId: 42, threadId: 11 }, slot: "C", threadName: "Cedar", }, { instanceId: "inst-b", status: "offline", slot: "D" }, ], threadReservations: [ { instanceId: "old-leader", target: { chatId: 42, threadId: 9 }, slot: "A", reason: "previous-process-still-probes-alive", lastReconcileAction: "leader-topic-previous-instance-still-live", }, ], topicSyncObservations: [ { instanceId: "closed-inst", target: { chatId: 42, threadId: 8 }, slot: "D", syncStatus: "closed", observedAtMs: 3000, lastReconcileAction: "mark-stale", }, ], recentRuntimeEvents: [], }, { verbose: true }, ); assert.deepEqual(lines.slice(18, 21), [ "topics:", "- active bindings: instances=1, targets=2", "- duplicate inst-a: 2 active threads Beacon target 42:10, Cedar target 42:11", ]); assert.ok( lines.includes( "- Beacon target 42:10 sync=open observed=1970-01-01T00:00:01.000Z probed=1970-01-01T00:00:02.000Z reconcile=leader-startup-probe", ), ); assert.ok(lines.includes("- Cedar target 42:11")); assert.ok( lines.includes( "- reservation [A] target 42:9 reason=previous-process-still-probes-alive instance=old-leader reconcile=leader-topic-previous-instance-still-live", ), ); assert.ok( lines.includes( "- sync [D] target 42:8 sync=closed observed=1970-01-01T00:00:03.000Z instance=closed-inst reconcile=mark-stale", ), ); }); test("Bridge status lines include bus follower diagnostics when present", () => { const lines = buildTelegramBridgeStatusLines( { botUsername: "demo_bot", allowedUserId: 42, pollingActive: true, lastUpdateId: 100, pendingDispatch: false, compactionInProgress: false, activeToolExecutions: 0, pendingModelSwitch: false, queuedItems: [], busNowMs: 20_000, busFollowers: [ { instanceId: "inst-a", cwd: "/repo/a", lastHeartbeatMs: 18_600, target: { chatId: -1007, threadId: 42 }, threadName: "Ember", }, { instanceId: "inst-b", lastHeartbeatMs: 12_000 }, ], recentRuntimeEvents: [], }, { verbose: true }, ); assert.deepEqual(lines.slice(19, 24), [ "bus:", "- followers: 2", "- inst-a: Ember heartbeat 1s ago target -1007:42 /repo/a", "- inst-b: heartbeat 8s ago", "", ]); }); test("Bridge status lines include local bus diagnostics", () => { const lines = buildTelegramBridgeStatusLines( { botUsername: "demo_bot", allowedUserId: 42, pollingActive: false, pendingDispatch: false, compactionInProgress: false, activeToolExecutions: 0, pendingModelSwitch: false, queuedItems: [], localBus: { leaderSocketPath: "\\\\.\\pipe\\pi-telegram-demo-bus", leaderTransport: "pipe", followerSocketPath: "\\\\.\\pipe\\pi-telegram-demo-follower", followerTransport: "pipe", followerRegistered: true, followerTarget: { chatId: 42, threadId: 9 }, followerThreadName: "Boreal", }, recentRuntimeEvents: [], }, { verbose: true }, ); assert.ok(lines.includes("local bus:")); assert.ok(lines.includes("- follower registered: yes Boreal target 42:9")); assert.ok( lines.includes( "- leader endpoint [pipe]: \\\\.\\pipe\\pi-telegram-demo-bus", ), ); assert.ok( lines.includes( "- follower endpoint [pipe]: \\\\.\\pipe\\pi-telegram-demo-follower", ), ); }); test("Bridge status lines include queue lanes and recent runtime events", () => { const lines = buildTelegramBridgeStatusLines( { botUsername: "demo_bot", allowedUserId: 42, pollingActive: true, lastUpdateId: 100, activeSourceMessageIds: [7, 8], pendingDispatch: true, compactionInProgress: false, activeToolExecutions: 2, pendingModelSwitch: true, queuedItems: [ { queueLane: "control" }, { queueLane: "priority" }, { queueLane: "default" }, { queueLane: "default" }, ], recentRuntimeEvents: [ { at: 1, category: "api:sendMessage", message: "rate limited" }, ], }, { verbose: true }, ); assert.deepEqual(lines, [ "connection:", "- bot: @demo_bot", "- allowed user: 42", "", "polling:", "- state: running", "- last update id: 100", "", "execution:", "- active turn: 7,8", "- pending dispatch: yes", "- compaction: idle", "- active tools: 2", "- pending model switch: yes", "", "queue:", "- queued turns: 4", "- lanes: control=1, priority=1, default=2", "", "recent runtime events:", "- summary: api:sendMessage=1", "- 1970-01-01T00:00:00.001Z api:sendMessage: rate limited", ]); }); test("Status HTML builder binds active model lookup", () => { const model = { provider: "openai", id: "gpt-5", contextWindow: 1000 }; const buildStatusHtml = createTelegramStatusHtmlBuilder({ getActiveModel: () => model, }); const html = buildStatusHtml({ sessionManager: { getEntries: () => [] }, getContextUsage: () => ({ percent: 0, contextWindow: undefined }), isIdle: () => true, modelRegistry: { isUsingOAuth: () => false }, }); assert.match(html, /Status.*idle/s); assert.match(html, /Context.*0\.0%\/1\.0k/s); }); test("Status HTML builder appends Threaded Mode bus role to status row", () => { const buildStatusHtml = createTelegramStatusHtmlBuilder({ getActiveModel: () => undefined, getBridgeStatusLineState: () => ({ hasBotToken: true, botThreadMode: "enabled", busRole: "leader", instanceThreadName: "Dune", pollingActive: true, pendingDispatch: false, compactionInProgress: false, activeToolExecutions: 0, pendingModelSwitch: false, queuedItems: [], recentRuntimeEvents: [], }), }); const html = buildStatusHtml({ sessionManager: { getEntries: () => [] }, getContextUsage: () => ({ percent: 0, contextWindow: 1000 }), isIdle: () => true, modelRegistry: { isUsingOAuth: () => false }, }); assert.match(html, /Status.*idle @leader/s); assert.doesNotMatch(html, /Telegram/s); }); test("Status HTML builder includes extension-provided status lines", () => { clearTelegramStatusLineProviders(); const unregisterCodex = registerTelegramStatusLineProvider( ({ activeModel }) => activeModel?.contextWindow === 1000 ? { label: "codex", value: "โ–ˆโ–ˆโ–ˆโ–ˆ 23.7h" } : undefined, { id: "@scope/codex" }, ); const unregisterBroken = registerTelegramStatusLineProvider( () => { throw new Error("optional provider failed"); }, { id: "@scope/broken" }, ); try { const buildStatusHtml = createTelegramStatusHtmlBuilder({ getActiveModel: () => ({ contextWindow: 1000 }), }); const html = buildStatusHtml({ sessionManager: { getEntries: () => [] }, getContextUsage: () => ({ percent: 0, contextWindow: undefined }), isIdle: () => true, modelRegistry: { isUsingOAuth: () => false }, }); assert.match(html, /Context.*0\.0%\/1\.0k/s); assert.match(html, /Codex.*โ–ˆโ–ˆโ–ˆโ–ˆ 23\.7h/s); } finally { unregisterCodex(); unregisterBroken(); clearTelegramStatusLineProviders(); } }); test("Status HTML builder leaves compaction lifecycle to Pi", () => { const buildStatusHtml = createTelegramStatusHtmlBuilder({ getActiveModel: () => undefined, isCompactionInProgress: () => true, }); const html = buildStatusHtml({ sessionManager: { getEntries: () => [] }, getContextUsage: () => ({ percent: 0, contextWindow: 1000 }), isIdle: () => true, modelRegistry: { isUsingOAuth: () => false }, }); assert.match(html, /Status.*idle/s); assert.doesNotMatch(html, /compacting/); }); test("Runtime event lines render the recent-event ring newest first", () => { assert.deepEqual(buildTelegramRuntimeEventLines([]), [ "recent runtime events: none", ]); assert.deepEqual( buildTelegramRuntimeEventLines([ { at: 0, category: "poll", message: "started" }, { at: 1000, category: "api:sendMessage", message: "rate limited" }, ]), [ "recent runtime events:", "- summary: api:sendMessage=1, poll=1", "- 1970-01-01T00:00:01.000Z api:sendMessage: rate limited", "- 1970-01-01T00:00:00.000Z poll: started", ], ); }); test("Structured runtime event recording redacts messages and details", () => { const events: TelegramRuntimeEvent[] = []; recordStructuredTelegramRuntimeEvent( events, { category: "api", error: new Error("token 123:abc failed"), details: { method: "sendMessage", token: "123:abc", retryable: true }, }, { botToken: "123:abc", maxEvents: 3, now: 1000 }, ); assert.deepEqual(events, [ { at: 1000, category: "api", message: "token failed", details: { method: "sendMessage", token: "", retryable: true, }, }, ]); assert.deepEqual(buildTelegramRuntimeEventLines(events), [ "recent runtime events:", "- summary: api:sendMessage=1", '- 1970-01-01T00:00:01.000Z api:sendMessage: token failed (token="", retryable=true)', ]); }); test("Runtime event recording bounds messages and string details", () => { const events: TelegramRuntimeEvent[] = []; recordStructuredTelegramRuntimeEvent( events, { category: "handler", error: new Error("x".repeat(1200)), details: { output: "y".repeat(1200) }, }, { maxEvents: 3, now: 1000 }, ); assert.equal(events[0]?.message.length, 1023); assert.match(events[0]?.message ?? "", /truncated 200 chars/); assert.equal(String(events[0]?.details?.output).length, 1023); assert.match(String(events[0]?.details?.output), /truncated 200 chars/); }); test("Runtime event recorder owns redacted bounded event state", () => { const recorder = createTelegramRuntimeEventRecorder({ getBotToken: () => "123:abc", maxEvents: 1, now: () => 1000, }); recorder.record("api", new Error("token 123:abc failed"), { method: "sendMessage", }); recorder.record("poll", "ok"); assert.deepEqual(recorder.getEvents(), [ { at: 1000, category: "poll", message: "ok" }, ]); recorder.clear(); assert.deepEqual(recorder.getEvents(), []); }); test("Runtime event recording redacts bot tokens and keeps a bounded ring", () => { const events: TelegramRuntimeEvent[] = []; recordTelegramRuntimeEvent(events, "one", new Error("token 123:abc failed"), { botToken: "123:abc", maxEvents: 3, now: 1, }); assert.deepEqual(events, [ { at: 1, category: "one", message: "token failed" }, ]); recordTelegramRuntimeEvent(events, "two", "plain", { botToken: "123:abc", maxEvents: 3, now: 2, }); recordTelegramRuntimeEvent(events, "three", "last", { botToken: "123:abc", maxEvents: 2, now: 3, }); assert.deepEqual(events, [ { at: 2, category: "two", message: "plain" }, { at: 3, category: "three", message: "last" }, ]); });