From a6c5737c1099ca52bc942a7f7c107d1b3a0ba270 Mon Sep 17 00:00:00 2001 From: lodar Date: Mon, 20 Jul 2026 12:16:29 +0000 Subject: [PATCH] feat(telegram): route bulk 'Clear all recommended' gate-inbox tap (DIVE-1505) Add a 'gclearall' callback handler mirroring the per-gate gclear: tap but with no --only, so it shells 'task clear-recs --channel-proof=' across the whole agent-clearable set. The CLI re-verifies the channel-proof and only ever touches sub-T2 gates, so tier-2 hard gates keep their per-gate taps. Fully fail-soft. Pairs with the 5dive-cli digest button/hint (same DIVE-1505). Co-Authored-By: Claude Opus 4.8 --- plugins/telegram/.claude-plugin/plugin.json | 2 +- plugins/telegram/server.ts | 30 +++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/plugins/telegram/.claude-plugin/plugin.json b/plugins/telegram/.claude-plugin/plugin.json index ba40311..11c2c33 100644 --- a/plugins/telegram/.claude-plugin/plugin.json +++ b/plugins/telegram/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "telegram", "description": "Telegram channel for Claude Code \u2014 messaging bridge with built-in access control, bundled lifecycle hooks (AskUserQuestion intercept, Stop-reply safety net), and a notify-user comms-playbook skill. Fork of Anthropic's telegram plugin, maintained by 5dive.", - "version": "0.5.34", + "version": "0.5.35", "author": { "name": "5dive", "email": "support@5dive.com" diff --git a/plugins/telegram/server.ts b/plugins/telegram/server.ts index 3ceb962..7a5ee81 100644 --- a/plugins/telegram/server.ts +++ b/plugins/telegram/server.ts @@ -4206,6 +4206,36 @@ bot.on('callback_query:data', async ctx => { return } + // DIVE-1505: bulk 'Clear all recommended (sub-T2)' tap from the gate-inbox + // digest (CLI `task inbox --send`). Same rail as the per-gate gclear: tap but + // with no --only, so the CLI clears EVERY agent-clearable (blocked, tier<2, + // has a rec, not lead-routed) gate at once — the verified sender is the + // --channel-proof, re-verified CLI-side; tier-2 hard gates are untouched and + // keep their per-gate taps. Fully fail-soft. + if (data === 'gclearall') { + try { + const { stdout } = await execFileP( + SUDO, + ['-n', '5dive', 'task', 'clear-recs', `--channel-proof=${senderId}`, '--from=telegram', '--json'], + { timeout: 15000 }, + ) + const j = JSON.parse(stdout) + const cleared = Number(j?.data?.cleared ?? 0) + if (j?.ok && cleared > 0) { + await ctx.answerCallbackQuery({ text: `✅ Cleared ${cleared} recommended gate${cleared === 1 ? '' : 's'}` }).catch(() => {}) + // Drop the whole keyboard — the digest's gates are resolved/re-scoped now. + await ctx.editMessageReplyMarkup().catch(() => {}) + } else { + await ctx + .answerCallbackQuery({ text: 'Nothing cleared — hard gates need their per-gate tap, or all were answered.' }) + .catch(() => {}) + } + } catch { + await ctx.answerCallbackQuery({ text: "Couldn't clear — tap a gate or open the dashboard." }).catch(() => {}) + } + return + } + // DIVE-332: tap on an auto-rendered Yes/No question button (the reply tool // appends `yn:yes`/`yn:no` when an agent message ends in a single yes/no // question). Inject the plain 'yes'/'no' as a channel inbound — the same shape