SLOPSHOPPER

secret-mask

Mask token-like strings in tool output before they reach the conversation

newguardcommandtoast
A shopper browsing a rack in a slop shop
Preview · a replayed session in a sandbox
claude · ~/work/app · secret-mask
› fix the failing auth test and add an audit log call ╭────────────────────────────────╮ │ secret-mask │ ⏺ Read(src/auth.ts) │ Masked 1 possible token (Bash) │ ⎿ 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 › /secret-mask ⎿ secret-mask: masking on, 1 masked ⎿ secret-mask: - Bash ×1 cat .env ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── › ? for shortcuts
README

<h1 align="center">Awesome Claude Code Mods</h1>

<a id="showcase"></a>

Mod showcase

<table> <tr><td width="33%" align="center" valign="top"><p><a href="https://github.com/therahul-yo/clawdman"><img src="assets/showcase-01.gif" width="100%" alt="Clawdman: An animated companion that reacts to your coding session. Demo · 10×."></a></p><p><strong><a href="https://github.com/therahul-yo/clawdman">Clawdman</a></strong></p></td><td width="33%" align="center" valign="top"><p><a href="AgentMods/pi-agent/"><img src="assets/showcase-02.gif" width="100%" alt="Pi Agent: Run pi-powered models as native Claude Code subagents. Demo · 10×."></a></p><p><strong><a href="AgentMods/pi-agent/">Pi Agent</a></strong></p></td><td width="33%" align="center" valign="top"><p><a href="FocusMods/breathing-exercises/"><img src="assets/showcase-03.gif" width="100%" alt="Breathing Exercises: A guided breathing animation while Claude works."></a></p><p><strong><a href="FocusMods/breathing-exercises/">Breathing Exercises</a></strong></p></td></tr> <tr><td width="33%" align="center" valign="top"><p><a href="sources/creative-toolkit/"><img src="assets/showcase-04.png" width="100%" alt="Creative Toolkit: A collection of live panels, session tools and playful mods. Code Pet screenshot."></a></p><p><strong><a href="sources/creative-toolkit/">Creative Toolkit</a></strong></p></td><td width="33%" align="center" valign="top"><p><a href="GameMods/agent-cartoons/"><img src="assets/showcase-05.gif" width="100%" alt="Agent Cartoons: Coding activity becomes a cartoon in a choice of visual styles."></a></p><p><strong><a href="GameMods/agent-cartoons/">Agent Cartoons</a></strong></p></td><td width="33%" align="center" valign="top"><p><a href="https://github.com/adamholter/claude-subway-surfers"><img src="assets/showcase-06.gif" width="100%" alt="Subway Surfers Desktop: Gameplay beside Claude Desktop while it works. Desktop demo · 10×."></a></p><p><strong><a href="https://github.com/adamholter/claude-subway-surfers">Subway Surfers Desktop</a></strong></p></td></tr> <tr><td width="33%" align="center" valign="top"><p><a href="GameMods/dino-game/"><img src="assets/showcase-07.gif" width="100%" alt="Dino Game: Play the T-rex runner above your prompt."></a></p><p><strong><a href="GameMods/dino-game/">Dino Game</a></strong></p></td><td width="33%" align="center" valign="top"><p><a href="GameMods/spell-bar/"><img src="assets/showcase-08.gif" width="100%" alt="Spell Bar: An animated spell bar for your selected effort level."></a></p><p><strong><a href="GameMods/spell-bar/">Spell Bar</a></strong></p></td><td width="33%" align="center" valign="top"><p><a href="AgentMods/agent-dashboard/"><img src="assets/showcase-09.gif" width="100%" alt="Agent Dashboard: A live dashboard for context, costs, permissions and agents."></a></p><p><strong><a href="AgentMods/agent-dashboard/">Agent Dashboard</a></strong></p></td></tr> </table>

<a id="browse-by-category"></a>

