SLOPSHOPPER

retry-flaky

Retries browser and Linear MCP tool calls twice when the connection dropped before the call ran.

newguardtoast
v0.1.0no licenseupdated 2026-10-01howells/howells-plugins/mods/retry-flaky
A shopper browsing a rack in a slop shop
Source 1 files
hooks/register.ts 39 lines
1import type { Register } from 'claude-code'
2
3const RETRIES = 2
4const PAUSE_MS = 1500
5
6const FLAKY = /^mcp__(claude-in-chrome|Claude_Browser|claude_ai_Linear|plugin_linear_linear)__/
7
8// Only errors that mean the call never reached the tool: a retry cannot repeat a write.
9const DROPPED =
10  /not connected|ECONNREFUSED|socket hang up|connection (closed|refused)|extension (is not|not|was) (connected|running|available)|no (browser|extension) (connected|available)|MCP error -32000/i
11
12export const register: Register = on => {
13  on('tool.call', async ($, e, next) => {
14    const tool = String(e.tool)
15    let ran = await next(e)
16
17    if (!FLAKY.test(tool)) {
18      return ran
19    }
20
21    for (let attempt = 1; attempt <= RETRIES; attempt += 1) {
22      const hasDropped = ran.deny === undefined && ran.isError === true && DROPPED.test(ran.text ?? '')
23
24      if (!hasDropped || next.signal.aborted) {
25        return ran
26      }
27
28      await $.clock.sleep(PAUSE_MS)
29      ran = await next(e)
30
31      if (ran.deny === undefined && ran.isError !== true) {
32        $.ui.toast(`retry-flaky: ${tool.split('__')[1]} recovered on retry ${attempt}`)
33      }
34    }
35
36    return ran
37  })
38}
39