/** * 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, getTelegramTopStatusSegment, 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, []); }); test("Status bar text renders bridge connection and queue states", () => { const theme = { fg: (token: string, text: string) => `<${token}>${text}`, }; assert.equal( buildTelegramStatusBarText(theme, { hasBotToken: false, pollingActive: false, paired: false, compactionInProgress: false, processing: false, queuedStatus: "", }), "telegram not configured", ); assert.equal( buildTelegramStatusBarText(theme, { hasBotToken: true, pollingActive: true, paired: true, compactionInProgress: false, processing: true, queuedStatus: " +1", }), "telegram active +1", ); assert.equal( buildTelegramStatusBarText(theme, { hasBotToken: true, pollingActive: true, paired: true, compactionInProgress: false, processing: true, processingStatus: "dispatching", queuedStatus: " +1", }), "telegram active +1", ); assert.equal( buildTelegramStatusBarText(theme, { hasBotToken: true, pollingActive: true, paired: true, compactionInProgress: false, processing: true, processingStatus: "active", queuedStatus: "", }), "telegram active", ); assert.equal( buildTelegramStatusBarText(theme, { hasBotToken: true, pollingActive: true, paired: true, compactionInProgress: true, processing: false, queuedStatus: "", }), "telegram connected", ); assert.equal( buildTelegramStatusBarText(theme, { hasBotToken: true, pollingActive: true, paired: true, compactionInProgress: true, processing: true, processingStatus: "active", queuedStatus: "", }), "telegram active", ); assert.equal( buildTelegramStatusBarText(theme, { hasBotToken: true, pollingActive: false, paired: true, instanceThreadName: "Aurora", compactionInProgress: false, processing: true, processingStatus: "queued", queuedStatus: " +2", }), "telegram disconnected +2", ); assert.equal( buildTelegramStatusBarText(theme, { hasBotToken: true, pollingActive: false, paired: true, busRole: "follower", compactionInProgress: false, processing: false, queuedStatus: "", }), "telegram follower", ); assert.equal( buildTelegramStatusBarText(theme, { hasBotToken: true, pollingActive: false, paired: true, busRole: "follower", instanceThreadName: "Amber", compactionInProgress: false, processing: true, processingStatus: "active", queuedStatus: "", }), "Amber active", ); assert.equal( buildTelegramStatusBarText(theme, { hasBotToken: true, pollingActive: false, paired: true, busRole: "follower", busLifecyclePhase: "electing", compactionInProgress: false, processing: false, queuedStatus: "", }), "telegram electing", ); assert.equal( buildTelegramStatusBarText(theme, { hasBotToken: true, pollingActive: false, paired: true, busLifecyclePhase: "electing", compactionInProgress: false, processing: false, queuedStatus: "", }), "telegram electing", ); assert.equal( buildTelegramStatusBarText(theme, { hasBotToken: true, pollingActive: false, paired: true, busRole: "follower", instanceThreadName: "Follower", compactionInProgress: false, processing: false, queuedStatus: "", }), "telegram follower", ); assert.equal( buildTelegramStatusBarText(theme, { hasBotToken: true, pollingActive: false, paired: true, busRole: "follower", instanceThreadName: "Lname", compactionInProgress: false, processing: false, queuedStatus: "", }), "Lname follower", ); assert.equal( buildTelegramStatusBarText(theme, { hasBotToken: true, pollingActive: false, paired: true, busRole: "follower", instanceSlot: "O", instanceThreadName: "extensions Follower", compactionInProgress: false, processing: false, queuedStatus: "", }), "extensions Follower follower", ); assert.equal( buildTelegramStatusBarText(theme, { hasBotToken: true, pollingActive: false, paired: true, busRole: "follower", instanceSlot: "O", instanceThreadName: "Oname", compactionInProgress: false, processing: false, queuedStatus: "", }), "Oname follower", ); assert.equal( buildTelegramStatusBarText(theme, { hasBotToken: true, pollingActive: true, paired: true, busRole: "leader", compactionInProgress: false, processing: false, queuedStatus: "", }), "telegram leader", ); assert.equal( buildTelegramStatusBarText(theme, { hasBotToken: true, pollingActive: true, paired: true, busRole: "leader", instanceThreadName: "🌙 A-identity", compactionInProgress: false, processing: false, queuedStatus: "", }), "🌙 A-identity leader", ); assert.equal( buildTelegramStatusBarText(theme, { hasBotToken: true, pollingActive: true, paired: false, compactionInProgress: false, processing: true, processingStatus: "queued", queuedStatus: " +1", }), "telegram awaiting pairing +1", ); assert.equal( buildTelegramStatusBarText(theme, { hasBotToken: true, pollingActive: true, paired: true, compactionInProgress: false, processing: false, queuedStatus: "", error: "typing failed", }), "telegram error typing failed", ); }); 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.equal( events[0], "telegram:telegram error demo error", ); assert.deepEqual(runtime.getStatusLines().slice(0, 3), [ "connection:", "- bot: @demo_bot", "- user: 7", ]); }); test("Status runtime publishes the polling state after cost", () => { const published: Array<[string, string, { placement: "after-cost" }]> = []; let pollingActive = true; const runtime = createTelegramBridgeStatusRuntime({ getConfig: () => ({ botToken: "token", allowedUserId: 7 }), isPollingActive: () => pollingActive, getActiveSourceMessageIds: () => undefined, hasActiveTurn: () => false, hasDispatchPending: () => false, isCompactionInProgress: () => false, getActiveToolExecutions: () => 0, hasPendingModelSwitch: () => false, getQueuedItems: () => [], formatQueuedStatus: () => "", getRecentRuntimeEvents: () => [], setStatusSegment: (_ctx, key, text) => { published.push([key, text, { placement: "after-cost" }]); }, }); const ctx = { ui: { theme: { fg: (_token: string, text: string) => text }, setStatus: () => {}, }, }; assert.equal( getTelegramTopStatusSegment({ pollingActive: true }), "Telegram: conectado", ); runtime.updateStatus(ctx); assert.deepEqual(published.pop(), [ "telegram", "Telegram: conectado", { placement: "after-cost" }, ]); pollingActive = false; assert.equal( getTelegramTopStatusSegment({ pollingActive: false }), "Telegram: desconectado", ); runtime.updateStatus(ctx); assert.deepEqual(published.pop(), [ "telegram", "Telegram: desconectado", { placement: "after-cost" }, ]); }); 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.equal( events[0], "telegram:telegram active", ); }); 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.equal( events[0], "telegram:telegram active +1", ); 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" }, ]); });