<h2>Browse by category <img src="assets/category-magnifier.gif" width="52" height="40" alt="Clawd with a magnifying glass"></h2>

Usage Mods · Agent Mods · Planning Mods · File Mods · Git Mods · Safety Mods · Memory Mods · Interface Mods · Prompt Mods · Testing Mods · Web Mods · Focus Mods · Game Mods · Integration Mods

Source packages available here: 82 mods from 38 repositories, with their complete tracked files and notices. Local package links open inside this collection. Other entries currently lead to upstream references while the wider source import is reviewed.

Entries are grouped by their main purpose. Collections can contain several kinds of mods; hosted mod pages are categorized individually.

<a id="usage"></a>

Usage Mods

Browse Usage Mods

Track model usage, costs, effort and quotas.

  • Auto Effort · arthur-fontaine - Let Jev select Claude's reasoning effort for each prompt, adapting the configured effort level to the incoming request rather than choosing it manually every time.
  • Automatic Model and Effort Router · sofanaja44 - Choose a Claude model and reasoning effort according to task difficulty, with rules that limit unnecessary prompt-cache rewrites. Cost and cache statistics help you follow the routing decisions.
  • Braille Usage · kawase1295 - Check your current model, context usage and five-hour or weekly limits in compact text-based meters above the prompt.
  • Budget and Context Toolkit · Arunjay4213 - Track session spending, subscription quotas, cache use and per-turn token costs. Set budget limits that warn before exhaustion and stop tool calls when a configured limit is exceeded.
  • Budget Governor · ccdwyer - Set session and daily spending caps, monitor them above the prompt, and receive a wrap-up reminder at eighty percent. New prompts are refused once the cap is reached.
  • Cache, Context and Cost Panel · anthonyhungnguyen - Track token spending for the session and recent days, get context-limit warnings, and see what rebuilding the prompt cache cost. A completion alert announces long turns.
  • Clawd Usage Meters · Toshkee - Watch live context, rate-limit and cost meters above the prompt, accompanied by Clawd's wand animations and banner tricks as you work in Claude Code.
  • Cockpit and Bodyguard · Para-FR - Inspect session turns, tools, tokens, durations and changed files in a live cockpit. A companion guard blocks access to .env files and destructive Bash commands, displaying blocked-action alerts.
  • Context and Quota Forecast · imsalik - See a context forecast alongside five-hour and weekly rate-limit usage above the prompt. Reset countdowns help you understand when each plan allowance becomes available again.
  • Context Saver · AlmogBaku - Spot repeated tool calls and wasteful workflows during a Claude Code session. Review their measured time and context cost, then send a suggested correction with one click.
  • Context Weather and Usage · travisoa - Read context fullness as changing weather symbols alongside token totals and quota consumption. Recent-turn bars show how the conversation grew, helping you spot increasing pressure on the context window.
  • Cost and Output Token Band · Luma-Sa - Keep five-hour and seven-day usage limits, session cost and output-token totals visible in a band above the Claude Code prompt while you work.
  • Cost Meter · zaferayan - Track API-equivalent session cost above the prompt, including subagent usage, with a configurable budget warning. On subscription plans, the displayed amount estimates API pricing rather than your bill.
  • Desktop Next Steps and Limits · shichang4fun - See quota limits and reset countdowns above the prompt in Claude Code Desktop. After each turn, suggested next prompts can be sent with a click or copied for editing.
  • Desktop Session Status Bar · sgmonda - Keep five-hour and weekly usage limits, reset times, session clocks and turn duration visible in Claude Code Desktop. The bar also lists active subagents, background jobs and scheduled wakeups.
  • Desktop SVG Usage Meters · s-hiraoku - See context use and the five-hour and seven-day quota windows as SVG meters above the prompt in Claude Code Desktop. The compact display keeps capacity visible while you work.
  • Effort Guard · stefanochieli - Track context and token usage, review an effort log for each turn and receive an escalation alert after repeated command or test failures. It observes activity without blocking it.
  • Effort Router · totally-tim - Choose reasoning effort for each turn with Jev or a compatible classifier, and display the selected level. Shadow mode records the recommendation; enforce mode applies it to the session.
  • Effort Shortcut · daanqq - Cycle Claude's reasoning effort through low, medium, high, and extra-high with one command. Bind that command to a key to change effort quickly while skipping the maximum setting.
  • Focus Band · chaoshengsc - Keep your five-hour and weekly plan usage visible above the prompt. Progress bars, percentages, and reset times help you see how much of each allowance you have used.
  • Jet Router · jetsongdev - Experiment with per-turn reasoning effort recommendations while keeping your chosen model. Use fixed test decisions or opt into Jev classification, with observation and optional application modes.
  • Jev Claude Router · Flam1ngFir3ball - Let Jev choose the model and reasoning effort for each turn while considering the cost of switching. It also provides Jev-guided context compaction.
  • Jev Model and Effort Selection · unclecode - Observe or pin model and effort choices, or opt into automatic selection with Jev. The experimental router lets you compare recommendations before allowing them to steer the session.
  • Jev Model Router · satviksinha - Choose a model and reasoning effort for each turn using TypeSafe's Jev, through its direct API or Vercel AI Gateway. A visible routing decision shows which model will handle the work.
  • Jev Route · drewpayment - Choose a Claude model for each turn using Jev's estimate of what the task needs. Toggle routing with /route to balance model capability against cost.
  • Limitpace · fstandhartinger - Track subscription limits and spending pace through live usage bars. An optional delegation adviser can suggest using another provider as part of managing your available capacity.
  • Model and Effort Router · moritalous - Choose reasoning effort for each prompt while keeping the model fixed, or enable a separate router that selects Haiku, Sonnet, or Opus using Jev. Both tools adjust resources per turn.
  • Model Shortcuts · richkuo - Use keyboard shortcuts to switch models and adjust reasoning effort, with the active choices displayed in the prompt footer.
  • Netrunner HUD · ccdwyer - Watch context use, token activity, tool calls, costs, and job status in an animated cyberpunk dashboard. Git and test widgets keep related session information alongside the live usage gauges.
  • Next Steps and Usage Band · pawandeepdhall - Keep five-hour and weekly usage limits visible with reset countdowns, and choose from suggested next steps after each reply. Buttons also provide shortcuts for starting a new chat or pushing work.
  • Oxide Jev Model Router · Kiy-K - Use Jev to choose subagent models and adjust the main conversation's model and reasoning effort as work progresses. A built-in classifier provides a fallback without an API key.
  • Plan and Context Usage Line · KhadeerBasha1232 - Track five-hour and weekly plan limits, reset times, context usage, the active model and session cost in one line above the Claude Code prompt.
  • Plan Usage and Reset Times · jumoog - Keep five-hour and weekly plan usage visible above the prompt, together with each reset time. Check the current allowance windows without opening a separate usage screen.
  • Power Bottom Status Line · brianSchanbacher - See the model, folder, branch, context fill, cost, elapsed time, cache hits and live agents in a cross-platform status line at the bottom of Claude Code.
  • Project Spend and Cache Status · Sma1lboy - Track project spending alongside context usage, cache hits and the cache countdown. Inspect why a turn missed the cache, and open the project ledger with /usage.
  • Prompt Enhancement and Telemetry · MiguelMachado-dev - Inspect per-turn duration, first-token latency, token throughput, requests and stalls in a live band. An additional command rewrites a draft prompt with Sonnet and returns it for your review.
  • Prompt Footer Usage · WoBok - Keep context usage and rate-limit consumption visible in Claude Code's prompt footer, so you can check those readings without opening a separate usage view.
  • Prompt Usage Timeline · augiefra - Compare five-hour and weekly usage with elapsed time, inspect token bars for recent prompts and watch context status above the prompt. Labels are available in English or French.
  • Quota and Cost Pills · Sh0ckWaveZero - Track five-hour and seven-day rate limits, session tokens and cost in compact indicators above the prompt. The band can sit alongside other status bands.
  • Quota Reserve · chrisns - Reserve part of your five-hour and weekly quota for later work. The mod pauses at configured thresholds, asks whether to continue, and releases the reserve shortly before the reset.
  • Rate-Limit History Band · mohammed-alsalhi - Follow rate-limit consumption since each window last reset, including five-hour, weekly, and per-model weekly allowances. A band above the prompt graphs how usage accumulates over time.
  • Retro Usage Band · iamkhalid2 - Keep your plan's five-hour and weekly usage limits in view through a slim retro-style band above the prompt. Check both allowances as you work.
  • Sessclone · NotTahaAli - Send Claude Code usage to a SessClone deployment so laptop, cloud and CI sessions can contribute to a shared team ledger of usage and cost.
  • Session and Weekly Usage Band · Gooner44 - See session, weekly and Fable 5.1 usage together in a band above the Claude Code prompt, keeping these separate usage readings visible while you work.
  • Session Cockpit · nvr0x5 - Track context, spending, usage limits, reset countdowns and burn rates above the prompt. Plan progress and active subagents share the same cockpit, with display options for terminal and Desktop sessions.
  • Session Cost and Remaining Usage · HydrowZer - See the current session cost and remaining usage in a band above the Claude Code prompt, keeping spending and available capacity visible beside your conversation.
  • Session Dashboard and Alerts · lucenity0 - Follow turn durations, token counts, files touched, and tool activity through a timer and dashboard. Companion mods notify you when long turns finish and block destructive commands or edits to secrets.
  • Session Internals Dashboard · tomstagl - Inspect context, tokens, cost, limits, tools and agents in a live side-pane dashboard. An accompanying insights interface lets the session answer questions using the displayed measurements.
  • Session Sidebar · richard-parayno - Toggle a sidebar showing usage limits, context size, prompt-cache expiry, current activity and touched files. It keeps the session's resource picture visible beside the conversation.
  • Stack and Wait Time · ShahriarBijoy - Follow tasks, subagents, rate limits and monthly cost in a stacked progress band. A companion vocabulary game uses German words related to the session's topic while Claude works.
  • Terminal Usage Monitor · ilkayGkbdk - Monitor context fill, rate limits, token speed, cost, and active subagents in a live terminal dashboard. The display brings the session's resource use together in one place.
  • Turn Receipts and Error Cues · roaringsoul404 - Receive a receipt after each turn listing touched files, commands, tokens and cost. A companion animation turns the spinner into a pixel-art failure cue when a tool call fails.
  • Usage and Active Agent Dashboard · quango2304 - Follow usage bars, limits, session cost, cache expiry and active time alongside the agents currently running. The combined display makes resource consumption visible while work is underway.
  • Usage and Cache Warmth Band · Vosssa - See five-hour and weekly usage, context fill and prompt-cache warmth together above the Claude Code prompt, keeping the main resource readings visible while you work.
  • Usage and Spend Chips · kreddevils18 - Track five-hour and weekly allowances, session cost, and spending history through colored chips above the prompt. Open /usage-mod for a fuller view of the usage details.
  • Usage Line · Steven-ODell - See five-hour, weekly and context usage in the prompt footer, including whether consumption is ahead of or behind an even pace through the usage window.
  • Usage Log · tanuu5 - Record five-hour and weekly usage after each turn, then compare consumption with your chosen pace in a graph. The separate Clawd Dance mod can also show that pacing above the prompt.
  • Usage Report · Schweem - Monitor context usage, five-hour and weekly quotas, and session cost in the status line, with warnings as you approach your limits.
  • Usage Wrapup · DaKev - Ask running agents to wrap up when your remaining plan allowance gets low, helping them finish their current work before the usage limit interrupts it.
  • Weekly Usage and Spend Board · aycandv - Compare spending by model with a weekly-limit pace gauge, using a sliding ticker in the terminal or a strip and details pane in the desktop app.

