Skip to content

Latest commit

 

History

History
605 lines (460 loc) · 128 KB

File metadata and controls

605 lines (460 loc) · 128 KB

Changelog

0.19.3: Extension Catalogue Image Hotfix

  • [Package] Updated the Pi extension catalogue image URL from the missing screenshot.png to the packaged banner.png. Impact: Pi extension catalogue listings can render the working banner image for pi-telegram.

0.19.2: Draft And Rendering Isolation Hotfix

  • [Config] Grouped assistant answer output under assistant: { rendering, draftPreviews }, while still reading and cleaning up legacy assistantRendering, draftPreviews, and richDraftPreviews. Impact: config vocabulary now matches the feature boundary; draft visibility and final rendering live together without implying that previews are inherently Rich Markdown.
  • [Preview] Hard-gated preview state creation behind the Draft previews setting. Impact: when Draft previews are off, message_start / message_update cannot create or flush draft frames; Telegram should show only native active status until the final answer.
  • [Preview] Aligned enabled draft previews with the selected final renderer: assistant.rendering: "rich" uses sendRichMessageDraft, while assistant.rendering: "html" uses legacy sendMessageDraft with HTML. Impact: the visible draft no longer morphs from Native Rich Markdown into legacy HTML at finalization.
  • [Rendering] Removed the thread-reply special case that forced anchored thread assistant replies through legacy Markdown-to-HTML. Impact: assistant.rendering: "rich" now uses native Rich Markdown for final assistant replies in Threaded Mode too, while assistant.rendering: "html" remains the only path that selects legacy HTML rendering.
  • [Tests] Updated reply regressions to assert native Rich Markdown delivery for anchored thread replies.

0.19.1: Settings Layer Hotfix

  • [Settings] Split the overloaded Rich Draft setting into two independent controls: Draft previews for live sendRichMessageDraft streaming and Assistant rendering for final-answer delivery mode. Impact: operators can hide/show in-progress drafts without changing how final Markdown is rendered.
  • [Rendering] Added persisted assistantRendering: "rich" | "html", defaulting to Native Rich Markdown and allowing legacy Markdown-to-HTML final assistant replies when selected. Impact: renderer compatibility is explicit instead of being conflated with preview visibility.
  • [Preview] Kept richDraftPreviews as the stored draft-preview flag for compatibility, but renamed the Settings UI to Draft previews. Impact: existing configs keep working while the product vocabulary moves toward the preview feature boundary.
  • [Validation] Updated menu/settings/reply regressions for the two-axis configuration model.

0.19.0: Telegram Companion Hub

  • [Context] Defined Rich Markdown as the model-answer membrane: complete assistant/guest model replies use native Rich Message delivery, while tool rows, reasoning/thinking blocks, menus, status, queue controls, settings, diagnostics, and other harness-owned surfaces stay on explicit Telegram HTML/plain rendering.
  • [Settings] Added an opt-in richDraftPreviews setting, exposed it in Telegram Settings, and gated sendRichMessageDraft preview frames behind it while preserving final native Rich Markdown replies. Impact: fresh installs default to final-only Rich Markdown plus native active status, and operators can explicitly enable progressive draft drawing when desired.
  • [Backlog] Opened 0.19.0 release preparation and closed the rich draft preview setting task, making final-only Rich Markdown replies the intended baseline and draft previews an opt-in progressive enhancement.
  • [Context] Clarified the README standard: keep the root entrypoint balanced between product positioning and a compact practical feature showcase, avoiding both over-abstract marketing copy and duplicated implementation docs. Impact: future README changes preserve the feature-catalogue value while keeping the surface coherent.
  • [Docs] Reworked the root README as a product-oriented RhythmE entrypoint with clearer hero positioning, install/connect flow, operating model, expanded feature showcase, classic-vs-Threaded Mode comparison, safety boundaries, extension platform summary, and documentation map. Impact: the public entrypoint now explains pi-telegram as a Telegram companion console while preserving a practical catalogue of user-facing capabilities.
  • [Guest Mode] Unauthorized guest-query replies now include the standard denied-action emoji. Impact: the compact Access denied message is easier to recognize in Telegram.

0.18.6: Threaded Mode parity hotfix

  • [Threaded Mode] Follower-routed prompts now record message ownership when the leader forwards them by thread target, and edited messages can route by stored message ownership when Telegram omits thread identity. Impact: later queue-control reactions and queued-prompt edits on the original Telegram message route back to the owning follower instead of being handled by the leader.
  • [Native Activity Status] Follower typing/activity startup now sends one thread-scoped action plus one aggregate action, and the default keepalive cadence is back to 2.5 seconds. Impact: follower ...active status avoids duplicate chat-action bursts that can hit Telegram rate limits.
  • [Threaded Mode] Follower /start can now register the visible bot command menu through the leader bus without a warning before opening the local menu, follower-sent Bot API messages are recorded in the leader's ownership map, and follower message edit/delete calls used by menu surfaces are allowed as validated same-chat message operations. Impact: follower menu callbacks and interactive cleanup route back to the owning follower even when Telegram callback payloads omit thread identity, without false bus-allowlist failures.
  • [Threaded Mode] Follower promotion now snapshots the current follower thread binding before clearing registration state and converts that binding into the leader profile before forced lock acquisition. Impact: an elected follower keeps its existing thread identity across promotion and later reload instead of becoming disconnected or provisioning a fresh leader thread.
  • [Threaded Mode] Follower registration now probes a reused same-profile thread with the connected notice before reporting it as reusable, and recreates the thread when Telegram reports the old target as stale. Impact: reconnecting a follower after its Telegram tab was closed no longer leaves the terminal showing a follower thread name while no matching Telegram thread is visible.
  • [Threaded Mode] Unbound-thread reroute controls now expose replace/restore for the current live bus roster instead of requiring prior leader reroute confirmation. Impact: when a new unbound Telegram thread appears, the operator can choose any currently live leader/follower instance to route to or replace/restore into that source thread.
  • [Status] Follower terminal status now gives active/compacting processing labels precedence over the stable follower role, matching leader behavior. Impact: a follower shows its thread name plus active while processing a Telegram-originated prompt, then returns to follower when idle.
  • [Threaded Mode] Reload-time target ownership now classifies only follower-owned records as follower targets and replaces stale same-profile/same-target follower registry entries on registration. Impact: after leader or follower reload, Telegram prompts and reroutes no longer get forwarded to dead instance ids or report a live thread as unavailable.
  • [Validation] Live Linux Threaded Mode smoke now passes for post-reload leader/follower prompt routing, unbound reroute/restore, and leader/follower terminal Active status. Impact: the hotfix candidate has Telegram-client evidence for the regressions fixed after 0.18.5.
  • [Docs] Added a leader/follower capability parity matrix covering prompts, queue reactions, edits, callbacks, replies, previews, attachments, native activity, command/menu bootstrap, and diagnostics. Impact: follower behavior now has an explicit parity checklist instead of being inferred from leader behavior.
  • [Engineering] Formalized an AGENTS.md compliance pass for non-trivial work and cleaned unused runtime/lifecycle test surfaces surfaced by strict no-unused diagnostics. Impact: future changes have an explicit project-rule audit step, and dead-code diagnostics stay actionable.

0.18.5: Windows Threaded Mode stabilization hotfix

  • [Bus Transport] Introduced an explicit local bus transport boundary for endpoint derivation, socket-vs-pipe detection, operation-aware retry policy, timeout/transient IPC error classification, endpoint reachability probes, request-scoped server/client transport events, and handler-failure ACKs instead of silent client timeouts. Impact: Unix socket behavior remains the stable baseline while Windows named-pipe readiness and retry behavior are contained in the transport layer instead of leaking into routing.
  • [Windows IPC] Leader-side forwarding now tolerates a pruned follower registry entry by using the follower's deterministic receiver endpoint, the default follower prune window is more conservative, and /telegram-status --debug identifies local bus endpoints as pipes or sockets. Impact: follower threads that already connected are less likely to fall back to not connected to the Telegram bus yet during Windows named-pipe heartbeat jitter, and diagnostics expose the active transport contour directly.
  • [Capability Switching] Live Threaded Mode downgrade now blocks follower takeover while active thread bindings prove the bot is degrading from a live leader/follower organism, confirms disabled thread capability after two 2.5-second monitor probes, retries classic polling restore after transient failures, and clears the in-memory follower registry when bus leadership stops. Impact: when BotFather disables private-chat threads, the current bus leader keeps the classic singleton polling role and followers disconnect instead of stealing ownership or lingering as a live bus roster.
  • [Diagnostics] Runtime JSONL reset now preserves the previous session log as logs.previous.jsonl and records that path in the new reset line. Impact: /reload no longer destroys the best evidence for long-running /start, menu, polling, queue, or bus stalls immediately before restart.
  • [Previews] Native rich Markdown previews no longer send syntax-only prefixes such as a bare opening **, while keeping the native draft/final lifecycle otherwise unchanged and removing unused throttle/manual-clear branches. Impact: Telegram avoids malformed early preview fragments without extra delivery policy that can create duplicate, stalled, or placeholder draft artifacts.
  • [Validation] Native Windows smoke passed for classic mode, classic ownership handoff, hot upgrade to Threaded Mode, leader/follower registration and delivery, and hot downgrade back to classic with follower disconnect. Impact: the named-pipe and capability-switching fixes have live evidence across both directions, with classic restore/status convergence inside the intended 5–15 second fallback window.

0.18.4: Windows Threaded Mode hotfix

  • [Windows IPC] Follower registration now retries transient local bus connection failures while the leader named pipe/socket is still coming online. Impact: a same-directory Windows follower is less likely to fail /telegram-connect with connect ENOENT \\.\\pipe\\... during leader reload or hot Threaded Mode activation.
  • [Queue] A session-bound queue dispatch watchdog now retries dispatch while Telegram work remains queued. Impact: if a platform drops the one-shot deferred dispatch wakeup, queued Telegram messages can resume without waiting for a manual /reload.

0.18.3: Threaded Mode live hotfix

  • [Threaded Mode] Inbound Telegram prompts now request an immediate dispatch and a session-bound deferred retry. Impact: hosts where Pi is not yet dispatch-ready at update handling time no longer need a later /reload or command to process the queued prompt.
  • [Thread Lifecycle] Automatic leader reclaim/reconciliation paths no longer call editForumTopic just to restore internal thread identity, and an unknown unbound thread is no longer auto-claimed by the leader while another live thread target exists. Prompt thread labels now prefer the local live leader/follower target over stale shared thread-store records. Impact: ordinary prompts and voice messages should not produce duplicate Telegram service messages such as renamed the thread to ..., and a same-directory follower thread is less likely to be smeared onto the leader binding or mislabeled in prompts.
  • [Threaded Mode] Follower Bot API authorization now permits safe bot identity reads and chat-level typing/activity within the follower's assigned chat, while preserving thread-scoped write restrictions for messages/files/topic mutation. Impact: forwarded follower updates no longer fail just because native activity/capability paths use the aggregate chat surface.
  • [Status] Leader target assignment now carries the live thread name into status fallback state. Impact: the status bar is less likely to flicker from Dune Leader/Active to generic Telegram Leader when the current active turn or thread-store lookup changes.
  • [Model Menu] The Telegram model menu now hides one-page pagination controls and keeps scope tabs hidden unless scoped models exist. Impact: the minimal model menu shows only main-menu navigation and the available models.

0.18.2: Setup pairing start hotfix

  • [Setup] /telegram-setup now updates the live in-memory config immediately after persisting the validated bot token and before starting polling. Impact: first-time setup no longer shows Send /start... followed by Telegram bot is not configured, and /start can be received without restarting Pi.

0.18.1: Windows setup transport hotfix

  • [Setup] /telegram-setup token validation now uses the same fallback-aware Telegram transport as normal API calls. Impact: Windows/QEMU hosts that fail native fetch during bot-token validation can retry through IPv4 fallback instead of failing before config is saved.
  • [Setup] Token validation transport failures now report a setup error notification instead of escaping as a command failure. Impact: operators get a clear retryable setup failure when Telegram is unreachable.
  • [Docs] Normalized Threaded Mode language across README, architecture docs, prompt guidance, and changelog: Threaded Mode is the mode name, thread is the user-visible Telegram surface, and BotFather is only the bot configuration tool. Impact: release docs no longer imply BotFather owns runtime Threaded Mode behavior.

0.18.0: Threaded Mode

  • [Threaded Mode] Added Telegram private-chat Threaded Mode while keeping classic private DM as the base mode. Threaded Mode is now the bus switch: in ordinary private-DM mode, one Pi session owns the bot; when Telegram exposes threads for the bot, one live leader owns polling/Bot API transport and visible follower Pi processes join explicitly with /telegram-connect. Impact: operators can choose either a simple single-instance bot or a multi-thread development workspace without competing pollers or hidden process spawning.
  • [Capability Switching] Reworked Threaded Mode availability around private-bot evidence: getMe.has_topics_enabled, incoming message_thread_id, and private-thread operation success/failure. A 5-second monitor can hot-upgrade classic mode to Threaded Mode and hot-downgrade back to classic without /reload. Impact: Threaded Mode behaves as a progressive enhancement instead of a startup-only assumption.
  • [Thread Routing] Preserved per-instance ownership for queues, active turns, model/tool state, previews, menus, lifecycle hooks, replies, files, voice, buttons, reactions, and command/control replies. Impact: leader and follower threads behave like scoped Telegram workspaces rather than views over one shared queue.
  • [Thread Lifecycle] Added durable current-state thread bindings with explicit owners, stable slots, compact baked thread names, reservations, and proof-before-delete cleanup through thread-reconciler. Impact: reloads, reconnects, stale tabs, restores, and cleanup avoid duplicate live threads and avoid deleting uncertain targets.
  • [Leader/Follower Recovery] Added recovery for reloads, reconnects, follower heartbeat loss, promotion, explicit disconnect, stale thread cleanup, and same-profile follower resume. Impact: Threaded Mode degrades forward across local process churn while preserving the intended thread binding where possible.
  • [Native Activity Status] Kept Telegram work indication native-only through Bot API sendChatAction(typing) / Telegram client ...active status. Custom progress/activity/thinking message surfaces are not part of the release path. Impact: long-running work uses the Telegram-native affordance instead of adding extra chat noise.
  • [Compaction Activity] Scoped typing to real work: active Telegram turns, tool/reasoning/message activity during those turns, confirmed manual /compact, and automatic compaction only when it belongs to an active Telegram turn. Thread-scoped typing preserves the concrete thread target and mirrors to All as aggregate activity. Impact: compaction shows native activity when it should, without reviving startup/connect/reload typing.
  • [Thread-Scoped Delivery] Propagated { chatId, threadId? } across inbound routing, replies, previews/drafts, typing, voice, attachments, menus, sections, callbacks, reactions, media groups, slash commands, and follower-routed Bot API calls. Impact: classic DM delivery and thread delivery share one target-scoped transport contract.
  • [Replies And Drafts] Anchored the first assistant reply block to the prompting message in Threaded Mode and kept later chunks sequential; preview rollover preserves the active turn's source reply metadata. Telegram Desktop may still omit the visual reply header despite the same correct payload that mobile renders. Impact: thread conversations keep local reply context without stacking headers on every chunk.
  • [Thread UX] Improved unbound-thread reroute/restore flows, cleanup of temporary chooser surfaces, connected/offline notices, status/menu role indicators, and routing controls. Impact: operator-facing Threaded Mode surfaces are more recognizable and less likely to leave stale controls behind.
  • [Proactive Push] Allowed Threaded Mode followers to send successful local non-Telegram final replies through the leader transport when proactivePush is enabled. Impact: follower-owned local results can reach the assigned thread without granting unrelated non-owner processes Telegram delivery.
  • [Agent Responsiveness] Moved successful Telegram turn follow-up delivery work into extension-owned background tasks. Impact: Pi can leave the working state sooner after producing the final answer while preserving Telegram delivery ordering.
  • [Telegram API Transport] Added PI_TELEGRAM_NETWORK_FAMILY=auto|ipv4|ipv6|ipv4-fallback; the default ipv4-fallback retries transport-level dual-stack failures through Node's IPv4-only HTTPS path after native fetch. JSON calls, multipart uploads, and file downloads now share one transport helper with richer redacted diagnostics. Impact: hosts with broken IPv6 can keep polling, typing, drafts, downloads, uploads, and direct tools working without global DNS changes.
  • [Security] Hardened local bus authorization with leader-minted secrets, derived private endpoints, allowed-user checks, target-scoped follower Bot API allowlists, and liveness refreshes around forwarded updates/API calls. Impact: followers can use their assigned thread without gaining arbitrary bot control.
  • [Windows IPC] Added native Windows named-pipe path selection for the local leader/follower bus alongside Unix socket support. Impact: Threaded Mode has an intended native Windows transport path, with live Windows smoke still tracked separately in the backlog.
  • [Diagnostics] Expanded /telegram-status, tmp/telegram/state.json, and redacted tmp/telegram/logs.jsonl around runtime role, roster, capability state, reservations, thread reconciliation, and transport health, without making diagnostics files routing authority. Impact: operators and agents can inspect Threaded Mode health without depending on stale history.
  • [Validation] Split Threaded Mode coverage across focused bus, leader, follower, runtime, integration, routing, lifecycle, and delivery tests. Impact: the release behavior is pinned by domain-owned regressions rather than one oversized integration bucket.
  • [Architecture] Moved Threaded Mode logic out of index.ts into focused domains for bus protocol, leader runtime, follower runtime, thread bindings, synchronization, polling/capability switching, and reconciliation. The separate public telegram.json bus switch was removed from the product model and implementation. Impact: the public surface stays small, classic mode remains the base mode, Telegram private-chat Threaded Mode is the multi-instance switch, and product language consistently says thread while Bot API topics remain implementation details.

0.17.5: Screenshot Refresh

  • [Docs] Refreshed the package screenshot.

0.17.4: Native Rich Markdown Splitter Hotfix

  • [Rich Markdown] Rewrap oversized fenced code, display-math, and fully wrapped inline-formatting blocks when splitting native Rich Markdown at Telegram transport limits. Impact: very long structured Markdown blocks no longer produce invalid partial Rich Markdown chunks, so final assistant replies can stay native without losing long code/math/formatted output.
  • [Tests] Added regressions for oversized fenced code, display math, and inline formatting split behavior. Impact: future native splitter changes must preserve structurally valid chunks beyond Telegram's single-message size limit.

0.17.3: Native Draft Preview Hotfix

  • [Rich Markdown] Normalize multiline display-math blocks written as $$ / content / $$ into Telegram-supported math code fences before native Rich Markdown delivery, while preserving literal delimiters inside code fences. Impact: assistant replies following the Telegram prompt guidance for block formulas no longer risk making the whole Rich Markdown message render as raw Markdown.
  • [Preview] Removed assistant plain-message preview fallback paths; failed native draft frames are recorded and skipped because partial Markdown can be temporarily invalid while the final answer remains valid. Draft delivery now sends only structurally closed Markdown prefixes, holding back unclosed inline spans, links, fenced code, comments, and display-math blocks until a safe boundary exists. Impact: assistant previews stay on Telegram's native Rich Draft API and no longer create raw-Markdown fallback bubbles.
  • [Validation] Live Telegram smoke-tested native draft/final Rich Markdown delivery with sections, lists, code fences, links, $$ display math, and inline buttons after reload. Impact: the 0.17.3 hotfix behavior is verified in the target Telegram client path, not only by local tests.

0.17.2: Indented List Rich Markdown Hotfix

  • [Rich Markdown] Neutralized indented list markers before native Rich Markdown delivery by replacing leading list indentation with non-breaking spaces while preserving top-level list markers. Impact: assistant replies with bold section headers followed by two-space-indented bullets containing slash/hyphen text, with, and inline code no longer render raw Markdown or truncate around the inline-code span.
  • [Preview] Pinned the same normalization path for native draft previews and editable/final Rich Markdown messages. Impact: risky replies use consistent Markdown safety behavior across draft, fallback edit, and final delivery paths.
  • [Tests] Added regression coverage for the discovered formatting-only and truncation-risk fixtures, including payload-tail preservation through native Markdown splitting and send delivery. Impact: future Rich Markdown parser changes are less likely to reintroduce partial Telegram messages.

0.17.1: Rich Markdown Parser Hotfix

  • [Rich Markdown] Normalize Bot-API-fragile source before native Rich Markdown delivery, including space-after-marker blockquotes and dollar-prefixed ticker atoms such as $BLDR / $NTVE, prefer Telegram rich_message blocks over raw text/caption when extracting quoted reply context for prompts, and keep Telegram copyability guidance generic by recommending inline code for short copyable literals. Impact: assistant replies are less likely to render as raw Markdown on Telegram Rich Message parser/client edges, replying to a native Rich Markdown bot message no longer injects raw Markdown source into [reply], and prompts nudge copyable identifiers without ticker-specific bloat.

0.17.0: Native Rich Markdown Delivery

  • [Rich Markdown] Assistant and guest replies now use Telegram-native Rich Message APIs directly: final assistant Markdown goes through sendRichMessage, streaming drafts go through sendRichMessageDraft, editable fallback previews finalize through editMessageText.rich_message, and guest replies use InputRichMessageContent. Impact: model-authored Markdown reaches Telegram as native Rich Markdown instead of passing through the legacy Markdown-to-HTML assistant path.
  • [Preview UX] Streaming preview is now a thin Rich Draft lifecycle controller with serialized flushes, no default debounce, no assistant rendering dependency, and no post-final draft-clear call. Impact: live Telegram clients get smoother draft updates and avoid duplicate final messages, blank finalization gaps, or the transient animated three-dot block observed during draft clearing.
  • [UI Boundary] Bridge-owned commands, menus, status messages, queue controls, buttons, and sections remain explicit Telegram HTML/plain UI by default, while companion sections can opt into Markdown/HTML/plain per view. Impact: native Rich Markdown improves model-authored replies without making hand-authored bot UI harder to maintain.
  • [API And Limits] Added typed Rich Message send/draft helpers, disabled automatic entity detection for assistant/guest Rich Markdown, and split native Markdown at Telegram Rich Message character/block limits while keeping reply metadata on the first chunk and reply markup on the final chunk. Impact: technical output avoids accidental entities and long replies stay within Bot API limits.
  • [Docs And Tests] Added a local Bot API Rich Messages reference, updated README/outbound/public API/sections/architecture/prompt/AGENTS guidance, kept formula prompting compact around $...$ / $$...$$, and added regressions for native delivery, guest replies, preview lifecycle, split replies, and the UI/compat rendering boundary. Impact: the release behavior is documented, covered, and easier to preserve.

0.16.6: Telegram Review Hardening Hotfix

  • [Guest Mode] Deny guest_message updates until the bridge already has a paired Telegram user. Impact: guest mode can no longer become the first pairing surface or trigger guest file/handler processing before explicit DM pairing.
  • [Lifecycle] Unref the compaction observer fallback timer when the host timer supports it. Impact: headless or shutdown paths are less likely to linger until the 5-minute safety timeout.
  • [Shutdown] Stop polling before clearing active-turn/abort state, keep the abort controller visible until the polling promise settles, and record typing-cleanup failures without skipping polling abort. Impact: session shutdown and polling cleanup ordering is more deterministic.
  • [Replies] Scope transport-level reply deduplication by chat id. Impact: equal Telegram message ids in different chats no longer suppress valid reply metadata for each other.
  • [Buttons] Consume one-shot telegram_button callback actions after the first successful resolve. Impact: repeated taps on an old assistant-authored button no longer enqueue duplicate prompts.
  • [Buttons] Centralized Telegram callback_data byte-limit guards for generated inline keyboards outside the section helper path. Impact: oversized generated button callbacks fail locally before Telegram rejects the message.
  • [Diagnostics] Record answerCallbackQuery transport failures in runtime API diagnostics while keeping callback handling non-fatal. Impact: /telegram-status can explain failed Telegram callback acknowledgements instead of losing the signal silently.
  • [Tests] Added regressions for shutdown during pending control, long-text, and media-group dispatch, for settings menu callbacks persisting voice/time changes to telegram.json, for malformed/boundary Markdown rendering, and for runtime outbound delivery retrying a transient Telegram API failure. Impact: high-risk queue/timer/settings/rendering/API paths are pinned at the bridge boundary.
  • [Docs] Documented which environment-driven transport defaults should be set before launch because module-load constants intentionally capture them.
  • [Backlog] Captured and narrowed the non-blocking 2026-06 review-swarm follow-ups for lifecycle shutdown hardening, reply/callback/button state cleanup, validation coverage, and bindings maintainability.

0.16.5: Context-Aware Prompt Guidance Hotfix

  • [Prompt Guidance] Made before-agent-start Telegram guidance context-aware: unconfigured sessions receive no bridge suffix, local/TUI prompts receive only explicit direct-delivery guidance, and Telegram-originated turns keep the full inbound, phone-width, voice, and button contract. Impact: ordinary local replies no longer get raw Telegram action-comment syntax unless the current turn actually comes from Telegram.
  • [Docs] Recorded the product boundary that pi-telegram is a mobile companion for a live Pi session, not a remote terminal, PTY supervisor, or process launcher. Telegram controls should stay within Pi's extension-facing APIs; true session replacement such as Telegram /new should wait for a public Pi hook that preserves interactive runtime and TUI semantics.

0.16.4: Follow-Up And Runtime Mode Hotfix

  • [Runtime] Feature-detect Pi ctx.mode and keep print/json runs passive by blocking polling start/resume in those modes. Impact: CLI/headless sessions can finish local work without inheriting Telegram polling, while tui/rpc and older Pi runtimes keep existing behavior.
  • [Queue] Forward queued Telegram prompts and unknown callback fallbacks to Pi with explicit followUp delivery semantics. Impact: Telegram input keeps the existing non-steering queue contract even when Pi's native streaming-message API requires an explicit busy-run policy.

0.16.3: Ownership And Shutdown Hotfix

  • [Ownership] Lock-gated proactive local/headless final-result push so only the current /telegram-connect owner can send non-Telegram agent-end replies to the paired chat, while accepted Telegram turns and queued work still finalize session-locally after polling ownership moves away. Impact: child/headless/non-owner instances no longer leak unrelated local results into Telegram.
  • [Shutdown] Made polling retry sleep abort-aware, unref()ed non-critical Telegram housekeeping timers, and routed registered session shutdown through the composed lifecycle runtime so session context cleanup runs with queue and polling cleanup. Impact: shutdown and print/headless runs are less likely to stay alive on retry/debounce/typing/preview timers, and direct-delivery ownership context is cleared at the session boundary.
  • [Tests] Added regressions for inherited child lock refusal, child-process no-poll ownership, child-process direct-tool non-owner refusal, proactive owner/non-owner/stale/off states, queued dispatch after lock movement, abort-during-retry polling sleep, process-level session shutdown, and real pi -p exit/no-leak paths with a local custom provider. Impact: the cross-instance ownership, queue, and shutdown contracts are pinned from unit coverage through CLI smoke coverage.
  • [Status] Changed /telegram-status bot identity fallback from not configured to unknown when a bot token exists but the bot username is absent. Impact: live sessions that are paired and polling no longer look unconfigured only because identity metadata is missing.
  • [Docs] Documented ownership, proactive-push, timer/shutdown, and multi-extension prompt-boundary contracts in README and /docs. Impact: companion extensions get clearer boundaries without adding a core question/prompt-mirroring API.

