Fix: Telegram approval keyboard missing session grant buttons
Problem
The TUI approval prompt offers five choices: approve once (y), grant the category for the session (s), grant the binary shape for the session (a), deny (n), or redirect to a different path (e).
But the Telegram inline keyboard only offers "Approve" and "Deny".
This means Telegram users get bombarded with repeated approval prompts for the same type of command. Every cargo run, every git diff, every ls triggers the same prompt, over and over. The only escape is raising approvalLevel to 5 (too permissive) or editing config.json by hand.
Root cause
ApprovalBridge.buildKeyboard() only builds y/n callback payloads. The gate already supports grant: "category" and grant: "shape" scopes, canGrantCategory() and canGrantShape() helpers exist, and ApprovalRequest already carries commandShape — the bridge just never wired the extra buttons.
Proposed fix
Two things:
- Add
s (grant category) button as a second row when canGrantCategory() returns true
- Add
a (grant shape) button as a third row when canGrantShape() returns true (shell commands only)
Then extend handleCallback() to parse the s/a callback kinds and pass the matching grant scope to ApprovalGate.resolve(). The recordGrant path in the gate already handles everything downstream.
Impact
- Reuses existing gate infrastructure — no new logic, just new buttons reach existing code paths
- Callback data stays well within Telegram's 64-byte limit
- Zero new dependencies
- Telegram users can now
s-grant a category once instead of approving 20 times
Files touched
Only src/channels/telegram/approval-bridge.ts and its test file.
Fix: Telegram approval keyboard missing session grant buttons
Problem
The TUI approval prompt offers five choices: approve once (
y), grant the category for the session (s), grant the binary shape for the session (a), deny (n), or redirect to a different path (e).But the Telegram inline keyboard only offers "Approve" and "Deny".
This means Telegram users get bombarded with repeated approval prompts for the same type of command. Every
cargo run, everygit diff, everylstriggers the same prompt, over and over. The only escape is raisingapprovalLevelto 5 (too permissive) or editing config.json by hand.Root cause
ApprovalBridge.buildKeyboard()only buildsy/ncallback payloads. The gate already supportsgrant: "category"andgrant: "shape"scopes,canGrantCategory()andcanGrantShape()helpers exist, andApprovalRequestalready carriescommandShape— the bridge just never wired the extra buttons.Proposed fix
Two things:
s(grant category) button as a second row whencanGrantCategory()returns truea(grant shape) button as a third row whencanGrantShape()returns true (shell commands only)Then extend
handleCallback()to parse thes/acallback kinds and pass the matchinggrantscope toApprovalGate.resolve(). TherecordGrantpath in the gate already handles everything downstream.Impact
s-grant a category once instead of approving 20 timesFiles touched
Only
src/channels/telegram/approval-bridge.tsand its test file.