SLOPSHOPPER

approve-blocked

Retries an auto-mode-blocked call up to three times so Claude Code's own permission prompt (and Moshi) can ask you.

newguard
v0.1.0no licenseupdated 2026-10-07adammhal/claude-mods/approve-blocked
A shopper browsing a rack in a slop shop
README

claude-mods

Claude Code mods.

left-undone

A sidebar that tracks what Claude said it would do and has not done yet. After each turn a small model audits Claude's reply: it adds new promises and closes the ones that were kept. Unfinished TodoWrite items show too.

Keys in the pane: a letter flags an entry, 1 sends the flagged ones back to Claude as "You left this undone: ...", 2 marks them done, 3 exports the list to ~/.claude/left-undone/latest.md, 4 imports it. /left-undone-export and /left-undone-import [path] do the same. The list is per session.

Install, typed at a Claude Code prompt:

/plugin install left-undone --marketplace <owner>/<repo>

Answer y to add the marketplace, then pick the user scope to have it in every session.

approve-blocked (experimental, untested)

When auto mode's classifier blocks a tool call, this retries the identical call up to three times so Claude Code's own permission prompt appears after three blocks in a row. It retries calls the classifier denied, so read its source before installing. Whether the retries count toward Claude Code's threshold is not confirmed.

/plugin install approve-blocked --marketplace <owner>/<repo>
Source 1 files
hooks/register.ts 27 lines
1import type { Register } from 'claude-code'
2
3const BLOCKED = /denied by the Claude Code auto mode classifier/i
4const TRIES = 3
5
6const blockedBy = (r: { deny?: string; isError?: boolean; text?: string }) => {
7  const why = r.deny ?? (r.isError === true ? r.text : undefined)
8  return typeof why === 'string' && BLOCKED.test(why)
9}
10
11export const register: Register = on => {
12  // Claude Code falls back to its own permission prompt after 3 blocks in a row,
13  // and that prompt is the one Moshi answers. Agents stop at the first block, so
14  // the same call is retried here until the third, which is the one that asks.
15  on('tool.call', async ($, e, next) => {
16    let ran = await next(e)
17    if (!blockedBy(ran) || e.tool === 'AskUserQuestion') return ran
18
19    const { tool, tool_use_id: _id, agentId: _agent, ...input } = e
20    for (let i = 1; i < TRIES && blockedBy(ran); i++) {
21      ran = await $.tool.call({ tool, ...input } as never)
22    }
23
24    return ran
25  })
26}
27