0.16.2: Screenshot Refresh Hotfix

  • [Docs] Refreshed the package screenshot. Impact: npm and repository previews show the current Telegram bridge UI without changing runtime behavior.

0.16.1: Disconnected Queue Status Hotfix

  • [Status] Keep showing the local Telegram queue count in the TUI status bar when polling ownership moves to another Pi instance and the bridge reads as disconnected. Impact: the singleton Telegram control lock can move without hiding pending session-local Telegram prompt work from the original agent.

0.16.0: Telegram Extension Commands

  • [API] Added registerTelegramCommand() on the public /commands subpath so companion extensions can explicitly provide Telegram-native slash commands without adding workflow-specific commands to core. Built-in bridge commands stay reserved, extension command names must be Bot API safe, duplicate extension names are rejected, commands stay hidden unless showInMenu is enabled, visible commands must provide an emoji used in /start help and Bot API descriptions, extension-command descriptions are shown in /start, visible extension commands are inserted after /compact before queue-control commands, prompt-template commands remain separated in /start, handler failures are isolated with runtime diagnostics, and routing precedence is built-ins → extension commands → prompt-template aliases. Impact: workflow-specific controls can live in companion extensions while pi-telegram remains a lightweight Telegram shell.

0.15.1: Typing Keepalive Cadence

  • [Typing Status] Pinned the default native Telegram typing keepalive interval at 2500 ms while preserving the 250 ms idle-drain cap. Impact: runtime behavior matches the intended conservative chat-action cadence.

0.15.0: Companion Status Lines

  • [API] Added registerTelegramStatusLineProvider() on the public /status subpath so companion extensions can append compact rows to the /start menu status text. Providers are synchronous, model-aware, isolated on failure, and rendered with Telegram-style capitalized labels. Impact: quota/status widgets can progressively enhance the Telegram operator menu without owning polling, transport, or core menu rendering.
  • [Docs] Documented the status-line provider with an abstract companion-extension example and listed pi-codex-usage as a companion extension. Impact: the public API docs stay implementation-neutral while the README still points operators to the concrete Codex quota widget.

0.14.0: Direct Telegram Delivery, Queue Semantics, And Section Diagnostics

  • [Prompt Guidance] Tightened agent context for Telegram buttons: use normal Markdown plus top-level hidden telegram_button comments, never JSON button specs or standalone button actions, and keep comments out of code/quotes/lists/indented examples. Impact: agents immediately know how to author visible Telegram text, inline buttons, and direct telegram_message payloads without transport hacks.
  • [Command Templates] Synced lib/command-templates.ts with the current pi-actors standard, including advisory risk labels, actor recipe context metadata, bundled short-flag detection, and fuller trusted-executable mitigation text. Impact: pi-telegram command-template tooling no longer lags the actor recipe/tooling implementation.
  • [Tools] Telegram is now a first-class local delivery target: telegram_attach sends files immediately to the paired/default chat when no Telegram turn is active, and new telegram_message supports explicit local/TUI requests to push Markdown text messages. telegram_message reuses the normal telegram_button comment planner, so direct buttons are authored exactly like ordinary Telegram replies and always attach to a real message. Direct local/TUI delivery is gated by /telegram-connect ownership, while active-turn reply delivery remains session-local. Impact: agents can deliver requested artifacts or notices to Telegram from terminal-originated work without bypassing singleton polling/control ownership.
  • [Status] TUI status now renders compacting with the same warning color used for active, while keeping the telegram domain label accented. Native typing cleanup now gives the last in-flight sendChatAction a short bounded drain before final reply delivery, and the typing keepalive interval is relaxed to 3s while staying below Telegram's typical chat-action TTL. Impact: manual or automatic context compaction reads as active model work, and Telegram typing is less likely to outlive a completed agent turn.
  • [Queue] Telegram queue and reply delivery now stay per Pi instance, independent from the singleton polling/control lock. /abort only enables abort-history preservation for Telegram-owned turns, and local/non-Telegram agent starts clear stale abort-history mode. Impact: moving /telegram-connect no longer silences an already accepted queue, and local prompts after abort no longer fold old queued turns into the next Telegram prompt.
  • [Sections] Section label, render, and callback failures now record source-scoped diagnostics and recover only when the matching surface succeeds. Section diagnostics expose only active/error, and settings-only callbacks keep Settings-level Back navigation. Impact: one broken companion section cannot break menu rendering or hide unrelated diagnostics.

0.13.2: Config Recovery And Inbound Output Bounds Hotfix

  • [Config] Invalid telegram.json now recovers on session startup by renaming the broken file to an .invalid-* recovery path, loading safe empty defaults, and recording a runtime diagnostic. Impact: a hand-edited or partially written config no longer bricks /telegram-setup or session startup.
  • [Inbound] Inbound handler, programmatic handler, voice transcription, and built-in text attachment outputs are now bounded before entering Telegram prompt context. Impact: large OCR, PDF, STT, or text-file outputs cannot silently explode prompt size.
  • [Diagnostics] Runtime event messages/details and inbound handler failure stdout/stderr are truncated before storage/rendering. Impact: /telegram-status remains useful after noisy provider or handler failures without hiding that truncation happened.

0.13.1: Rendering, Typing, And Continue Queue Hotfix

  • [Rendering] Fixed Telegram HTML rendering for Markdown bold/italic spans that cross soft line breaks, so assistant replies like **first line\nsecond line** render as bold text instead of showing raw asterisks. Added a regression for the guest-mode-style multiline bold reply shape.
  • [Typing Status] Hardened assistant message activity hooks so transient preview/provider transport failures are recorded but do not break the native Telegram typing keepalive while an active turn continues.
  • [Continue Queue] /continue now enqueues as a control-lane resume prompt and explicitly clears abort-history mode, so queued Telegram prompts stay separate and the continuation runs ahead of queued prompt work after abort or compaction recovery.

