SLOPSHOPPER

recording-mode

Toggle /recording to mask emails and secret-looking tokens in the AbovePrompt banner.

newbandcommand
A shopper browsing a rack in a slop shop
Preview · a replayed session in a sandbox
claude · ~/work/app · recording-mode
› fix the failing auth test and add an audit log call ⏺ Read(src/auth.ts) ⎿ Read 6 lines ⏺ Update(src/auth.ts) ⎿ Added 2 lines, removed 1 line ⏺ Bash(bun test) ⎿ 3 pass, 1 fail ● Done. refresh now rejects expired claims and logs an audit event. ✻ Worked for 42s · done 4:20 PM › /recording ⎿ recording-mode: Recording mode ON (redaction active). RECORDING — emails/secrets/amounts masked in banner ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── › ? for shortcuts

Draws

Band
RECORDING — emails/secrets/amounts masked in banner
README

recording-mode

Toggle /recording to mask emails and secret-looking tokens in the AbovePrompt banner.

Install

claude plugin marketplace add kenhuangus/claude-code-mods-pack
claude plugin install recording-mode@kenhuang-mods
Source 2 files
hooks/recording-mode.mjs 34 lines
1const MODE = { plugin: "recording-mode", key: "mode" };
2export function mask(text) {
3  let n = 0;
4  let out = String(text ?? "");
5  out = out.replace(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/gi, () => { n++; return "[EMAIL]"; });
6  out = out.replace(/\b(?:sk|pk|api|key|token|secret)[_-][A-Za-z0-9_]{8,}\b/gi, () => { n++; return "[SECRET]"; });
7  out = out.replace(/\$\s?\d[\d,]*(?:\.\d+)?/g, () => { n++; return "[AMOUNT]"; });
8  return { text: out, masked: n };
9}
10export function register(on) {
11  on("session.start", async ($, e, next) => {
12    const r = await next(e);
13    await $.state.set(MODE, { on: false, masked: 0 });
14    await $.command.register({ name: "recording", description: "Toggle recording/redaction mode: /recording on|off" });
15    return r;
16  });
17  on("command.run", { command: "recording" }, async ($, e) => {
18    const arg = String(e.args ?? e.text ?? e.input ?? "").toLowerCase();
19    const { value: cur } = await $.state.get(MODE);
20    let nextOn = !cur?.on;
21    if (/\boff\b/.test(arg)) nextOn = false;
22    if (/\bon\b/.test(arg)) nextOn = true;
23    await $.state.set(MODE, { on: nextOn, masked: cur?.masked ?? 0 });
24    return { text: `Recording mode ${nextOn ? "ON (redaction active)" : "OFF"}.` };
25  });
26  on("ui.render", { component: "AbovePrompt" }, async ($, e, next) => {
27    if (e.props?.hasSurvey) return next(e);
28    const { value: mode } = await $.state.get(MODE);
29    if (!mode?.on) return next(e);
30    const { Box, Text } = $.ui.resolve(e);
31    return Box({ paddingX: 1, children: [Text({ color: "red", bold: true, children: "RECORDING — emails/secrets/amounts masked in banner" })] });
32  });
33}
34
types/index.d.ts 8 lines
1declare module "claude-code" {
2  interface PluginState {
3    "recording-mode": {
4      mode: { on: boolean; masked: number };
5    };
6  }
7}
8