<a id="agents"></a>

Agent Mods

Browse Agent Mods

Coordinate agents and follow their actual work.

  • 5dive Telemetry Toolkit · 5dive-ai - Connect Claude Code sessions to 5dive's task and gate controls, with a panel showing assignments and token budgets. Optional telemetry, compaction and tool-call policies support coordinated agent work.
  • Agent Control and Document Desk · masahide - Send messages and interruption requests to Claude through the agentctl command line and collect acknowledgments. A companion document desk gathers questionnaire answers and detailed document-review comments in a browser, then delivers them to Claude.
  • Agent Dashboard · scasella - Monitor the main agent and its subagents in a live dashboard that brings together model usage, permission requests, task activity and session logs.
  • Agent Flow · Charlie0113-T - Open /flow to follow a live tree of the session's subagents and teammates beside the transcript. A text view is available where panes cannot be displayed.
  • Agent Models and Peek · alex2481kobe - Show each subagent's model and reasoning effort beside its task in the native agent list. A companion viewer displays images inline, using real pixels or a terminal-compatible block
Source 4 files
hooks/register.ts 147 lines
1import { atom, read, update } from 'claude-code'
2import type { EngineInterface, Register } from 'claude-code'
3
4import { STRINGS, langOf } from './i18n'
5import type { Strings } from './i18n'
6import { maskText } from './mask'
7
8const hits = atom({ plugin: 'secret-mask', key: 'hits' } as const, [])
9const isOff = atom({ plugin: 'secret-mask', key: 'isOff' } as const, false)
10
11// 這幾個工具的結果是 Claude 之後要拿來改檔的原文,遮了會讓 Edit 對不上或寫回壞掉的值
12const EXEMPT = new Set(['Read', 'Edit', 'Write', 'NotebookEdit'])
13
14type Block = { type: string; [field: string]: unknown }
15
16// 記錄失敗也要讓遮蔽照常生效,所以錯誤吞掉只留 debug log
17const record = async ($: EngineInterface, t: Strings, tool: string, where: string, count: number) => {
18  const hit = { tool, where: maskText(where, t.mark).text.slice(0, 60), count }
19
20  try {
21    await update($, hits, list => [...list, hit].slice(-100))
22    $.ui.toast(t.toast(count, tool))
23  } catch {
24    $.ui.log('secret-mask: could not record hit', { to: 'debug' })
25  }
26}
27
28// 遮一個 tool_result block 的內容,回傳新 block 和遮了幾處
29const maskResult = (block: Block, mark: string): { block: Block; count: number } => {
30  const { content } = block
31
32  if (typeof content === 'string') {
33    const masked = maskText(content, mark)
34
35    return { block: { ...block, content: masked.text }, count: masked.count }
36  }
37  if (!Array.isArray(content)) {
38    return { block, count: 0 }
39  }
40
41  let count = 0
42  const parts = (content as Block[]).map(part => {
43    if (part.type !== 'text' || typeof part.text !== 'string') {
44      return part
45    }
46    const masked = maskText(part.text, mark)
47    count += masked.count
48
49    return { ...part, text: masked.text }
50  })
51
52  return { block: { ...block, content: parts }, count }
53}
54
55export const register: Register = (on, options) => {
56  const t = STRINGS[langOf(options)]
57  const commands = new Map<string, string>()
58
59  on('session.start', async ($, e, next) => {
60    await $.command.register({
61      name: 'secret-mask',
62      description: t.description,
63      argumentHint: '[off|on]',
64    })
65
66    return next(e)
67  })
68
69  // Bash 的 stdout / stderr 在來源就換掉,畫面和對話紀錄都看不到原值
70  on('tool.call', { tool: 'Bash' }, async ($, e, next) => {
71    commands.set(e.tool_use_id, e.command)
72    const ran = await next(e)
73
74    if (ran.deny !== undefined || ran.isError === true || (await read($, isOff))) {
75      return ran
76    }
77
78    const out = maskText(ran.result.stdout, t.mark)
79    const err = maskText(ran.result.stderr, t.mark)
80    const count = out.count + err.count
81
82    if (count === 0) {
83      return ran
84    }
85    await record($, t, 'Bash', e.command, count)
86
87    return {
88      result: { ...ran.result, stdout: out.text, stderr: err.text },
89      ...(ran.context === undefined ? {} : { context: ran.context }),
90    }
91  })
92
93  // 其他工具和 Bash 的錯誤輸出在寫進對話時遮,模型讀到的是遮過的
94  on('session.append', { door: 'tool-result' }, async ($, e, next) => {
95    const tool = e.origin.kind === 'tool' ? e.origin.tool : 'unknown'
96
97    if (EXEMPT.has(tool) || (await read($, isOff))) {
98      return next(e)
99    }
100
101    let total = 0
102    let where = tool
103    const content = e.message.content.map(block => {
104      if (block.type !== 'tool_result') {
105        return block
106      }
107      const masked = maskResult(block, t.mark)
108
109      if (masked.count > 0 && typeof block.tool_use_id === 'string') {
110        where = commands.get(block.tool_use_id) ?? tool
111      }
112      total += masked.count
113
114      return masked.block
115    })
116
117    if (total === 0) {
118      return next(e)
119    }
120    await record($, t, tool, where, total)
121
122    return next({ ...e, message: { ...e.message, content } })
123  })
124
125  on('command.run', { command: 'secret-mask' }, async ($, e) => {
126    const arg = e.args.trim()
127
128    if (arg === 'off' || arg === 'on') {
129      await update($, isOff, () => arg === 'off')
130
131      return { text: arg === 'off' ? t.off : t.on }
132    }
133
134    const list = await read($, hits)
135    const state = t.state(await read($, isOff))
136
137    if (list.length === 0) {
138      return { text: t.none(state) }
139    }
140
141    const total = list.reduce((sum, hit) => sum + hit.count, 0)
142    const lines = list.map(hit => `- ${hit.tool} ×${hit.count}  ${hit.where}`)
143
144    return { text: [t.total(state, total), ...lines].join('\n') }
145  })
146}
147
hooks/i18n.ts 45 lines
1import type { PluginOptions } from 'claude-code'
2
3export type Lang = 'en' | 'zh-TW' | 'zh-CN'
4
5const LANGS: readonly Lang[] = ['en', 'zh-TW', 'zh-CN']
6
7export const langOf = (options: PluginOptions): Lang => LANGS.find(lang => lang === options.language) ?? 'en'
8
9const en = {
10  mark: '…(masked)',
11  toast: (count: number, tool: string) => `Masked ${count} possible token${count === 1 ? '' : 's'} (${tool})`,
12  description: 'List possible tokens masked in this session; off / on to toggle',
13  off: 'off for this session.',
14  on: 'masking again.',
15  state: (isOff: boolean): string => (isOff ? 'off' : 'on'),
16  none: (state: string) => `masking ${state}, nothing masked in this session yet.`,
17  total: (state: string, total: number) => `masking ${state}, ${total} masked`,
18}
19
20const zhTW: typeof en = {
21  mark: '…(已遮)',
22  toast: (count, tool) => `遮了 ${count} 個疑似 token(${tool})`,
23  description: '列出這個 session 遮過的疑似 token;off / on 切換',
24  off: '這個 session 先不遮。',
25  on: '恢復遮蔽。',
26  state: isOff => (isOff ? '目前關閉' : '目前開啟'),
27  none: state => `${state},這個 session 還沒遮過東西。`,
28  total: (state, total) => `${state},共遮 ${total} 處`,
29}
30
31const zhCN: typeof en = {
32  mark: '…(已脱敏)',
33  toast: (count, tool) => `已脱敏 ${count} 个疑似 token(${tool})`,
34  description: '列出本次会话脱敏过的疑似 token;off / on 切换',
35  off: '本次会话暂停脱敏。',
36  on: '已恢复脱敏。',
37  state: isOff => (isOff ? '当前关闭' : '当前开启'),
38  none: state => `${state},本次会话还没有脱敏过内容。`,
39  total: (state, total) => `${state},共脱敏 ${total} 处`,
40}
41
42export type Strings = typeof en
43
44export const STRINGS: Record<Lang, Strings> = { en, 'zh-TW': zhTW, 'zh-CN': zhCN }
45
hooks/mask.ts 56 lines
1export type Masked = { text: string; count: number }
2
3// 每條規則兩個 capture:前綴照留,第二個是要遮的值
4const PREFIXED: readonly RegExp[] = [
5  /()(sk-[A-Za-z0-9_-]{20,})/g,
6  /()(gh[pousr]_[A-Za-z0-9]{30,})/g,
7  /()(github_pat_[A-Za-z0-9_]{40,})/g,
8  /()(xox[abprs]-[A-Za-z0-9-]{10,})/g,
9  /()(eyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,})/g,
10  /()(AKIA[0-9A-Z]{16})/g,
11  /()(AIza[0-9A-Za-z_-]{35})/g,
12  /()(ya29\.[0-9A-Za-z_-]{20,})/g,
13  /(Bearer\s+)([A-Za-z0-9._~+/=-]{20,})/gi,
14]
15
16// KEY=值 和 "key": "值" 容易誤傷程式碼,所以值要夠長、同時有字母和數字才遮
17const ASSIGNED: readonly RegExp[] = [
18  /((?:^|[\s;])(?:export\s+)?[A-Z0-9_]*(?:TOKEN|SECRET|PASSWORD|PASSWD|API_?KEY|PRIVATE_KEY|ACCESS_KEY)[A-Z0-9_]*=["']?)([A-Za-z0-9_\-+/=]{16,})/gm,
19  /("[A-Za-z0-9_]*(?:token|secret|password|api_?key)[A-Za-z0-9_]*"\s*:\s*")([A-Za-z0-9_\-+/=.]{16,})(?=")/gi,
20]
21
22const PRIVATE_KEY =
23  /(-----BEGIN [A-Z ]*PRIVATE KEY-----)[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g
24
25const looksRandom = (value: string) => /[A-Za-z]/.test(value) && /[0-9]/.test(value)
26
27// 把文字裡疑似 token 的部分換成前 4 碼加標記,回傳遮了幾處
28export const maskText = (input: string, mark: string): Masked => {
29  let count = 0
30  let text = input.replace(PRIVATE_KEY, (_, head: string) => {
31    count += 1
32
33    return `${head}${mark}`
34  })
35
36  const apply = (pattern: RegExp, isStrict: boolean) => {
37    text = text.replace(pattern, (whole: string, prefix: string, secret: string) => {
38      if (isStrict && !looksRandom(secret)) {
39        return whole
40      }
41      count += 1
42
43      return `${prefix}${secret.slice(0, 4)}${mark}`
44    })
45  }
46
47  for (const pattern of PREFIXED) {
48    apply(pattern, false)
49  }
50  for (const pattern of ASSIGNED) {
51    apply(pattern, true)
52  }
53
54  return { text, count }
55}
56
types/index.d.ts 8 lines
1export type MaskHit = { tool: string; where: string; count: number }
2
3declare module 'claude-code' {
4  interface PluginState {
5    'secret-mask': { hits: MaskHit[]; isOff: boolean }
6  }
7}
8