mirror of
https://github.com/wassname/pi-telegram.git
synced 2026-06-27 16:46:21 +08:00
15fa661b7a
The first-DM auto-pair behavior combined with ! shell passthrough meant
the first account to DM the bot gained arbitrary shell access. This
removes that footgun entirely.
- allowedUserId must be set before polling starts; missing config blocks
polling with a TUI warning rather than silently accepting any sender
- TELEGRAM_ALLOWED_USER_ID env var is read on session start and
overwrites the saved config value, so rotating the allowed user is a
restart away
- /telegram-setup now prompts for a numeric user ID after the bot token
if one is not already configured
- Denied senders receive an auth error reply; their numeric ID is also
logged to the pi TUI as a warning so operators can identify themselves
on a fresh install without needing @userinfobot
- Dropped the {kind: "pair"} authorization state entirely; undefined
allowedUserId now produces deny, not pair
- Removed pairTelegramUserIfNeeded, shouldPair, shouldNotifyPaired
Existing installs with allowedUserId already in telegram.json are
unaffected. Fresh installs require explicit configuration.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
8.4 KiB
8.4 KiB
Project Context
0. Meta-Protocol Principles
Constraint-Driven Evolution: Add structure when the bridge gains real operator or runtime constraintsSingle Source of Truth: Keep durable rules inAGENTS.md, open work inBACKLOG.md, completed delivery inCHANGELOG.md, and deeper technical detail in/docsBoundary Clarity: Separate Telegram transport concerns, pi integration concerns, rendering behavior, and release/documentation stateProgressive Enhancement + Graceful Degradation: Prefer behavior that upgrades automatically when richer runtime context exists, but always preserves a useful fallback path when it does notRuntime Safety: Prefer queue and rendering behavior that fails predictably over clever behavior that can desynchronize the Telegram bridge from pi session state
1. Concept
pi-telegram is a pi extension that turns a Telegram DM into a session-local frontend for pi, including text/file forwarding, streaming previews, queued follow-ups, model controls, and outbound attachment delivery.
2. Identity & Naming Contract
Telegram turn: One unit of Telegram input processed by pi; this may represent one message or a coalesced media groupQueued Telegram turn: A Telegram turn accepted by the bridge but not yet active in piActive Telegram turn: The Telegram turn currently bound to the running pi agent loopPreview: The transient streamed response shown through Telegram drafts or editable messages before the final reply landsScoped models: The subset of models exposed to Telegram model selection when pi settings or CLI flags limit the available list
3. Project Topology
/index.ts: Main extension entrypoint and runtime composition layer for the bridge/lib/*.ts: Flat domain modules for reusable runtime logic. Favor domain files such as queueing/runtime, replies, polling, updates, attachments, registration/hooks, Telegram API/config, turns, media, setup, rendering, menu/status/model-resolution support, and other cohesive bridge subsystems; usesharedonly when a type or constant truly spans multiple domains/tests/*.test.ts: Domain-mirrored regression suites that follow the same flat naming as/lib/docs/README.md: Documentation index for technical project docs/docs/architecture.md: Runtime and subsystem overview for the bridge/README.md: User-facing project entry point, install guide, and fork summary/AGENTS.md: Durable engineering and runtime conventions/BACKLOG.md: Canonical open work/CHANGELOG.md: Completed delivery history
4. Core Entities
TelegramConfig: Persisted bot/session pairing statePendingTelegramTurn/ActiveTelegramTurn: Queue and active-turn state for Telegram-originated workTelegramPreviewState: Streaming preview state for drafts or editable Telegram messagesTelegramModelMenuState: Inline menu state for status/model/thinking controlsQueuedAttachment: Outbound files staged for delivery throughtelegram_attach
5. Architectural Decisions
index.tsstays the single extension entrypoint, while reusable runtime logic should be split into flat domain files under/lib; prefer domain-oriented grouping over atomizing every helper into its own file, and usesharedsparingly for genuinely cross-domain types or constants- The bridge is session-local and restricted to a single pre-configured allowed Telegram user;
allowedUserIdmust be set before polling starts, either viaTELEGRAM_ALLOWED_USER_IDenv var or the/telegram-setupprompt; there is no auto-pair-on-first-DM behavior - Telegram queue state is tracked locally and must stay aligned with pi agent lifecycle hooks; queued items now have explicit kinds and lanes so prompt turns and synthetic control actions can share one ordering model, while dispatch still respects active turns, pending dispatch, compaction, and pi pending-message state
- Prompt items should remain in the queue until
agent_startconsumes the dispatched turn; removing them earlier breaks active-turn binding, preview delivery, and end-of-turn follow-up behavior - In-flight
/modelswitching is supported only for Telegram-owned active turns and is implemented as set-model plus synthetic continuation turn plus abort; if a tool call is active, the abort is delayed until that tool finishes instead of interrupting the tool mid-flight - Telegram replies render through Telegram HTML, not raw Markdown; real code blocks must stay literal and escaped
telegram_attachis the canonical outbound file-delivery path for Telegram-originated requests
6. Engineering Conventions
- Treat queue handling, compaction interaction, and lifecycle-hook state transitions as regression-prone areas; validate them after changing dispatch logic
- Treat Markdown rendering as Telegram-specific output work, not generic Markdown rendering; preserve literal code content, avoid HTML chunk splits that break tags, prefer width-efficient monospace table and list formatting for narrow clients, and flatten nested Markdown quotes into indented single-blockquote output because Telegram does not render nested blockquotes reliably
- Keep comments and user-facing docs in English unless the surrounding file already follows another convention
- Each project
.tsfile should start with a short multi-line responsibility header comment that explains the file boundary to future maintainers - Name extracted
/libmodules and mirrored/testssuites by bare domain when the repository already supplies the Telegram scope; preferapi.ts,queue.ts,updates.ts, andqueue.test.tsover redundanttelegram-*filename prefixes - Prefer targeted edits, keeping
index.tsas the orchestration layer and moving reusable logic into flat/libdomain modules when a subsystem becomes large enough to earn extraction; current extracted domains include queueing/runtime decisions, replies, polling, updates, attachments, registration and lifecycle-hook binding, Telegram API/config support, turn-building, media extraction, setup, rendering, status rendering, menu/model-resolution/UI support, and model-switch support
7. Operational Conventions
- When Telegram-visible behavior changes, sync
README.mdand the relevant/docsentry in the same pass - When durable runtime constraints or repeat bug patterns emerge, record them here instead of burying them in changelog prose
- When fork identity changes, keep
README.md, package metadata, and docs aligned so the published package does not point back at stale upstream coordinates - Work only inside this repository during development tasks; updating the installed Pi extension checkout is a separate manual operator step, not part of normal in-repo implementation work
8. Integration Protocols
- Telegram API methods currently used include polling, message editing, draft streaming, callback queries, reactions, file download, and media upload endpoints
- pi integration depends on lifecycle hooks such as
before_agent_start,agent_start,message_start,message_update, andagent_end ctx.ui.input()provides placeholder text rather than an editable prefilled value; when a real default must appear already filled in, preferctx.ui.editor()- For
/telegram-setup, prefer the locally saved bot token over environment variables on repeat setup runs; env vars are the bootstrap path when no local token exists - Status/model/thinking controls are driven through Telegram inline keyboards and callback queries
- Inbound files may become pi image inputs; outbound files must flow through
telegram_attach
9. Pre-Task Preparation Protocol
- Read
README.mdfor current user-facing behavior and fork positioning - Read
BACKLOG.mdbefore changing runtime behavior or documentation so open work stays truthful - Read
/docs/architecture.mdbefore restructuring queue, preview, rendering, or command-handling logic - Inspect the relevant
index.tssection before editing because most bridge behavior is stateful and cross-linked
10. Task Completion Protocol
- Run the smallest meaningful validation for the touched area;
npm testis the default regression suite once rendering or queue logic changes - For rendering changes, ensure regressions still cover nested lists, code blocks, underscore-heavy text, and long-message chunking
- For queue/dispatch changes, validate abort, compaction, pending-dispatch, and pi pending-message guard behavior
- Sync
README.md,CHANGELOG.md,BACKLOG.md, and/docswhenever user-visible behavior or real open-work state changes