0.13.0: Command Template Standard, Voice Hardening, And Domain Cleanup

  • [Architecture] Extracted outbound assistant-action markup parsing into lib/outbound-markup.ts and removed the temporary Voice/Outbound/Queue import-cycle allowance. Impact: project source imports are fully acyclic again while preserving existing voice and outbound helper exports.
  • [Tests] Updated the Pi SDK centralization invariant to guard the current @earendil-works/* package scope as well as the legacy scope. Impact: new direct SDK imports outside lib/pi.ts are caught again.
  • [Voice Providers] Generated compatibility ids for STT/TTS providers now use monotonic counters with registry probing, and provider disposers now remove only their own registered instance. Impact: anonymous ids stay collision-safe across stale registry entries/module reloads, and stale disposers cannot delete replacement providers.
  • [Security] Telegram temp directories, downloaded inbound files, and locks.json writes now use explicit private filesystem modes. Impact: private attachments and local polling ownership metadata are less exposed on permissive-umask or shared hosts.
  • [Docs] Clarified that voice.sendTranscript is the bridge-owned transcript preference and updated provider examples to gate transcriptText with getTelegramVoiceSendTranscript(config). Impact: companion voice providers no longer need to invent duplicate transcript/reply-policy UI.
  • [Tests] Added a long-session runtime regression that preserves queued work across /abort, explicit /next, and in-flight model switching. Impact: the high-risk queue/dispatch path now has coverage for an operator session that chains abort recovery into model-switch continuation.
  • [Naming] Renamed the concrete Bot API transport domain from lib/api.ts / tests/api.test.ts to lib/telegram-api.ts / tests/telegram-api.test.ts. Impact: the transport owner is clearer and no longer competes conceptually with the public /api/*.ts package membranes.
  • [Status] /telegram-status recent runtime events now include a category summary before the detailed event list. Impact: provider, handler, and transport failure categories are easier to scan during companion-extension diagnostics.
  • [Tests] Added a combined telegram_voice + telegram_button outbound planner smoke regression and corrected the text-group non-contiguous-tail fixture to reflect the widened split-message id gap. Impact: the rendering/markup watchlist now has direct coverage for mixed assistant action markup without changing runtime behavior.
  • [Audit] Added fixture lifecycle coverage for STT/TTS provider re-registration across session-start/resume/reload-style boundaries, and scanned the local workspace for removed @llblab/pi-telegram/lib/* companion imports. Impact: the remaining hotfix lifecycle and migration audit items are now closed in this environment.
  • [Refactor] Split assistant-authored button planning, callback storage, callback handling, and button prompt-turn construction from lib/outbound.ts into lib/outbound-buttons.ts, with symmetric tests/outbound-buttons.test.ts coverage. Impact: the outbound domain is smaller and button behavior now has a direct module-level test peer while existing lib/outbound.ts exports remain compatible.
  • [Tests] Added symmetric tests/outbound-markup.test.ts coverage for lib/outbound-markup.ts, including top-level comment collection, fenced-code exclusion, partial-comment stripping, attribute parsing, and multi-voice planning. Impact: assistant action markup has direct module-level regression coverage instead of relying only on umbrella outbound tests.
  • [Tests] Added symmetric tests/menu-status.test.ts coverage for lib/menu-status.ts, including status reply markup rows, voice-active thinking suppression, callback routing, and status message send/update helpers. Impact: status-menu behavior now has a direct module-level regression peer.
  • [Tests] Added symmetric tests/menu-thinking.test.ts coverage for lib/menu-thinking.ts, including reply markup, thinking-level callbacks, invalid/voice/non-reasoning guards, and menu send/update helpers. Impact: thinking-menu behavior now has direct module-level regression coverage.
  • [Tests] Added symmetric tests/setup.test.ts coverage for lib/setup.ts, including token defaults, prompt mode selection, setup success/failure, and prompt-runtime guard cleanup after errors. Impact: /telegram-setup prompt behavior now has direct module-level regression coverage.
  • [Tests] Added symmetric tests/menu-settings.test.ts coverage for lib/menu-settings.ts, including built-in settings markup, detail menu active states, settings mutations, and stale-message fallback toggles. Impact: settings-menu behavior now has direct module-level regression coverage.
  • [Context] Cleared the completed backlog down to No open work and tightened the lib/outbound.ts domain header after button/markup extraction. Impact: historical completion notes stay in the changelog, while backlog and domain ownership now reflect current reality.
  • [Refactor] Split native Telegram voice delivery from lib/outbound.ts into lib/outbound-voice.ts, with symmetric tests/outbound-voice.test.ts coverage. Impact: outbound voice upload/provider orchestration now has a direct domain owner and lib/outbound.ts is reduced to the outbound surface, command handlers, text transforms, artifact composition, and compatibility re-exports.
  • [Command Templates] Replaced pi-telegram's command-template implementation with the current pi-actors standard as a deliberate breaking 0.x minor change. Impact: templates now use parallel and when, support string timeout/delay/retry, inherited default references, {value??fallback}, {flag?yes:no}, and empty-arg filtering; old local mode, critical, and pipe shapes were removed/migrated to parallel, failure, and template: [...].
  • [Docs] Removed real companion-extension identities from abstract voice-provider examples and README guidance, keeping concrete names only in the explicit Companion Extensions list. Impact: pi-telegram documentation now keeps bridge responsibilities separate from third-party companion-extension ownership.
  • [Docs] Integrated public API smoke examples for Extension Sections, raw updates, inbound handlers, outbound handlers, and voice providers into docs/public-api.md using only stable public membranes. Impact: companion-extension authors get copyable patterns in the canonical public API guide and avoid removed @llblab/pi-telegram/lib/* imports.
  • [Docs] Updated README release positioning and corrected Extension Sections docs so ctx.edit() owns automatic Back-row insertion, ctx.open() is documented as a standalone chat-message sender, and section callbacks appear before built-in menu callbacks. Impact: companion extension authors get an accurate public contract.
  • [Backlog] Restored concrete near-term follow-up slices for public API migration, provider lifecycle, smoke examples, diagnostics, voice-domain DAG cleanup, section examples, and voice transcript config clarity. Impact: README's open-work link points to actionable development priorities again.

0.12.0: Public API Membranes, Telegram UX Safety, And Extension Interop

  • [Typing Status] Auto-compaction now starts and stops the native Telegram typing keepalive like manual /compact, including timeout and shutdown cleanup. Active Telegram turns also re-arm typing on assistant message start/update events so transient provider/model errors cannot permanently leave a continuing run without Telegram activity feedback.
  • [Compaction Safety] Telegram /compact now opens an inline confirmation dialog before manual compaction starts, protecting the operator from accidental taps near /start. The dialog follows the dedicated UI style guide: a bold text-only question with emoji only on the explicit Yes, compact and No buttons. Confirming edits the dialog directly to Compaction started. instead of showing a separate Compaction confirmed. step.
  • [Docs] Added docs/ui-style.md as the focused style guide for inline buttons, toggles, tabs, option lists, cards, and dialogs.
  • [Docs] Restructured docs/architecture.md into a clearer architectural map with runtime topology, domain ownership, core flows, extension surfaces, and operational behavior while pushing detailed UI/callback rules toward focused standards.
  • [Breaking API] Renamed the public implementation domains to lib/sections.ts, lib/updates.ts, lib/inbound.ts, and lib/outbound.ts. Package exports now expose only the stable public API domains (/sections, /updates, /inbound, /outbound, /voice, /keyboard) and no longer expose the compatibility ./lib/*.ts wildcard.
  • [Architecture] Folded the public update-handler interop surface into updates and renamed the internal long-poll loop module back to polling, giving the pair concise one-word domains: updates for update contracts/classification/handler registry and polling for the getUpdates runtime. Entrypoint extraction now lives in bindings, a concrete pi-facing command/tool/lifecycle wiring boundary rather than a new product domain.
  • [Tests] Added an architecture invariant and package self-import regressions that pin the 0.12.0 package exports to stable /api membranes with exact runtime export shapes and prevent accidental restoration of the removed ./lib/*.ts wildcard.
  • [Docs] Added docs/public-api.md as the public API map for commands, config, assistant markup, extension APIs, callback ownership, and public/internal stability boundaries.
  • [API] Hardened Telegram Extension Sections by rejecting duplicate section ids and validating ctx.callbackData() against Telegram's 64-byte callback-data limit.
  • [API] Added registerTelegramUpdateHandler() as the matrix-aligned low-level update bus name.
  • [API] Documented the public low/high-level registration matrix: low-level buses (updates, inbound, outbound) intentionally have no ids, while high-level sections and voice providers use stable ids in new integrations.
  • [Settings UI] Refined control conventions: boolean toggles use Capitalized horizontal On/Off with green active On, yellow active Off, and black inactive markers; state/navigation rows use Capitalized status values; horizontal tabs use capitalized labels with purple default-state and yellow elevated-state active markers; vertical option lists keep only the current value marked green; submenu navigation distinguishes ⬆️ Main menu from deeper ⬆️ Back rows; confirmation actions use explicit Yes, ... labels such as 🗜 Yes, compact; added State & Navigation Buttons section to the style guide for buttons that show state and lead to a submenu.
  • [Config] Time Injection Hidden mode now removes time.injectionMode from telegram.json instead of persisting "hidden", matching Voice Reply Hidden semantics: missing key = default hidden state.

0.11.2: Queue Continuation, Compaction Safety, And Settings Polish

  • [Time Context] Renamed the disabled time injection mode from off to hidden in Settings and config defaults, matching voice reply mode semantics where no prompt-context line is injected. Legacy off callbacks/config values are still treated as hidden.
  • [Settings UI] Settings detail headings now show the current value immediately after the bold label in monospace style, making each submenu title double as the active setting summary.
  • [Entrypoint] Removed root-level API re-exports from index.ts; public extension APIs remain available from their owning lib/* modules while the root file stays a default-only composition root.
  • [Continue Queue] /continue now enqueues a standalone priority prompt without preserving already queued prompts as history. Impact: queued prompts stay iterative queue items instead of being folded into one combined continue prompt.
  • [Auto Compaction] Observes native session_before_compact / session_compact events and blocks queued Telegram prompt dispatch while compaction is running, then resumes the queue after compaction settles. Impact: queued Telegram turns no longer race Pi auto-compaction and trigger Cannot read properties of undefined (reading 'signal') after compaction.
  • [Command Templates] Updated the command-template helper library and regressions with typed placeholders, array-index placeholder resolution, repeat fanout from array length, unbounded default timeout semantics, and trusted-command warnings.
  • [Docs] Updated the command-template standard with typed args, array placeholders, failure propagation, recover cleanup, and trust-boundary guidance.
  • [Docs] Decomposed oversized architecture documentation blocks into focused sections for runtime ownership, queue validation, application menu shape, outbound actions, and interactive controls. Impact: the architecture entry point is easier to scan without changing runtime behavior.
  • [README] Split queue reaction shortcuts into priority and removal lists, added pi-xai-voice as a companion extension, and kept the time-injection row label compact while preserving the full detail-heading label. Impact: operator-facing docs match the current Telegram menu language.
  • [Context] Recorded the convention that extension-local standards should stay self-contained and avoid naming sibling extension implementations as authorities. Impact: shared standards can evolve independently without creating false extension dependencies.

0.11.1: Time Context And Settings Polish

  • [Time Context] Added optional telegram.json time prompt context for Telegram-originated turns. time.injectionMode values are off, always, and per-chat interval; time.interval is stored in milliseconds and timezone comes from the system. The [time] line renders last after attachments, handler outputs, and voice context, and Settings exposes a 🕒 Time mode selector.
  • [Settings UI] The proactive push row now uses 📌 Proactive push: on|off, and proactive push, time, and voice reply submenus use matching emoji headings.

0.11.0: Voice Provider Platform

  • [Voice Synthesis Provider API] Added a first-class voice synthesis provider surface for Telegram voice replies. Providers register with registerTelegramVoiceSynthesisProvider() from @llblab/pi-telegram/lib/voice.ts, synthesize text into .ogg/.opus, may return { audioPath, transcriptText }, and can contribute voice-specific prompt guidance through getVoicePromptContribution(view).
  • [Voice Prompt Context] Replaced the redundant [The user sent a voice message.] prompt marker with compact voice context owned by pi-telegram: [voice] reply mode: manual, [voice] reply mode: mirror, or [voice] reply mode: always. The marker is placed after handler [outputs] when present, otherwise after [attachments], and can expand to a [voice] list when more fields are added.
  • [Voice Reply Policy] Missing or invalid telegram.json voice.replyMode now resolves to manual regardless of provider defaults. Provider UIs can still change policy by writing voice.replyMode to the same config file pi-telegram reads.
  • [Voice Reply Policy] Added voice.replyMode with manual, mirror, and always modes. The bridge tags voice turns, suppresses previews for voice-tagged replies, and transparently converts implicit assistant text to voice when policy asks for it while explicit <!-- telegram_voice --> markup still wins.
  • [Status UI] Removed extension-section diagnostics from the Telegram status text. Section state belongs on dynamic section button labels and submenus, while /telegram-status keeps runtime/transport diagnostics focused.
  • [Extension Sections] Main-menu section rows now support a dynamic getLabel() function, matching Settings rows, so extensions can surface live state directly on their button labels.
  • [Prompt Guidance] Clarified [voice] turn context in the Telegram system prompt: manual means normal agent-authored output with optional explicit telegram_voice markup, mirror means voice input prefers voice output, and always means replies should stay TTS-friendly for automatic conversion.
  • [Config Interop] Added a narrow live config runtime so companion voice sections can update telegram.json voice policy and the active pi-telegram config store in one step.
  • [Voice Delivery] Restored outbound type: "voice" command handlers as the explicit first leg of voice delivery, followed by programmatic handlers and registered voice synthesis providers as zero-config fallbacks, so operator-configured telegram.json TTS handlers are never overridden by provider extensions.
  • [Inbound Handler API] Added registerTelegramInboundHandler(kind, handler) as the generic programmatic counterpart to configured inboundHandlers, completing the handler/provider matrix beside registerTelegramOutboundHandler, registerTelegramVoiceTranscriptionProvider, and registerTelegramVoiceSynthesisProvider.
  • [Voice Transcription Provider API] Added registerTelegramVoiceTranscriptionProvider() for provider-owned STT. Explicit inbound handlers and programmatic inbound handlers still run first; registered STT providers are fallback for voice/audio files without handler output.
  • [Settings UI] Added built-in voice reply mode controls to pi-telegram Settings and removed the need for provider extensions to own duplicate reply-policy UI; the selector persists voice.replyMode to telegram.json even from stale visible menu messages and uses the 👄 Voice reply: hidden|manual|mirror|always row with lowercase model-style active dots.
  • [Voice Prompt Context] Missing or invalid voice.replyMode is now surfaced in Settings as hidden: it behaves like manual, emits no [voice] reply mode: manual prompt-context block, and stores no voice.replyMode; explicit manual keeps the same behavior but renders context. mirror mode text-originated turns stay on the manual text path, including support for explicit telegram_voice markup.
  • [Voice Delivery] Voice delivery now uses Telegram sendVoice plus the native record_voice chat action. Providers own speech rewriting, TTS, and OGG/Opus conversion; non-OGG provider output fails voice delivery and falls back to the planned text reply.
  • [Voice Fallbacks] Voice artifact failures now throw to the queue runtime, which records diagnostics and sends the planned text fallback with outbound markup stripped and reply markup preserved when no text was already delivered.
  • [Voice Platform Cleanup] Collapsed merged prototype-only domains: removed shared globals, global-augmentations, and broad shutdown cleanup modules. Voice, section, external-handler, and outbound-handler global registry keys are now owned by their respective domains, and session shutdown no longer clears every extension registry globally.
  • [Docs] Added docs/voice.md and README coverage for voice modes, provider registration, STT provider fallbacks, caption-style transcripts, native voice format requirements, fallback behavior, and provider-owned settings.
  • [Tests] Added voice policy, provider registry, preview suppression, artifact delivery, fallback, OGG/Opus validation, prompt contribution, and entrypoint/invariant regressions. Full validation passes with 575 tests.

0.10.8: Compact Typing Timing Hotfix

  • [Compaction] Telegram /compact now starts the native typing chat-action keepalive after the "Compaction started" notice is sent, then stops it on completion or failure. Impact: operators see the same Telegram activity indicator during context compression that they already see during normal agent/tool work, without showing typing before the explicit start confirmation arrives.

0.10.7: Stale Context Hardening Hotfix

  • [Session Reloads] Context-sensitive command, pairing, queue, session-start, and update-dispatch paths now ignore only stale-session/stale-context failures instead of swallowing broad runtime errors. Impact: the bridge survives ctx replacement/fork/reload races while real bugs still surface for diagnostics.
  • [Runtime Status] Restored status update error propagation so existing polling/dispatch safety wrappers can record stale status failures as structured runtime events instead of losing diagnostics inside the status domain.
  • [Release] Added a tag-triggered GitHub Actions release workflow that verifies the vX.Y.Z tag matches package.json, extracts the matching CHANGELOG.md section, and publishes a GitHub Release automatically.
  • [Tests] Added focused regressions proving the newly guarded call sites tolerate stale context errors and still rethrow unrelated failures.

0.10.6: Native Typing Keepalive Hotfix

  • [Typing] Telegram native typing chat actions now refresh every 2.5s instead of every 4s. Impact: the bot's Telegram-side typing animation has more headroom to stay visible during model retries, transient model/API errors, and other long-running agent work.
  • [Queue Menu] Empty queue refresh now rotates through a wider set of small status phrases. Impact: repeatedly refreshing an empty queue feels less repetitive while preserving the same callbacks and menu layout.
  • [Tests] Added coverage for the default native typing keepalive cadence.

0.10.5: Queue Continuity And Input Resilience Hotfix

  • [Compaction] /compact completion and failure callbacks now request deferred queue dispatch instead of dispatching immediately. Impact: queued Telegram turns resume after compaction state and Pi idle/pending-message state have a chance to settle.
  • [Text Groups] Long-text split recovery is more aggressive where Telegram chunking actually drifts: the debounce is rounded to 1s, the conservative 3600-character start threshold is preserved, and continuation messages can span a much wider message-id gap while staying scoped to the same chat/user and non-command text. Impact: very large pasted prompts are more likely to arrive as one agent turn instead of several fragmented turns.
  • [Runtime Status] Typing-loop and prompt-dispatch status updates are now best-effort and record stale-context failures as structured runtime events. Impact: status/Running indicators remain resilient after error paths without hiding diagnostics.
  • [Tests] Added regressions for deferred compact dispatch, stale status failures in typing/dispatch paths, and many-part split-text grouping.

0.10.4: Polling Status Resilience Hotfix

  • [Polling] Status-bar updates from the polling loop are now best-effort and no longer crash the extension when a captured session context becomes stale after session reload. Failures are recorded as structured polling runtime events with phase: "status-update". Impact: polling cleanup and retry status updates stay resilient without changing the Telegram API, config, or operator workflow.
  • [Tests] Added stale-context polling regressions for startup, cleanup, and retry status updates. Impact: the external PR #43 fix is now covered by maintainer-side tests and kept aligned with local style.

0.10.3: Dependency Audit Hotfix

  • [Dependencies] Refreshed the lockfile transitive dependency set to resolve current protobufjs / @protobufjs/utf8 npm audit advisories inherited through development peer installs. Impact: npm run validate is green again without changing runtime API or bridge behavior.

0.10.2: Delete Message Port Hotfix

  • [ctx.deleteMessage()] Added deleteMessage() to TelegramSectionContext and TelegramSectionCallbackContext. Extensions can now delete the message that triggered a callback — useful for cleaning up confirmation dialogs after the user makes a choice.
  • [API] Added deleteMessage to TelegramBridgeApiRuntime, backed by Telegram's deleteMessage Bot API method with error recording.
  • [Demo] Confirmation dialog in pi-telegram-extension-demo now deletes itself on answer (ctx.deleteMessage()) and posts a follow-up result message (ctx.open()).
  • [Docs] Updated context port listings and interactive-messages section in extension-sections.md with deleteMessage().

0.10.1: Navigation Abstraction Hotfix

  • [ctx.open()] Removed automatic Back-row prepend from ctx.open(). ctx.open() sends a new message into the chat — a Back button makes no sense outside the menu. ctx.edit() still auto-prepends the correct navigation row for in-menu views.
  • [Platform Docs] Extended docs/extension-sections.md with a dedicated section on sending interactive messages into chat via ctx.open(): confirmation dialogs, approve/deny gates, and extension-driven button flows that live outside the menu hierarchy.

0.10.0: Extension Sections Platform

  • [Extension Sections] Implemented the Telegram Extension Sections platform: extensions can register structured UI sections that appear in the main Telegram application menu and Settings submenu without owning a second bot poller.
  • [Registry] Added lib/extension-sections.ts with a section registry (createTelegramExtensionSectionRegistry), token-based callback routing (section:<token>:<action>:<payload>), main-menu row injection, settings submenu row injection, registerTelegramSection() globalThis bridge for ordinary pi extensions, and diagnostics.
  • [API] Exported registerTelegramSection(section) / getTelegramSectionDiagnostics() from @llblab/pi-telegram/lib/extension-sections.ts. Extensions receive narrow typed context ports (TelegramSectionContext / TelegramSectionCallbackContext) with answerCallback, edit, open, and enqueuePrompt.
  • [Main Menu] Section rows are injected before the built-in Settings row in the status/application menu. Sections render their own inline-keyboard views with an automatic ⬆️ Main menu back button.
  • [Settings Submenu] Extension settings rows appear before built-in settings controls. Each section can expose an optional settings block with its own open and handleCallback.
  • [Callback Routing] section: is now a pi-telegram-owned callback prefix. Section callbacks are dispatched before built-in menu handling. Stale tokens receive a graceful "no longer available" answer. Unknown section callbacks fall through to the existing callback namespace fallback.
  • [Menu Integration] Updated menu-status.ts to accept a sectionRegistry and inject section rows before Settings. Updated menu-settings.ts to accept a sectionRegistry and inject extension settings rows before built-in controls. Updated menu.ts to parse and dispatch section: callbacks through the registry.
  • [Demo] Added @llblab/pi-telegram-extension-demo — a companion pi extension demonstrating section registration, a read-only Explorer UI with prompt enqueue, and a settings toggle. The demo lives in extensions/pi-telegram-extension-demo/.
  • [Model Labels] Model button labels now use compact provider/ModelId format (e.g., anthropic/claude-sonnet-4-5) instead of ModelId [provider]. Models are sorted by provider for predictable grouping. The status row and detail view already used this canonical format.
  • [Navigation] Section ctx.edit() and ctx.open() automatically prepend the correct Back button: ⬆️ Main menumenu:back at root level, ⬆️ Backsection:<token>:open from section callbacks, ⬆️ Backsettings:list from settings callbacks. Back buttons are deduplicated when already present.
  • [Settings Status] Settings rows now support a dynamic getLabel() function for live status indicators (e.g., 🟢/⚫️ based on internal state). Called on every Settings list render, no polling needed.
  • [Context] Added callbackData(action, payload?) to section context types — section authors never hand-roll section: callback strings. Tokens are filled in automatically.
  • [CLI] Removed /telegram-settings from pi CLI commands. Telegram settings remain available through the Telegram /settings inline menu. Keeps the pi TUI simple.
  • [Demo] Renamed @llblab/pi-telegram-demo@llblab/pi-telegram-extension-demo with a standalone package.json depending on @llblab/pi-telegram ^0.10.0, a comprehensive README.md, and a GitHub repository reference. Proves third-party devs can extend the pi-telegram interface as an ordinary npm package.
  • [Tests] Added 26 regression tests in tests/extension-sections.test.ts covering registry lifecycle, main-menu and settings row ordering, callback parsing, section open/callback/settings-open dispatch, stale token handling, handler fallback, and back-button dedup.

0.9.9: Guest Mode HTML Rendering

  • [Guest Mode] Guest replies now render through the same renderTelegramMessage pipeline as direct messages: Markdown → HTML → answerGuestQuery with parse_mode: "HTML". Bold, italic, code, links, lists, and tables render identically in guest and DM replies.
  • [Replies] Added createGuestMarkdownReplySender in the replies domain — guest rendering stays encapsulated within replies.ts and index.ts no longer imports from rendering.ts directly.
  • [API] Simplified answerGuestQuery title to a fixed "Response" string (the InlineQueryResultArticle title is hidden in guest mode and was previously generated by stripping HTML/Markdown from the message text).
  • [API] Removed replyMarkup parameter from answerGuestQuery — inline keyboards are not supported in guest mode because callback_query from inline results carries inline_message_id instead of chat_id/message_id, which the existing callback routing cannot handle.

0.9.8: Guest Mode Context

  • [Guest Mode] Extended the [telegram] prefix with |from:user (sender) and |guest:GroupName (source chat for group guest messages) so the agent sees who sent the message and where from. Private guest chats omit the guest: suffix.
  • [Guest Mode] Added |from:user to the [reply] block so the agent knows the original author of a replied-to message in guest mode.
  • [Guest Mode] Formatted guest prompt text identically to regular DMs through buildTelegramTurnPrompt, including [attachments] and [outputs] sections with file downloads and inbound handler processing.
  • [Prompts] Added compact agent guidance explaining guest-mode prefix suffixes (|from:, |guest:) and reply-from context.

0.9.7: Bot API 10.0 Alignment

  • [Dependencies] Migrated peer dependencies and imports from @mariozechner/* to @earendil-works/* (pi-agent-core, pi-ai, pi-coding-agent). Impact: the extension now tracks the new @earendil-works package scope; transitive @mariozechner packages remain in the lockfile until their upstreams migrate.
  • [Package] Added engines: { "node": ">=22.0.0" } to document the supported Node expectation while keeping dev dependencies on latest for early-stage iteration. Impact: users know the minimum Node version without constraining the development dependency matrix prematurely.
  • [Polling] Added "guest_message" to TELEGRAM_ALLOWED_UPDATES so the bot receives guest-mode updates. Impact: without this, guest mentions are silently ignored by Telegram.
  • [Telegram API] Updated sendMessageDraft wrapper for Bot API 10.0 semantics: removed the empty-text guard, made text optional, and added optional parse_mode, entities, and message_thread_id parameters. Impact: preview can now show a "Thinking…" placeholder with empty text, and callers can pass rich formatting through parse_mode or entities.
  • [Telegram API] Added answerGuestQuery to the API runtime for Bot API 10.0 Guest Mode support. Impact: callers can reply to guest queries in chats where the bot is not a member. Uses InlineQueryResultArticle as the result payload per Bot API 10.0 contract.
  • [Updates] Extended inbound update routing to recognize guest_message updates. Added getAuthorizedTelegramGuestMessage, guest flow action, execution plan, runtime handler, and prompt enqueue support. Unauthorized guest queries receive an "Access denied." reply via answerGuestQuery. Guest turns customize the agent-end delivery to use answerGuestQuery instead of normal reply transport. Impact: the bridge can now receive and route guest-mode mentions in group chats while preserving the existing private-message authorization model.
  • [Runtime] Added typing-loop skip for guest turns (chatId === 0) to avoid spurious sendChatAction errors in the status bar.
  • [Tests] Added regression tests for empty-text draft delivery, undefined-text draft delivery, rich preview with parse_mode and entities, guest query answers, guest extraction, guest flow classification, guest execution plan, guest deny reply, and guest message routing through the runtime.
  • [Preview] Updated sendDraft interface in lib/preview.ts to accept optional text and formatting options, keeping the preview pipeline aligned with the new API wrapper.

0.9.6: Runtime Adapter Positioning

  • [Package] Repositioned the package description from "Better Telegram DM bridge extension for Pi" to "Telegram runtime adapter for Pi". Impact: package metadata now reflects the runtime adapter/operator-console role rather than a narrow pipe metaphor.
  • [Telegram API] Introduced TELEGRAM_API_BASE for the Bot API endpoint and documented native HTTP/HTTPS proxy operation through HTTP_PROXY, HTTPS_PROXY, NO_PROXY, and explicit NODE_USE_ENV_PROXY=1 / --use-env-proxy enablement. Impact: users behind corporate proxies, local HTTP tunnels, or restricted networks get a zero-runtime-dependency proxy path without replacing native fetch; SOCKS5 remains outside the zero-dependency core.
  • [Dependencies] Refreshed the lockfile transitive dependency set so npm audit clears current fast-uri and fast-xml-builder advisories inherited through development peer installs. Impact: the full npm run validate pipeline passes without changing runtime dependencies.
  • [README] Restructured the user entrypoint around install → connect → use → core features → docs, then consolidated examples, terminology, proxy setup, PI_CODING_AGENT_DIR, and other environment-only configuration around the runtime-adapter/operator-console model. Impact: first-time users get a clearer path from installation to operation, while vivid examples and non-UI runtime knobs stay discoverable.
  • [Context] Promoted the runtime-adapter/operator-console README rhythm, /start menu emphasis, and environment-only configuration rule into AGENTS.md. Impact: future documentation edits preserve the same positioning and env-knob coverage instead of drifting back toward a narrow bridge metaphor.

0.9.5: Telegram Delivery Resilience Hotfix

  • [Preview Delivery] Preview flush failures from Telegram transport errors such as fetch failed / ECONNRESET are now caught and recorded as runtime diagnostics instead of escaping from the preview pipeline. Impact: transient Telegram connectivity failures no longer crash the extension during streamed preview edits.
  • [Final Delivery] Final Markdown preview replacement now catches Telegram transport failures and returns a normal fallback signal; the agent-end delivery path records final-text delivery failures and continues cleanup, attachment handling, and queue dispatch. Impact: a failed editMessageText at agent_end no longer breaks the bridge lifecycle or blocks the next queued Telegram turn.
  • [Diagnostics] Preview and final delivery failures now flow through the runtime event recorder with compact phase metadata. Impact: /telegram-status can show recent transport failures without dumping noisy stack traces into the extension runner.
  • [Tests] Added preview and queue regressions for non-fatal Telegram transport failures during preview flush and final delivery.
  • [Extension Sections Draft] Added a draft design note for pi-native Telegram extension sections, reserved the future section: callback prefix, linked the draft from docs, and recorded the project philosophy that pi-telegram should inherit Pi's extensibility model as a shared Telegram shell for loaded extensions. Impact: the future 0.10.0 extension platform direction is documented without exposing a stable API yet.
  • [Docs Formatting] Normalized project Markdown so prose paragraphs stay as single logical lines and Markdown tables remain narrow instead of using artificial hard wraps. Impact: editors and viewers can handle visual wrapping naturally while fixed-width structures stay readable.
  • [Settings Copy] Tightened the proactive-push settings text by removing redundant persistence/default wording.

0.9.4: Temp Dir And Command Template Hotfix

  • [Telegram Temp Dir] Default Telegram API temp files now respect PI_CODING_AGENT_DIR, falling back to ~/.pi/agent when the env var is unset. Impact: sandboxed or relocated agent dirs no longer force Telegram downloads through the default home-directory path.
  • [Command Templates] Updated the local Command Template Standard: command-template nodes now document mode, label, delay, repeat, parallel fanout semantics, zero-based repeat placeholders, padding, and limited arithmetic expressions such as {_(index+1)}. Impact: inbound/outbound Telegram handler docs and helpers share the current portable automation contract without depending on another extension's documentation.
  • [Queue Menu] Empty queue refresh clicks now rotate through compact alternate empty-state headings while preserving the default first-open ⌛ Queue is empty. state, and the Refresh button now stays directly under Back for both empty and populated queue lists. Impact: manual queue polling feels alive and the primary refresh control stays in a stable location without changing queue semantics.

0.9.3: External Handlers Rename

  • [External Handlers] Renamed the external update handlers domain to external-handlers across source, tests, and docs. Impact: the interop domain now has a cleaner name aligned with inbound/outbound handler naming.
  • [Breaking] Removed the old external-update-handlers module/doc path and old exported update/interceptor aliases. Impact: layered extensions should import from @llblab/pi-telegram/lib/external-handlers.ts and use the TelegramExternalHandler* names.

0.9.2: External Update Interceptors

  • [External Update Interceptors] Added a versioned globalThis registry that lets layered pi extensions observe and optionally consume Telegram updates before pi-telegram's default routing. Impact: approval gates and other same-process extensions can react synchronously to Telegram callbacks without owning a second bot poller.
  • [External Update Interceptors] Validated the full v1 registry shape (version, add, and dispatch) before reusing a pre-existing global registry and documented the zero-coupling bootstrap contract. Impact: install-order interop stays safe even when another extension initializes the registry first.
  • [Queue Menu] Non-empty queue lists now keep the 🌀 Refresh row below queued items, matching the empty-queue surface. Impact: users can manually refresh the queue screen while waiting for changes without navigating away.
  • [Security] Refreshed the lockfile to resolve the transitive basic-ftp audit advisory. Impact: release validation returns to a clean npm audit state.

0.9.1: Model Detail Hotfix

  • [Model Menu] Detail-mode activation now preserves scoped thinkingLevel by resolving the selected scoped entry before falling back to the unscoped model list. Impact: scoped model shortcuts opened through the detail submenu keep their reasoning/thinking level.
  • [Model Menu] Activating an already active model from the detail submenu now still runs the refresh path that applies scoped thinking changes while returning to the model list. Impact: tapping Active can still correct the thinking level instead of becoming a no-op.
  • [Proactive Push] Removed the unused proactive reply-target store and always sends proactive local-result pushes without reply_to_message_id. Impact: the runtime no longer carries dead state for a target-capture behavior that does not exist yet.
  • [Queue Reactions] Added 🔥 as a priority reaction and 🗑 as a queue-removal reaction. Impact: the intuitive fire/removal gestures now work alongside the existing reaction controls.
  • [Docs] Updated the status-bar example to match the compact active/queued display.

0.9.0: Hidden Settings And Proactive Push

  • [Settings Menu] Added hidden Telegram /settings with a proactive push checkbox detail submenu plus /telegram-settings in the terminal. Impact: operators can see green/black binary flag state, use green/black/yellow on/off checkbox controls from Telegram, and toggle the same proactive push flag locally without adding a visible bot-command entry.
  • [Proactive Push] telegram.json now supports proactivePush; when enabled, successful local non-Telegram Pi final replies are sent to the paired Telegram chat if no Telegram turn is active and the current session still owns the Telegram lock. Local prompt text stays private because the bot does not own or mirror terminal user messages. Impact: long local tasks can notify the phone with result context without leaking from stale bridge owners or failed/aborted turns.
  • [Queue UI] Empty queue states now use the bottom-filled hourglass while non-empty queue states keep . Queue item details now show the selected queue position above the raw prompt preview, preserve reaction-specific priority emoji in the heading, and use side-by-side Priority/Normal tabs that refresh the heading marker immediately. The terminal status bar now stays yellow active while Telegram-owned work still has running tools even if a queued prompt is removed by reaction. Impact: queue emptiness has a small visual easter egg, item submenus stay oriented without changing queue semantics, and queue-removal reactions no longer visually degrade active work to connected.
  • [Model Menu] Model rows now open a detail submenu with Back, ☑️ Activate/🟢 Active selection, and yellow/black-marked Scoped/All membership tabs. Impact: model selection remains one tap away while scoped model membership can be managed from Telegram.
  • [Status Menu] The main Telegram menu status row now shows compacting while a Telegram /compact run is active. Impact: the phone UI reflects the same compaction state that already blocks dispatch and appears in terminal status.
  • [Prompt Guidance] Telegram prompt injection now asks agents to target 37 visible cells for tables, dense list items, and compact text blocks. Impact: replies better fit narrow mobile Telegram screens, especially when emoji or wide glyphs are present.

0.8.2: Lock-Safe Delivery

  • [Lock Safety] Active Telegram turns now re-check singleton ownership before preview flushes and final agent-end delivery. Impact: an old Pi instance stays silent after another instance takes the Telegram bridge lock, even if the old instance finishes a long-running prompt later.
  • [Inbound Handlers] The first step of an inbound composition now receives the full configured handler timeout before elapsed-time accounting starts on later steps. Impact: composition timeout behavior is deterministic and avoids one-millisecond test/runtime drift at pipeline start.
  • [Menu UI] Model and Thinking submenu headers now include their matching command icons (🤖 and 🧠). Impact: submenu headings match the Queue menu's icon-led style.

0.8.1: Outbound Voice Translation Hotfix

  • [Outbound Voice] Composed voice handlers now pass the original telegram_voice text to the first pipeline step through stdin, then continue piping each step's stdout into the next step. Impact: translate-from-stdin voice pipelines can translate hidden voice text before TTS instead of failing with an empty first-step input.
  • [Queue Menu] Queue item detail previews now render prompt text inside a bounded raw <pre> block, and generic queue navigation/headings use the waiting icon. Impact: absolute file paths and attachment references remain readable without Telegram interpreting slash-prefixed paths as commands, long previews are truncated below Telegram's message limit, and the queue surface has a clearer generic icon distinct from ordered-list or priority markers.
  • [Queue Delete] Queue item removal now uses explicit 🗑 Delete wording and opens a two-button confirmation (🗑 Yes, delete / ❌ No) before mutating the queue. Impact: accidental queue-item deletion is harder while the item detail flow remains compact.
  • [Queue Priority] Priority reactions now preserve the exact normalized promotion emoji and render it in both queue-menu rows and the Pi status-bar queued preview. Reaction metadata is grouped into semantic id ranges (10..13 for priority, 20..23 for removal). Impact: 👍, , ❤️, and 🕊️ keep the same priority semantics while making the user's chosen reaction visible across Telegram and TUI surfaces.
  • [Configuration Docs] Documented the configuration philosophy that rich visual/TUI setup stays minimal for now while agents can read README/docs and update telegram.json for advanced workflows. Impact: configuration guidance matches the extension's agent-assisted operator model without adding premature TUI surfaces.
  • [Outbound Docs] Tightened voice-handler critical-step wording around transform → TTS → conversion pipelines and handler-level fallbacks. Impact: docs now match translated voice pipelines without implying provider-specific TTS fallbacks.
  • [Command Template Docs] Updated docs/command-templates.md to the current portable standard. Impact: the documented standard now includes retry, fail-open composition, critical-step abort semantics, and the 30s default timeout without requiring cross-extension references.
  • [Lock Docs] Synchronized docs/locks.md bit-for-bit with the extension-neutral Locks Standard shared by pi-wakeup. Impact: singleton ownership documentation no longer carries project-specific examples that prevent exact reuse across extensions.

0.8.0: Handler Bus

  • [Inbound Handlers] Added inboundHandlers as the provider-neutral Telegram → Pi transformation bus. Raw Telegram text can match type: "text", mime: "text/plain", or mime: "text/*", receives text on stdin and {text}, and non-empty stdout replaces the prompt text before queueing; media/file handlers keep the existing {file}/{mime}/{type} behavior with optional independent selectors. Impact: translation, normalization, STT, OCR, and file extraction can share one command-template integration model.
  • [Text Attachments] Attached text/plain/text/* files now have a built-in fail-open reader that injects UTF-8 content into [outputs] when no configured handler produced output. Impact: ordinary .txt and other text documents become readable to Pi without custom extraction config.
  • [Inbound Domain] Renamed the implementation module and mirrored regression suite from attachment-handlers to inbound-handlers. Impact: file names now match the unified text/media preprocessing domain while legacy attachmentHandlers config remains supported.
  • [Outbound Attachment Domain] Renamed the outbound file-delivery module and mirrored regression suite from attachments to outbound-attachments. Impact: telegram_attach ownership now reads as an outbound domain beside outbound-handlers while behavior stays unchanged.
  • [Inbound Docs] Consolidated the deprecated docs/attachment-handlers.md page into docs/inbound-handlers.md and removed the old page. Impact: the inbound bus docs are now the canonical home for legacy attachmentHandlers, placeholders, ordered fallbacks, and prompt-output behavior without split documentation.
  • [Attachment Handlers] attachmentHandlers is now deprecated but remains supported as a compatibility alias appended after inboundHandlers. Impact: existing voice/file preprocessing configs keep working while new configs can move to the unified inbound bus.
  • [Outbound Handlers] Added outboundHandlers support for type: "text"; final text/Markdown replies can be transformed before Telegram rendering and delivery. Impact: translation-back or other outbound text normalization can be configured without hard-coded providers.
  • [Outbound Text Preview] Finalized rich preview messages now pass through outbound type: "text" handlers before Telegram edit/delivery, with expanded README/docs examples for machine translation, final text rewrites, composed translated voice-over, and inline-button compatibility. Impact: outbound text transforms apply even when the final answer reuses an existing preview instead of falling back to a separate send path, while inline buttons remain attached and visible labels are transformed without changing callback prompts.

0.7.2: Split Text Coalescing Hotfix

  • [Text Coalescing] Telegram text messages that look like automatic splits of one near-limit human message are now short-debounced and forwarded to Pi as one prompt, using a conservative 3600-character near-limit threshold. Commands, bot messages, media groups, captions, non-contiguous messages, and normal short follow-ups bypass coalescing. Impact: long pasted logs/prompts are less likely to arrive as separate Pi turns when Telegram chunks them.
  • [Runtime Tests] The media-group runtime regression now waits for the real debounce instead of mixing fake timers with the polling loop, and the reaction-priority runtime test flushes pending microtasks before ending the active turn. Impact: CI should stop failing on timing-only races around delayed dispatch and queued reaction mutations.
  • [Callback Namespaces] Current status-screen navigation callbacks now use the canonical menu: namespace (menu:model, menu:thinking, menu:queue). status: remains reserved as an owned legacy prefix but is no longer emitted by current UI. Impact: new inline menu callbacks align with the unified app-menu model while old status: payloads still cannot leak to external fallback handlers.

0.7.1: Layered Callback Interop

  • [Callback Interop] Unknown Telegram inline-button callback data that does not belong to pi-telegram-owned prefixes (tgbtn:, menu:, model:, thinking:, status:, queue:) is now forwarded to Pi as [callback] <data> after assistant-button, queue-menu, and app-menu handlers decline it. docs/callback-namespaces.md defines the shared callback namespace standard for layered extensions. Impact: layered Pi extensions can namespace and handle their own Telegram inline buttons without polling the same bot or forking pi-telegram.
  • [Prompt Templates] Prompt-template aliases stay visible only inside /start and are no longer registered in the Telegram bot command menu. Impact: reusable Pi workflows remain discoverable without making Telegram's global command menu noisy.

0.7.0: Unified App Menu & Command Template Hardening

  • [Commands] Visible Telegram bot command menu now exposes /start, /compact, /next, /continue, /abort, and /stop; /help, /status, /model, /thinking, and /queue remain hidden compatibility shortcuts. /start, /help, and /status open one unified app menu containing command help, status rows, and inline controls. Command emoji are centralized as fixed adornments in the commands domain and reused by matching menu buttons (🤖 model, 🧠 thinking); /next uses and /continue uses ▶️. /continue enqueues a priority Telegram-owned continue prompt instead of forcing the next queued item or requiring Pi to be idle. Impact: the visible command surface is cleaner while existing operator muscle memory still works and skills can react to queued continue prompts.
  • [Application Menu] /start opens command help plus status rows and the inline application menu; /queue opens the queue section directly, the status menu Queue button shows the current queued-item count, all submenus keep Back/Main menu navigation in the top row, and queued items are listed in dispatch order with numeric labels plus /📎 markers. Queue menu message text uses the same HTML heading style as the other inline menus; empty queue menus render bold message text with only the Main menu navigation button instead of a disabled empty-state button. Item submenus support Back, Priority/Normal tabs, and Cancel, and stale item clicks refresh the live list. Impact: queued Telegram work is inspectable and mutable from the menu control surface without relying only on reactions.
  • [Prompt Templates] /start now shows a separate block for Pi prompt-template commands, and the Telegram bot command menu registers Telegram-safe prompt-template aliases such as fix-tests/fix_tests when they do not conflict with built-in bridge commands or hidden shortcuts. Sending /template_name args from Telegram expands the matching Pi prompt-template file before queueing the turn. Impact: reusable Pi workflows are available from Telegram without duplicating prompt text manually.
  • [Keyboard] Shared Telegram inline-keyboard reply-markup structure was extracted to keyboard, while menu owns application-control button semantics and outbound-handlers owns assistant-authored button semantics. Impact: inline UI domains share one Bot API shape without centralizing feature behavior.
  • [Domain DAG] Source-module opening comments now include Zones: tags for cross-cutting responsibility areas such as Telegram transport, Pi agent lifecycle, TUI, and shared utilities. Impact: flat files keep folder-like orientation without adding directory nesting.
  • [Menu Refactor] Queue-menu UI moved from menu.ts into the flat menu-queue domain while core queue mechanics remain in queue; model-menu state, scoped model pages, callback planning, and model-menu rendering moved into the flat menu-model domain while core model semantics remain in model; thinking-menu text, markup, callbacks, and rendering moved into the flat menu-thinking domain; status-menu payloads, callbacks, and rendering moved into the flat menu-status domain. Impact: menu.ts is smaller and queue/model/thinking/status control surfaces have dedicated UI boundaries without adding folders or changing Telegram behavior.
  • [Menu] Busy-state messages now mention /abort, /next, and /stop; submenu main navigation uses top-row ⬆️ Main menu; thinking-menu text is a compact bold heading because the selected level is already marked in the buttons; model-menu scope and pagination controls now sit at the top under Main menu, and the pagination indicator opens a compact <b>Choose a page:</b> picker with numbered page buttons.
  • [Queue Reactions] Priority reactions now accept 👍, ⚡️, ❤️, and 🕊; removal reactions now accept 👎, 👻, 💔, and 💩. Impact: users can use more default Telegram reactions for queue control while keeping the same priority/removal semantics.
  • [Config] telegram.json persistence now writes through a private temp file and atomic rename before restoring 0600 permissions. Impact: concurrent setup/status reload paths and interrupted writes no longer expose readers to a truncated JSON file.
  • [Status] Main-menu status output now renders Status: idle|active|pending|unknown as a normal status row instead of a standalone heading; TUI status-bar active uses the warning color token.
  • [Reply Dedup] Only the first agent message in a turn replies to the triggering prompt; subsequent messages skip reply_to_message_id. Impact: stacked reply headers no longer waste vertical viewport space—the first message anchors the thread and the rest deliver as independent messages. Implemented at the transport level in buildTelegramReplyParameters so preview delivery, voice upload, and all text paths are caught uniformly. Reset on agent_start via lifecycle.ts.
  • [Command Template] Default timeout of 30s (DEFAULT_COMMAND_TIMEOUT_MS) is now exported and enforced; handler invocations may omit explicit timeout where the default is sufficient.
  • [Command Template] critical field standardised: when true, leaf failure aborts the entire root composition. attachment-handlers.ts and outbound-handlers.ts composition loops implement fail-open default (continue on non-critical failure) with critical re-throw gating. Impact: the TTS pipeline (edge-tts → ffmpeg) can mark ffmpeg as critical and abort cleanly.
  • [Docs] Handler documentation and README examples now rely on default command timeouts and keep config examples minimal; critical-step guidance remains where needed.
  • [Typing Safety] Typing-loop send failures now update the live status through the prompt-dispatch context and still record diagnostics. Impact: transient typing failures are visible without relying only on /telegram-status.
  • [Type Safety] Preview reply markup now flows through generic preview controller/runtime and agent-end finalization contracts instead of any. Impact: assistant-authored buttons keep their concrete inline-keyboard type through preview finalization without narrowing future preview transports.
  • [Tests] 416 passing (was 402 before prompt-template command coverage): reply dedup, critical composition gating, queue controls, queued /continue, unified app menu/status rows, menu-domain splits, queue-menu navigation order, preview reply-markup typing, prompt-template command expansion, and transport-level reply-parameter dedup are all covered.

0.6.3: Outbound Action Syntax & Prompt Guidance

  • [Outbound Buttons] telegram_button: Label now creates a label-only button whose callback prompt equals the label. Impact: button shorthand now matches the telegram_voice: Text inline style and leaves one canonical label-only syntax.
  • [Outbound Actions] telegram_voice text="..." and telegram_button label=... prompt="..." now provide explicit one-line action forms. Impact: agents can keep short voice and button actions on one line without relying on body blocks.
  • [Outbound Parsing] Hidden action bodies now stay attached to their action heads within the parser recovery window. Impact: hidden prompt and TTS bodies stay out of Telegram-visible messages.
  • [Prompt Guidance] Telegram prompt injection is now organized by inbound context, visible output, and native outbound actions, with explicit one-line vs body telegram_button syntax. Impact: agents get the same operational rules with less duplicated guidance and more consistent action markup.
  • [Architecture] Entrypoint wiring now names inbound routing, queue session lifecycle, agent lifecycle hooks, outbound reply collaborators, and repeated pi context ports before registration. Impact: index.ts remains the composition root while the final hook/polling registration blocks are easier to scan.
  • [Config] Missing telegram.json is now handled with an explicit existence check before reading. Impact: first-run config loading keeps the empty-config fallback without using read failures as control flow.

0.6.2: Reload-Stale Queue Dispatch Hotfix

  • [Queue Dispatch] Deferred post-agent-end queue dispatch is now session-bound and canceled on session shutdown. Impact: /reload and session replacement can no longer leave old queue timers calling stale ExtensionContext methods such as ctx.isIdle().
  • [Typing Safety] Typing-loop transport failures now go only to runtime diagnostics instead of updating status through an interval-captured context. Impact: typing errors remain visible in diagnostics without retaining live ExtensionContext in timer error paths.
  • [Lock Watcher Safety] Ownership-loss watchers now retain only the snapshotted lock identity and stop polling without a captured live context. Impact: singleton takeover cleanup no longer needs stale-prone status refreshes from watcher callbacks.
  • [Media Group Safety] Media-group debounce timers now flush through controller state instead of closure-capturing the inbound context. Impact: album coalescing keeps the same behavior while reducing stale-context retention in timer callbacks.

0.6.1: Outbound Action & Command Timeout Hardening

  • [Command Template Runtime] Timed-out command templates now escalate from SIGTERM to SIGKILL when the child process does not exit. Impact: attachment and outbound-handler pipelines no longer hang forever on commands that ignore graceful termination.
  • [Outbound Buttons] telegram_button blocks may now omit the body when the callback prompt should equal the label. Impact: concise buttons such as <!-- telegram_button label="OK" --> work without duplicating the prompt text.
  • [Outbound Comment Parsing] Top-level outbound comments are now recognized again after fenced code blocks closed by Markdown-valid indented or longer fences. Impact: code examples stay literal while later telegram_voice and telegram_button blocks still execute correctly.
  • [Command Template Docs] The command-template contract now explicitly documents the strict 0.6.x shape: use timeout, and keep args as a string array of placeholder declarations. Impact: legacy timeoutMs and string-form args are not presented as supported compatibility paths.

0.6.0: Command Templates & Assistant-Authored Outbound Actions

  • [Outbound Actions] Assistant replies now use hidden telegram_voice and telegram_button blocks as Telegram-native action markup. Impact: text stays in the normal Markdown answer, voice block bodies become native OGG/Opus sendVoice messages, and button bodies become normal queued Telegram prompt turns without agent-side transport tool calls.
  • [Outbound Semantics] Outbound behavior is now owned by the unified outbound-handlers domain. Impact: voice artifacts, per-block language/rate attributes, independent multi-voice delivery, singular one-block-one-button callbacks, top-level-only comment stripping, artifact upload, and prompt reply metadata are planned and delivered as one post-agent_end response surface while code examples stay literal.
  • [Command Template Standard] Command-backed handlers now share a compact shell-free template contract: no command field, template as string or template: [...], args as declarations only, defaults via defaults or {name=default}, top-level timeout wrapping composed sequences, stdout-to-stdin composition piping, and output defaulting to "stdout" while allowing artifact selectors such as "ogg". Impact: inbound attachment preprocessing and outbound artifact generation use the same portable automation model without provider-specific fields or shell evaluation.
  • [Handler Boundaries] Inbound preprocessing now lives in attachment-handlers, outbound generated actions live in outbound-handlers, and reusable template mechanics live in command-templates. Impact: file names, mirrored tests, and docs match the actual domains instead of broad handlers, standalone voice, or grouped button mini-DSL boundaries.
  • [Docs] Handler examples now use portable /path/to/stt, /path/to/tts, and /path/to/tool placeholders and dense command-template documentation. Impact: release docs describe what operators configure without leaking host-local skill paths or repeating the same template rules across documents.

0.5.2: Telegram Reply Context

  • [Telegram Replies] Normal Telegram prompts now include quoted Telegram reply_to_message text/caption as a bounded [reply] context block. Impact: replying to an earlier Telegram message gives the agent the quoted context instead of only the new message text. Inspired by external PR #4 from @maphim.
  • [Command Safety] Slash-command parsing still uses only the new message text/caption, and reply context is injected only while building or editing queued prompt turns. Impact: replying with /status, /model, /stop, and other commands still executes the command instead of becoming a normal prompt.
  • [Docs & Tests] Updated README, architecture/context notes, package metadata, and media/turn regressions for reply-context forwarding, truncation, queued edits, and command-safe raw text extraction. Impact: the feature is documented and covered without weakening the existing queue/command split.

0.5.1: Stop Queue Reset Hotfix

  • [Queue Safety] Telegram /stop now clears all waiting Telegram queue items, resets pending model-switch/abort-history preservation state, and then aborts the active run when possible. Impact: queued priority/default/control turns can no longer leave the bridge stopped after an abort; the next Telegram message starts from a clean queue like a fresh TUI prompt.
  • [Docs & Tests] Updated README, architecture notes, agent context, and queue/runtime/command regressions for the new stop/reset contract. Impact: the hotfix behavior is documented and covered by the high-risk stop plus queue path.

0.5.0: Command Templates, Domain Boundaries & Queue UX

  • [Queue UX] Telegram /status and /model now execute immediately, post-agent-end queue dispatch retries after pi settles idle state, and the status bar shows specific busy labels (active, dispatching, queued, tool running, model). Reaction priority remains local and applies to text, voice, file, image, and media-group turns without introducing pi steering semantics. Impact: controls do not get stuck behind generation, queued work no longer needs a later Telegram update to unstick, and attachment turns keep predictable ordering.
  • [Attachment Handlers] Inbound preprocessing now uses portable template configs with args/defaults and ordered fallback chains, documented in docs/command-templates.md and current inbound handler docs. Impact: voice/STT primary-fallback setups work from telegram.json without coupling pi-telegram to private auto-tool registry internals.
  • [Domain Boundaries] Removed the broad registration domain and moved registration surfaces to owners: attachments register telegram_attach, commands register pi /telegram-* commands, lifecycle registers hooks, and prompts own Telegram-specific system prompt injection. Impact: entrypoint wiring is clearer and each registration surface has focused tests.
  • [telegram_attach] The outbound attachment tool now lives in the attachments domain with outbound limits, queueing failure events, and pi-friendly tool-result formatting. Impact: outbound file delivery behavior is owned by the same domain that queues and sends Telegram attachments.
  • [Docs & Validation] Updated README, docs, architecture/context maps, backlog, focused coverage, and removed vendored repository-local agent skills in favor of global validation tooling. Impact: user-facing docs, validation, and package-adjacent repo contents match the 0.5.0 code shape without stale skill copies.

0.4.0: Singleton Locks & Attachment Handlers

  • [Locks] Added the shared locks.json singleton ownership standard and documented it in docs/locks.md. Telegram polling ownership now lives under @llblab/pi-telegram in ~/.pi/agent/locks.json, while telegram.json remains pure bot/user configuration. /telegram-connect acquires the lock, replaces stale locks, or moves live external owners here through an interactive confirmation; /telegram-disconnect releases it. Session initialization reads ownership state, active owners stop local polling when locks.json no longer points at their own pid/cwd, session replacement via /new suspends polling/watchers without touching explicit ownership before resuming in the new session, and a reopened pi process resumes a stale same-cwd lock automatically. Impact: runtime locks can be reset or moved without deleting Telegram configuration, finding the previous pi instance, or crashing on stale extension contexts.
  • [Attachment Handlers] Added telegram.json inbound attachment handlers with MIME/type matching, safe command placeholder substitution, compact [attachments] <directory> plus [outputs] prompt sections, and quiet omission of empty or failed handler output. Impact: common flows such as Telegram voice transcription can happen before the agent sees the turn while keeping source attachment paths visible.
  • [Refactor] Extracted inbound route composition from index.ts into /lib/routing.ts, keeping paired update execution, callback menus, command-or-prompt dispatch, media grouping, prompt enqueueing, queued edits, and attachment-handler turn building behind one cohesive route wiring boundary. Impact: the entrypoint stays smaller while high-risk Telegram update flow remains covered by runtime and invariant tests.

0.3.0: Modular Runtime, Queue Controls, Diagnostics

Runtime Architecture

  • [Flat Domain DAG] The extension now uses index.ts as the single composition root over flat, acyclic /lib domains. API transport, persisted config/pairing, model control, queue/lifecycle, runtime state, commands, menu UI, polling, previews, replies, rendering, media, turns, attachments, updates, setup, status, pi SDK adapters, and registration each have explicit ownership. Impact: bridge behavior is easier to locate without introducing a second entrypoint or shared bucket modules.
  • [Composition Root] index.ts now focuses on live pi/Telegram ports, session-local state, and cross-domain wiring. Stable defaults and local adapters for rendering, preview limits, preview reply metadata, attachment limits, Telegram prompt prefixes, prompt suffixes, command control items, bot command registration, API runtime construction, polling controllers, prompt dispatch, reply delivery, setup prompts, queue/session lifecycle, agent hooks, and tool hooks live in their owning domains. Impact: the entrypoint is smaller and reads as orchestration instead of carrying domain behavior.
  • [Type Boundaries] Concrete Bot API transport shapes live in api, queued/active turn contracts live in queue, persisted session state lives in config, media download metadata lives in media, model selection contracts live in model, and domain constants stay with their owners. Narrow structural view contracts are used where a domain only needs a projection. Impact: public module interfaces are cleaner and accidental cross-domain coupling is reduced.
  • [Runtime State] runtime owns only session-local coordination primitives: queue/control/priority counters, lifecycle flags, setup guards, abort handler storage, typing-loop timers, prompt-dispatch lifecycle binding, and agent-end reset sequencing. Preview state, queue planning, command behavior, rendering, and API transport stay outside runtime. Impact: mutable bridge state is centralized without becoming a general-purpose behavior bucket.

Queue, Lifecycle, And Controls

  • [Queue Core] queue owns prompt/control item contracts, explicit control/priority/default lane admission rules, queue stores, active-turn state, queue mutation, dispatch readiness, prompt enqueueing, control enqueueing, session start/shutdown sequencing, and agent/tool lifecycle hooks. Impact: scheduling rules, active-turn binding, abort preservation, compaction guards, and dispatch safety are enforced in one place.
  • [Command Admission] /stop, /compact, /help, and /start execute immediately, while /status, /model, and model-switch continuation prompts enter the control lane ahead of normal prompts. Priority reactions promote waiting prompts into the priority lane without bypassing control actions. Asynchronous control-item execution is serialized so new prompts or controls cannot dispatch while a queued /status or /model action is still settling. Impact: Telegram controls stay responsive while normal messages remain predictably ordered.
  • [Model Control] model owns model identity, thinking levels, scoped model pattern parsing/resolution/sorting, current-model state, in-flight model-switch state, restart eligibility, delayed abort decisions, continuation prompt construction, and model-switch controller runtime binding. Impact: model selection, scoped menus, and in-flight restart behavior have one cohesive home.
  • [Commands And Menus] commands owns slash-command parsing, command metadata, command-message targets, command execution modes, control-queue adapters, bot command registration, and stop/compact/status/model/help side effects. The Telegram bot command menu no longer exposes /debug; diagnostics live in pi-side /telegram-status and the pi TUI. menu owns inline status/model/thinking UI state, model-menu caching, callback routing, callback planning, render payloads, and menu message updates. Impact: Telegram controls can be tested without reading the full runtime composition.

Telegram Delivery, Rendering, And Files

  • [Rendering] rendering owns Telegram HTML Markdown scanning, escaping, preview snapshots, raw HTML chunking, long-message splitting, table/list formatting, grapheme/display-width-aware table padding for emoji and wide Unicode text, nested quote flattening, link safety, task-list handling, and literal code preservation. Impact: Telegram output stays readable on narrow clients while avoiding malformed HTML and broken code blocks.
  • [Registration] The Telegram before-agent prompt suffix now reminds the assistant to prefer narrow table columns because Telegram is often read on phone-width screens where wide monospace tables become unreadable. Impact: Telegram-originated tabular answers are more likely to fit mobile chats before renderer-level formatting is applied.
  • [Preview And Replies] preview owns streaming preview lifecycle, draft/editable-message transport choices, flush scheduling, preview finalization, and assistant-message hooks, while defaulting preview reply metadata through the replies helper instead of threading it through index.ts. replies owns final rendered-message delivery, reply parameters, assistant-message extraction, plain/Markdown replies, interactive message delivery, and split-message reply metadata. Impact: rich previews, final replies, errors, attachment notices, and uploads are tied to the source Telegram prompt when possible and degrade safely when Telegram cannot attach the reply.
  • [Files And Attachments] api owns Bot API calls, retries, runtime error recording, temp-dir cleanup, inbound file limits, lazy bot-token clients, chat actions, and file downloads. media owns inbound text/media extraction, file-info normalization, media-group debounce, and download assembly. attachments owns outbound attachment queueing, atomic multi-file staging, stat checks, outbound limits, photo/document classification, and queued attachment sending. Impact: inbound downloads and outbound uploads are size-limited by default, large files fail predictably without leaving partial attachment batches staged, and outbound artifacts flow through telegram_attach.
  • [Config And Setup] config owns telegram.json, bot-token/allowed-user state, single-user authorization, and first-user pairing. setup owns token prompting, stored-token/env fallback selection, validation, and guarded setup orchestration. Impact: pairing and setup behavior stays consistent across /telegram-setup, /telegram-connect, /start, and update routing.

Observability, Packaging, And Validation

  • [Status And Diagnostics] /telegram-status now reports bridge diagnostics as grouped line-by-line pi notification sections separated by blank lines, ending with the redacted recent runtime/API event ring after connection, polling, execution, and queue state such as active turn, queue depth, queue lanes, compaction, active tool count, and pending model-switch state. Transport/API failures, polling/update failures, prompt dispatch failures, control action failures, typing failures, compaction failures, setup failures, session lifecycle failures, and attachment queue/delivery failures are recorded in the ring, while benign unchanged edit responses and empty draft-clear attempts do not pollute it. Impact: operators can diagnose bridge stalls and transport/runtime failures after the fact without exposing a Telegram-side debug command.
  • [Package Contents] The npm package uses an explicit allowlist and keeps the tracked lockfile. Impact: published tarballs exclude tests and internal context files while preserving predictable release contents.
  • [Validation] The project now ships typecheck, test, audit, package dry-run, and combined validate scripts plus GitHub Actions validation. Regression coverage spans rendering fixtures, queue/runtime/session behavior, command admission, lane contracts, invalid-lane rejection, setup, registration, replies, polling, updates, attachments, media, config, model resolution, preview timers, and extension-runtime flows. Impact: release checks catch type errors, dependency issues, package-content drift, rendering regressions, queue/lifecycle races, and architecture-boundary drift before publishing.
  • [Architecture Guards] Invariant tests enforce an acyclic local import graph, ban lib/constants.ts and lib/types.ts, keep empty interface-extension shells collapsed into clearer type aliases, centralize direct pi SDK imports, keep index.ts source code free of direct Node runtime imports, local helper declarations, local arrow adapters, direct process.env, and direct pi.* receiver access, keep runtime and structural leaf domains isolated, guard menu/model, API/config, media/update/API, and attachment/queue/media/API boundaries, and require project TypeScript files to keep responsibility headers. Impact: the Flat Domain DAG shape and file-boundary documentation stay protected as domains continue to evolve.
  • [Refactor] Reopened compression/decomposition/refactor/consistency passes tightened menu-domain message render/send plumbing, compressed repeated menu/media/attachment/runtime/API/model/queue test harness shapes, extracted shared runtime context, model-context, dispatch-event, Telegram config, deferred-response, API-response, rich-response, prompt-block, fetch-method, API response/client/fetch-restore, runtime fetch/model, model-test, queue-model, queue prompt/control/item-type, registration active-turn, menu-model, and pi API test fixtures, migrated runtime integration tests onto those fixtures, replaced ad hoc structural casts with owning-domain or test-local helpers where practical, and removed avoidable test casts from attachment, polling, update, model, reply, menu, pi-adapter, and registration suites. Impact: the codebase stays easier to extend without changing Telegram runtime behavior.

0.2.x: Fork Genesis

  • [Turns] Preserved existing attachment-path blocks and aborted-turn history context when a still-queued Telegram message is edited. Impact: caption edits no longer make queued prompts lose their downloaded file references or prior-message context.
  • [Polling] Persisted Telegram long-poll offsets only after each update is handled successfully. Impact: a handler failure no longer marks an unprocessed Telegram update as consumed, reducing the chance of silently dropping inbound messages.
  • [Telegram API] Added HTTP-status-aware Bot API response parsing, malformed-success handling, retry/backoff for 429 and 5xx Bot API responses, streaming Telegram downloads with size-limit checks, file-backed multipart upload blobs, partial-download cleanup on limit failures, startup cleanup for stale Telegram temp files, and UUID-based sanitized temp filenames. Impact: Telegram transport failures now report clearer status/description details, transient Telegram throttling/server failures get retried automatically, oversized inbound files are rejected before or during download, outbound multipart sends avoid preloading files into memory, partial and stale temp files are removed, and downloaded files are less prone to timestamp collisions or unsafe local names.
  • [Rendering] Escaped generated HTML attributes separately, sanitized code-fence language classes, and chunked raw HTML-mode output below Telegram length limits with balanced tag reopening across raw HTML chunks. Impact: generated Telegram HTML is harder to malformed through link or fence metadata and long raw-HTML replies no longer exceed Telegram's message size limit or break active tags across chunk boundaries.
  • [Preview] Serialized overlapping preview flushes through a single in-flight flush chain. Impact: rapid streaming updates no longer allow concurrent Telegram edit calls to overwrite newer preview text with stale snapshots.
  • [Polling] Added a bounded poisoned-update policy for repeatedly failing Telegram updates. Impact: one malformed or consistently failing update can no longer stall the long-poll loop forever; after the retry threshold, the bridge records and advances past it.
  • [Menu] Added short-lived model-menu input caching plus TTL/LRU cleanup for stored inline menu state. Impact: repeated /status and /model interactions do less settings/model-registry work, while old Telegram inline keyboards expire predictably instead of accumulating for the whole session.
  • [Updates] Routed Telegram edited_message updates separately from new messages and applied edits to matching queued turns. Impact: editing a still-queued Telegram message updates the pending prompt instead of enqueueing a duplicate turn.
  • [Refactor] Moved shared Telegram Bot API transport shapes out of index.ts into lib/types.ts. Impact: the entrypoint is smaller and future runtime extraction can reuse one type boundary instead of keeping local duplicate interfaces.
  • [Refactor] Moved Telegram media-group debounce and pending-group removal into the existing media domain with mirrored tests. Impact: album coalescing and reaction/delete cleanup are easier to validate without reading the full extension entrypoint, while avoiding an unnecessary extra domain file.
  • [Refactor] Extracted Telegram slash-command parsing and command-action routing into lib/commands.ts with mirrored tests, and moved queued-turn text replacement for edited messages into the turn domain. Impact: command normalization/execution planning and queued edit mutations are reusable, while the entrypoint keeps less local runtime state logic.
  • [Rendering] Hardened link rendering so absolute links stay clickable, markdown-heavy link labels reduce to plain clickable labels, tooltip titles are ignored safely, balanced-parenthesis URLs stay intact, and unsupported link forms degrade without broken anchors. Impact: Telegram replies now keep more links usable while avoiding malformed output for relative, reference-style, or footnote-like link syntax.
  • [Preview] Evolved rich streaming from first-chunk snapshots to stable-block previews with a conservative plain tail fallback, while preserving original blank-line spacing between rendered blocks and keeping headings visually separated from following blocks. Impact: closed top-level Markdown blocks now stream as rich Telegram HTML before finalization, incomplete fences, quotes, lists, and other trailing work remain readable without producing broken rich formatting, preview/final block spacing no longer collapses extra empty lines, and headings no longer visually merge into following code blocks when source Markdown omits a blank line.
  • [Refactor] Split preview concerns so runtime transport and finalization live in the preview domain while preview snapshot derivation lives in the rendering domain. Impact: rich streaming can evolve independently from final reply delivery while keeping preview appearance decisions closer to the Telegram renderer.
  • [Streaming] Switched Telegram previews from plain draft-first text to rich first-chunk message editing, so formatting appears during generation instead of only after finalization. Impact: users now see richer streamed output earlier, while final replies still replace the preview with fully rendered Telegram HTML.
  • [Rendering] Preserved leading indentation on the first Markdown line, kept numeric markers for ordered task lists in both preview and final Telegram rendering, and stopped reinterpreting standalone [x] or [ ] prose as inline checkboxes. Impact: nested content no longer flattens when a message starts with indentation, numbered checklists keep their ordered semantics, and literal checklist-like prose stays literal.
  • [Queue UI] Marked liked high-priority queued Telegram turns with in the pi status-bar queue preview. Impact: operators can now distinguish reaction-promoted turns from normal queued prompts at a glance.
  • [Docs] Added short responsibility header comments to every project .ts file. Impact: file boundaries are easier to understand while navigating the growing /lib split.
  • [Naming] Renamed extracted domain modules and mirrored regression suites to use repo-scoped bare domain filenames such as api.ts, queue.ts, and queue.test.ts instead of repeating telegram-* in every path. Impact: the internal topology is easier to scan and stays aligned with the repository-level Telegram scope.
  • [Controls] Expanded Telegram session controls with a richer /status view, inline model selection, and thinking-level controls, and fixed the callback-selection path so idle model and thinking picks apply immediately instead of only becoming visible after a later Telegram interaction. Impact: more bridge configuration can be managed directly from Telegram with more predictable immediate feedback.
  • [Queue] Upgraded Telegram turn queueing with previews, reaction-driven prioritization/removal, media-group handling, aborted-turn history preservation, and safer dispatch gating. Impact: follow-up handling is more transparent and less prone to lifecycle races.
  • [Rendering] Added Telegram-oriented Markdown rendering and hardened reply streaming/chunking behavior, including narrower monospace Markdown table output without outer side borders, monospace list markers for unordered and ordered lists, and flattened nested quote indentation inside a single Telegram blockquote. Impact: formatted replies render more reliably while preserving literal code blocks and using width more efficiently on narrow Telegram clients.
  • [Runtime] Hardened attachment delivery, polling/runtime behavior, Telegram session integration, preview-finalization and reply-transport routing into the replies domain, lazy Telegram API client routing into the Telegram API domain, turn-building extraction into its own domain, menu/model-resolution plus menu-state, pure menu-page derivation, pure menu render-payload builders, menu-message runtime, callback parsing, callback entry handling, callback mutation helpers, full model-callback planning and execution, and interface-polished callback effect ports into the menu domain, direct execute-from-update routing into the updates domain, model-switch restart glue extraction into the model-switch domain, and tool/command/lifecycle-hook registration extraction into a dedicated registration domain. Impact: the bridge is more robust as a daily Telegram frontend for pi.
  • [Metadata] Updated package repository metadata to point at the llblab/pi-telegram fork and renamed the npm package to @llblab/pi-telegram with public scoped publish settings. Impact: published package links no longer send users to stale upstream coordinates and the package can be published under the fork-owned npm scope.
  • [Validation] Added lightweight regression tests for Telegram Markdown rendering, queue/runtime/agent-loop/session/control/dispatch, replies, polling, updates, attachments, registration, turns, menu, and Telegram API/media/config helpers, including quote/list, table, link/code, mixed-link/code chunking, mixed-block chunk transitions, long multi-block, long-quote, long inline-formatting chunk boundaries, list-code-quote-prose chunk transitions, narrower monospace table rendering without outer side borders, monospace unordered and ordered list markers, flattened nested quote indentation inside one Telegram blockquote, inbound poll/pair/dispatch runtime cases, preview finalization, aborted-turn history carry-over, queued-status/model-after-agent-end sequencing, compaction gating, media-group debounce dispatch, direct menu callback planning and execution, pure menu-page derivation, pure menu render-payload builders, reaction-driven reprioritization/removal, immediate in-flight model-switch continuation, delayed abort-after-tool-completion, lazy Telegram API client routing, turn-building, and scoped-model resolution. Impact: key renderer and queue invariants now have repeatable automated coverage across the known high-risk bridge paths.
  • [Model Switching] Enabled /model during an active Telegram-owned run by applying the new model and continuing on the new model automatically, delaying the abort until the current tool finishes when needed. Impact: Telegram can now approximate pi's manual stop-switch-continue workflow with fewer mid-tool aborts.
  • [Queue Core] Introduced queued item kinds and explicit queue-lane ordering semantics so prompt turns and synthetic control actions share one ordering model, then regrouped the extracted helpers into flatter domain-oriented /lib modules such as queue, replies, polling, updates, attachments, turns, menu, Telegram API, and registration while keeping index.ts as the entrypoint. Prompt items now stay queued until agent_start consumes the dispatched turn, which restores correct active-turn binding for previews and final delivery. Impact: the bridge now has a clearer foundation for scheduling async extension operations alongside Telegram prompts without losing a single obvious runtime entry file.
  • [Registration] Moved extension tool, command, and lifecycle-hook binding into the registration domain and added registration-focused regression coverage. Impact: extension wiring is easier to reason about and test without dragging full runtime state into every registration change.
  • [Control Queue] Moved /status and /model command handling onto high-priority control queue items. Impact: control actions can wait safely behind the current run while still jumping ahead of normal queued prompts.
  • [Setup] /telegram-setup now shows the stored bot token first, otherwise prefills from common Telegram bot environment variables before falling back to the placeholder, using an actual prefilled editor when a real default exists. Impact: repeat setup respects local saved state while first-run and secret-managed setup stay fast.