Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion plugins/telegram/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
30 changes: 30 additions & 0 deletions plugins/telegram/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading