#22095: feat: add Telegram inline buttons to exec approval requests
size: S
Cluster:
Telegram Inline Button Enhancements
## Summary
This PR enables Telegram-native inline button UX for exec approvals.
## Issue
- Fixes: #22078
## Root cause
- Exec approval forwarding previously sent approval requests through generic text payloads only:
- `src/infra/exec-approval-forwarder.ts` used `payloads: [{ text: ... }]`
- Telegram has first-class inline button support in outbound channelData, but exec-approval forwarding wasn’t populating it.
## Changes
- `src/infra/exec-approval-forwarder.ts`
- Added Telegram button construction for approval IDs.
- Requests now attach `channelData.telegram.buttons` for Telegram targets:
- ✅ Allow Once → `/approve <id> allow-once`
- 🔒 Always Allow → `/approve <id> allow-always`
- ❌ Deny → `/approve <id> deny`
- Kept existing text flow unchanged to preserve CLI/other-channel compatibility.
- `src/infra/exec-approval-forwarder.test.ts`
- Added regression test asserting Telegram approval requests include the expected inline-button payload.
## Behavior impact
- Telegram users now can approve/deny security-sensitive commands with one tap.
- Non-Telegram channels unchanged.
- No behavior change for already-resolved/expired payloads (they remain text-only notifications).
## Validation
- `pnpm test src/infra/exec-approval-forwarder.test.ts`
- `pnpm check`
## Confidence
- The logic is narrowly scoped and directly covered by a regression test.
- No data-shape or protocol contracts were changed outside this path.
- Callback data is within Telegram limits and routes through existing callback handler logic via synthetic message replay.
- Risk is low; this improves UX without changing approval semantics.
## Next (optional)
- Consider replacing old approval message buttons after resolve/expiry in a follow-up if desired for clean UX parity.
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Added Telegram inline buttons to exec approval requests for improved UX. When exec approvals are forwarded to Telegram channels, users now see three inline buttons (✅ Allow Once, 🔒 Always Allow, ❌ Deny) instead of just text instructions. The buttons send `/approve <id> <decision>` commands via `callback_data`, which are processed as synthetic text messages by the existing callback handler (src/telegram/bot-handlers.ts:1001-1009). Non-Telegram channels continue to receive text-only messages unchanged.
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk
- The change is narrowly scoped to a single UX enhancement path with comprehensive test coverage. The implementation correctly integrates with existing Telegram callback handling and approval command processing. No protocol changes or breaking modifications were introduced.
- No files require special attention
<sub>Last reviewed commit: ad3226c</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#9265: Feature: Telegram Inline Button Support for Exec Approvals
by vishaltandale00 · 2026-02-05
91.0%
#16102: Fix: Telegram Inline Button Support for Exec Approvals (builds on #...
by RoguePhoenix117 · 2026-02-14
86.7%
#14549: feat(telegram): add support for URL-type inline buttons
by kokosthief · 2026-02-12
81.8%
#19829: fix(telegram): fall back to default scope for array capabilities wi...
by NewdlDewdl · 2026-02-18
79.0%
#21346: [AI-assisted] Telegram: add reaction state machine with fallback an...
by Archie818 · 2026-02-19
77.1%
#19213: Telegram: preserve DM topic thread in direct replies
by Kemalau · 2026-02-17
76.7%
#12978: fix(telegram): use real message_id for inline button callback react...
by omair445 · 2026-02-10
76.6%
#19991: feat(telegram): callback direct mode with dedupe, button state, and...
by li-yifei · 2026-02-18
75.8%
#19102: Fix Telegram per-message link preview override
by Clawborn · 2026-02-17
75.6%
#20236: fix(telegram): make reaction handling soft-fail and message-id resi...
by PeterShanxin · 2026-02-18
75.5%