SLOPSHOPPER

spend-delete-ask

Asks the operator before any tool that moves money, spends a balance or deletes something a session cannot restore (Stripe, PayPal, QuickBooks, link carts…

newtoast
A shopper browsing a rack in a slop shop
README

bbm-mods

Read-only public mirror of the Claude Code mods (plugins) that Brand Bridge Media sessions run. The source of truth is claude-mods/ in the private bbm-infrastructure repo; every merge there that touches a mod overwrites this repo with a fresh snapshot. Edits made here are lost on the next sync.

Pull requests are not accepted. One opened by anyone but the owner is closed automatically and the owner is notified.

Install (what the cloud environment setup script runs):

claude plugin marketplace add brand-bridge-media/bbm-mods
claude plugin install fleet-tracker@bbm-mods --scope user
Source 2 files
hooks/register.ts 16 lines
1import type { Register } from 'claude-code'
2
3import { askFor } from './logic'
4
5// Why (LCH-528): money-moving and destructive tools were a sentence in the operator's preferences. This
6// puts the call in front of them through the engine's own permission prompt. The list is ./logic.ts.
7export const register: Register = on => {
8  on('classic.PreToolUse', { tool: /^mcp__/ }, async ($, e, next) => {
9    const ask = askFor(String((e as any).tool ?? ''))
10    if (ask === undefined) return next(e)
11    try { $.ui.toast(ask) } catch { /* a toast never changes the ask */ }
12    return { ask }
13  // Fail open: a bug here must never stop a tool call.
14  }).catch(($, e, next) => next(e))
15}
16
hooks/logic.ts 72 lines
1// Which tool calls ask the operator first (LCH-528, operator gate: irreversible money/data).
2// Kept as a list, not a pattern: a broad `*__delete_*` would also ask before routine,
3// reversible cleanup (a session deleting its own scheduled check-in) and stall unattended
4// sessions. A tool named here asks; anything else is untouched.
5
6/** Every tool on these MCP servers moves money. */
7export const MONEY_SERVERS = ['mcp__Stripe__']
8
9/** Tools that bill, invoice, buy or spend a finite balance. */
10export const MONEY_TOOLS: readonly string[] = [
11  'mcp__PayPal__create_invoice',
12  'mcp__PayPal__create_bulk_invoices',
13  'mcp__PayPal__send_invoice',
14  'mcp__PayPal__send_bulk_invoices',
15  'mcp__PayPal__create_payment_link',
16  'mcp__Insert_Link__add_guest_post_to_cart',
17  'mcp__Insert_Link__add_link_insertion_to_cart',
18  'mcp__Roominate__create_scene',
19  'mcp__Roominate__create_from_product',
20  'mcp__Roominate__add_product_to_room',
21  'mcp__Roominate__edit_image',
22  'mcp__Roominate__make_video',
23  'mcp__Roominate__publish_to_store',
24  'mcp__plugin_small-business_intuit-quickbooks__qbo_sales_create_invoice',
25  'mcp__plugin_small-business_intuit-quickbooks__qbo_sales_send_invoice',
26  'mcp__plugin_small-business_intuit-quickbooks__qbo_sales_create_recurring_invoice',
27  'mcp__plugin_small-business_intuit-quickbooks__qbo_sales_create_payment_link',
28  'mcp__plugin_small-business_intuit-quickbooks__qbo_sales_send_payment_link',
29  'mcp__plugin_small-business_intuit-quickbooks__qbo_payroll_create_employee',
30  'mcp__plugin_small-business_intuit-quickbooks__money_onboarding_application_submit',
31  'mcp__plugin_small-business_intuit-quickbooks__quickbooks_transaction_import',
32]
33
34/** Deletes and trash on systems with no undo from a session. */
35export const DESTRUCTIVE_TOOLS: readonly string[] = [
36  'mcp__Airtable__delete_records_for_table',
37  'mcp__Airtable__delete_table',
38  'mcp__Airtable__delete_automation',
39  'mcp__Airtable__delete_interface',
40  'mcp__Airtable__delete_page',
41  'mcp__Notion__notion-delete-pages',
42  'mcp__Notion__notion-delete-databases',
43  'mcp__Google_Drive__trash_file',
44  'mcp__GitHub_Custom__delete_repository',
45  'mcp__GitHub_Custom__delete_file',
46  'mcp__github__delete_file',
47  'mcp__Cloudflare_Developer_Platform__d1_database_delete',
48  'mcp__Cloudflare_Developer_Platform__kv_namespace_delete',
49  'mcp__Cloudflare_Developer_Platform__r2_bucket_delete',
50  'mcp__Cloudflare_Developer_Platform__hyperdrive_config_delete',
51  'mcp__Supabase__delete_branch',
52  'mcp__Supabase__reset_branch',
53  'mcp__Supabase__pause_project',
54  'mcp__Tailwind_-_Pinterest__delete_board',
55  'mcp__Beehive__delete_podcast_show',
56  'mcp__Beehive__delete_podcast_episode',
57]
58
59const MONEY = new Set(MONEY_TOOLS)
60const DESTRUCTIVE = new Set(DESTRUCTIVE_TOOLS)
61
62/** The ask text for a tool, or undefined when it does not ask. */
63export function askFor(tool: string): string | undefined {
64  if (MONEY.has(tool) || MONEY_SERVERS.some(p => tool.startsWith(p))) {
65    return `[mod:spend-delete-ask] ${tool} moves money or spends a balance. Approve only if the operator asked for exactly this.`
66  }
67  if (DESTRUCTIVE.has(tool)) {
68    return `[mod:spend-delete-ask] ${tool} deletes something a session cannot restore. Approve only if the operator asked for exactly this.`
69  }
70  return undefined
71}
72