Skip to content

Latest commit

ย 

History

7 Commits

Folders and files

NameName
Last commit message
Last commit date
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐Ÿฆ pawse

English ยท ํ•œ๊ตญ์–ด

An interactive hook widget for Claude Code: when Claude pauses, the lion Leo peeks out so you can reply straight from a desktop popup.

When Claude finishes a task (Stop) or waits for your input (Notification), pawse shows a small desktop widget. Type your next instruction right in the widget and Claude keeps going. Built with PowerShell + WPF โ€” no install required (Windows only).

Optionally, pawse can also confirm risky commands before they run โ€” see Optional: PreToolUse.

Screenshots

Stop โ€” type your next instruction Notification โ€” Claude needs you
pawse Stop widget pawse Notification toast

What each event does

Event Trigger Widget Leo
Stop Claude finishes a response Preview of the last message + an input box. Type to make Claude continue ({"decision":"block"}); leave it empty to just stop. ๐Ÿ˜Š happy
Notification Permission / idle input wait Toast notification (auto-dismiss). Informational only. ๐Ÿ˜ฎ surprised !

A third event, PreToolUse (risky-command confirm), is optional and off by default โ€” see Optional: PreToolUse.

Design: aligned with Windows 11 Fluent (8px card / 4px controls, soft shadow + 1px border, Segoe UI Variable type ramp 20/14/12, WCAG AA-passing colors), automatic light/dark following the system, and a slide-in entrance (respecting the system "Show animations" setting).

How it works

The widget script is wired into Claude Code hooks. The key idea is that it's bidirectional:

Claude finishes โ”€โ–ถ Stop hook โ”€โ–ถ pawse widget appears
                                     โ”‚  you type the next instruction
                                     โ–ผ
       {"decision":"block","reason":"<your text>"}  โ”€โ–ถ Claude continues

Install

Windows only. pawse uses powershell.exe + WPF. Installing on macOS/Linux is harmless but the widget won't appear.

Recommended: install as a plugin

pawse ships as a Claude Code plugin โ€” nothing to hand-edit. In Claude Code:

/plugin marketplace add sinwoo0225/Pawse
/plugin install pawse@leo

Then run /reload-plugins (or restart Claude Code). The Stop + Notification hooks are wired automatically via ${CLAUDE_PLUGIN_ROOT}.

Manual install (fallback)

Prefer to wire it yourself? Clone the repo and add this to hooks in ~/.claude/settings.json, replacing <install-path> with the absolute path to the repo. Note the plugin\ subfolder โ€” the script lives under plugin/:

"hooks": {
  "Stop": [{ "hooks": [{ "type": "command", "timeout": 600,
    "command": "powershell.exe -NoProfile -ExecutionPolicy Bypass -File \"<install-path>\\plugin\\claude-widget.ps1\" -Event Stop" }] }],
  "Notification": [{ "hooks": [{ "type": "command", "timeout": 30,
    "command": "powershell.exe -NoProfile -ExecutionPolicy Bypass -File \"<install-path>\\plugin\\claude-widget.ps1\" -Event Notification" }] }]
}

Then restart Claude Code to load the hooks.

WPF needs an STA thread, so it's invoked with powershell.exe (Windows PowerShell 5.1), not pwsh.

Upgrading from a pre-plugin manual install? The script moved from the repo root into plugin/. Switch to the plugin install above, or update your settings.json hook path to add \plugin.

Optional: PreToolUse (risky-command confirm)

Not part of the default install above โ€” pawse can also pop a confirm widget right before a command runs. To turn it on, add a PreToolUse hook alongside the others:

"PreToolUse": [{ "matcher": "Bash", "hooks": [{ "type": "command", "timeout": 600,
  "command": "powershell.exe -NoProfile -ExecutionPolicy Bypass -File \"<install-path>\\plugin\\claude-widget.ps1\" -Event PreToolUse" }] }]

Then set a DangerPattern regex in config.psd1 to choose which commands trigger it (the shipped default '.' matches every command), and restart Claude Code.

When does the PreToolUse widget appear?

Before a tool runs, the hook decides whether to show the confirm widget. It only shows when all three gates pass โ€” otherwise it exits silently and Claude's normal permission flow continues:

        tool about to run
                โ”‚
                โ–ผ
   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   yes
   โ”‚ 1. permission_mode โˆˆ {auto, bypassPermissions, dontAsk}? โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ–ถ exit 0  (no widget)
   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                โ”‚ no
                โ–ผ
   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   yes
   โ”‚ 2. command covered by a permissions.allow rule?          โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ–ถ exit 0  (no widget)
   โ”‚    (Bash(...) form โ€” the hook matcher is "Bash")         โ”‚
   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                โ”‚ no
                โ–ผ
   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   no
   โ”‚ 3. command matches DangerPattern?                        โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ–ถ exit 0  (normal flow)
   โ”‚    (default config '.' โ‡’ every command matches)          โ”‚
   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                โ”‚ yes
                โ–ผ
        โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
        โ•‘   PreToolUse widget appears   โ•‘
        โ•‘   ํ—ˆ์šฉ  /  ์ง์ ‘ ํ™•์ธ  /  ์ฐจ๋‹จ   โ•‘   (Allow / Ask / Block)
        โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
                โ”‚
                โ–ผ
   permissionDecision: allow / ask / deny  โ”€โ–ถ Claude
  • Gate 1 (mode): auto/bypassPermissions/dontAsk proceed without asking, so the widget stays out of the way. It still appears in default/plan/acceptEdits.
  • Gate 2 (allowlist): mirrors permissions.allow from ~/.claude and the project's .claude settings, so commands you already trust don't pop the widget. Approving "don't ask again" adds the rule automatically.
  • Gate 3 (DangerPattern): shipped as '.' (matches everything) for a terminal-mirror feel; set a real regex in config.psd1 to limit the widget to risky commands only.

Because the hook can't see Claude Code's resolved permission decision (only tool_name / tool_input / permission_mode), this is a best-effort mirror โ€” session-only "allow once" approvals and the built-in safe-command classifier aren't visible to it.

Configuration (config.psd1)

Key Description
Sound Play a sound when the widget appears
NotificationAutoCloseSeconds Toast auto-dismiss time (seconds)
PreviewMaxChars Max chars for the Stop preview (0 = unlimited)
Mode 'auto' (follow Windows light/dark) ยท 'light' ยท 'dark'
Accent / AccentDark Light/dark accent (primary button & focus). Defaults pass WCAG AA (โ‰ฅ4.5:1)
Animate Slide-in entrance. If omitted, follows the Windows "Show animations" setting ($true/$false to force)
DangerPattern (PreToolUse only) Regex for which commands trigger the confirm widget; '.' matches every Bash command. Has no effect unless the optional PreToolUse hook is enabled

config.psd1 is read every time a widget appears, so changes apply without restarting Claude Code.

Installed as a plugin? The bundled config.psd1 lives in the plugin cache and is overwritten on update. On first run pawse copies it to the plugin's data folder (${CLAUDE_PLUGIN_DATA}\config.psd1); edit that copy โ€” your settings then survive plugin updates. (Manual installs just edit plugin/config.psd1 directly.)

Changing the character (Leo)

The plugin/assets/ folder contains Leo's three expressions (stop.png, notification.png, pretooluse.png). Replace them with your own transparent PNGs (square recommended) to change the character. Delete them to fall back to the built-in vector character. When installed as a plugin, drop your PNGs in ${CLAUDE_PLUGIN_DATA}\assets\ instead so they survive updates.

Try it directly

# Stop widget (type, continue โ†’ check JSON output)
'{"hook_event_name":"Stop","stop_hook_active":false,"transcript_path":""}' |
  powershell.exe -NoProfile -ExecutionPolicy Bypass -File .\plugin\claude-widget.ps1 -Event Stop

# Notification toast
'{"notification_type":"idle_prompt","message":"Waiting for input"}' |
  powershell.exe -NoProfile -ExecutionPolicy Bypass -File .\plugin\claude-widget.ps1 -Event Notification

# PreToolUse widget (optional event โ€” risky command)
'{"tool_name":"Bash","tool_input":{"command":"rm -rf build"}}' |
  powershell.exe -NoProfile -ExecutionPolicy Bypass -File .\plugin\claude-widget.ps1 -Event PreToolUse

Logic only (no GUI): powershell.exe -NoProfile -ExecutionPolicy Bypass -File .\plugin\test-widget.ps1

Details & limitations

  • Stop: when the hook writes {"decision":"block","reason":"<text>"} to stdout, Claude resumes with that text as its next instruction. If stop_hook_active is true (already in a widget-triggered resume), the widget is skipped to avoid an infinite loop.
  • Notification is informational only and can't answer permission prompts. (The optional PreToolUse widget can confirm commands โ€” see Optional: PreToolUse.)
  • While the widget waits for input, Claude waits too. If it exceeds timeout (seconds) the hook is killed and the widget closes, so 600 is recommended for Stop (and PreToolUse if enabled).
  • All of stdin, stdout, transcript reads, and the script file are handled as UTF-8 so non-ASCII (e.g. Korean) doesn't break.

Layout

File Role
.claude-plugin/marketplace.json Self-hosted marketplace leo (lists the pawse plugin)
plugin/.claude-plugin/plugin.json Plugin manifest
plugin/hooks/hooks.json Stop + Notification hooks (wired via ${CLAUDE_PLUGIN_ROOT})
plugin/claude-widget.ps1 Single entry point; dispatches on -Event Stop|Notification|PreToolUse
plugin/config.psd1 User settings (bundled default โ€” see the data-folder note in Configuration)
plugin/assets/ Leo expression PNGs (customizable)
plugin/test-widget.ps1 Dependency-free logic tests
settings-hooks.snippet.json Manual-install hooks snippet (fallback)

License

MIT โ€” see LICENSE.


ํ•œ๊ตญ์–ด

Claude Code๊ฐ€ ๋ฉˆ์ถœ ๋•Œ(pause) ์‚ฌ์ž Leo๊ฐ€ ๊ณ ๊ฐœ๋ฅผ ์™ ๋‚ด๋ฏธ๋Š”, Claude Code์šฉ ์–‘๋ฐฉํ–ฅ hook ์œ„์ ฏ.

Claude Code๊ฐ€ ์ž‘์—…์„ ๋งˆ์น˜๊ฑฐ๋‚˜(Stop) ์ž…๋ ฅ์„ ๊ธฐ๋‹ค๋ฆด ๋•Œ(Notification) ๋ฐ์Šคํฌํ†ฑ์— ์ž‘์€ ์œ„์ ฏ์„ ๋„์šฐ๊ณ , ๊ทธ ์œ„์ ฏ์—์„œ ๋ฐ”๋กœ ๋‹ค์Œ ์ง€์‹œ๋ฅผ ์ž…๋ ฅํ•˜๋ฉด Claude๊ฐ€ ์ด์–ด์„œ ์ž‘์—…ํ•ฉ๋‹ˆ๋‹ค. PowerShell + WPF๋กœ ๋งŒ๋“ค์–ด ๋ณ„๋„ ์„ค์น˜๊ฐ€ ํ•„์š” ์—†์Šต๋‹ˆ๋‹ค(Windows ์ „์šฉ).

์œ„ํ—˜ํ•œ ๋ช…๋ น ์‹คํ–‰ ์ „ ํ™•์ธ์ด ํ•„์š”ํ•˜๋ฉด ์„ ํƒ ๊ธฐ๋Šฅ์œผ๋กœ ์ผค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค โ€” ์•„๋ž˜ ์„ ํƒ: PreToolUse ์ฐธ๊ณ .

์ด๋ฒคํŠธ๋ณ„ ๋™์ž‘

์ด๋ฒคํŠธ ํŠธ๋ฆฌ๊ฑฐ ์œ„์ ฏ Leo
Stop Claude๊ฐ€ ์‘๋‹ต์„ ๋งˆ์นจ ๋งˆ์ง€๋ง‰ ๋ฉ”์‹œ์ง€ ๋ฏธ๋ฆฌ๋ณด๊ธฐ + ์ž…๋ ฅ์ฐฝ. ์ž…๋ ฅํ•˜๋ฉด Claude๊ฐ€ ์ด์–ด์„œ ์ž‘์—…({"decision":"block"}). ๋น„์›Œ๋‘๋ฉด ๊ทธ๋ƒฅ ์ข…๋ฃŒ. ๐Ÿ˜Š ์›ƒ์Œ
Notification ๊ถŒํ•œ/์ž…๋ ฅ ๋Œ€๊ธฐ(idle) ํ† ์ŠคํŠธ ์•Œ๋ฆผ(์ž๋™ ๋‹ซํž˜). ์ •๋ณด ์ „์šฉ. ๐Ÿ˜ฎ ๋†€๋žŒ !

์„ธ ๋ฒˆ์งธ ์ด๋ฒคํŠธ PreToolUse(์œ„ํ—˜ ๋ช…๋ น ํ™•์ธ)๋Š” ์„ ํƒ ๊ธฐ๋Šฅ์ด๋ฉฐ ๊ธฐ๋ณธ ๋น„ํ™œ์„ฑ โ€” ์•„๋ž˜ ์„ ํƒ: PreToolUse ์ฐธ๊ณ .

๋””์ž์ธ: Windows 11 Fluent ์ •ํ•ฉ(8px ์นด๋“œ / 4px ์ปจํŠธ๋กค, ๋ถ€๋“œ๋Ÿฌ์šด ๊ทธ๋ฆผ์ž + 1px ํ…Œ๋‘๋ฆฌ, Segoe UI Variable ํƒ€์ž…๋žจํ”„ 20/14/12, WCAG AA ํ†ต๊ณผ ์ƒ‰), ์‹œ์Šคํ…œ ๋ผ์ดํŠธ/๋‹คํฌ ์ž๋™ ์ „ํ™˜, ๋“ฑ์žฅ ์Šฌ๋ผ์ด๋“œ์ธ(์‹œ์Šคํ…œ "์• ๋‹ˆ๋ฉ”์ด์…˜ ํ‘œ์‹œ" ์„ค์ • ์กด์ค‘).

๋™์ž‘ ๋ฐฉ์‹

Claude Code์˜ hooks์— ์œ„์ ฏ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ํ•ต์‹ฌ์€ ์–‘๋ฐฉํ–ฅ์ด๋ผ๋Š” ์  โ€” Stop hook์ด {"decision":"block","reason":"<์ž…๋ ฅ>"}์„ ๋ฐ˜ํ™˜ํ•˜๋ฉด ๊ทธ ์ž…๋ ฅ์ด Claude์˜ ๋‹ค์Œ ์ง€์‹œ๊ฐ€ ๋˜์–ด ์ž‘์—…์ด ์ด์–ด์ง‘๋‹ˆ๋‹ค.

์„ค์น˜

Windows ์ „์šฉ. pawse๋Š” powershell.exe + WPF๋ฅผ ์“ฐ๋ฏ€๋กœ Windows์—์„œ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค. mac/Linux์— ์„ค์น˜ํ•ด๋„ ๋ฌดํ•ดํ•˜์ง€๋งŒ ์œ„์ ฏ์€ ๋œจ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ถŒ์žฅ: ํ”Œ๋Ÿฌ๊ทธ์ธ์œผ๋กœ ์„ค์น˜

pawse๋Š” Claude Code ํ”Œ๋Ÿฌ๊ทธ์ธ์œผ๋กœ ๋ฐฐํฌ๋˜์–ด ๊ฒฝ๋กœ๋ฅผ ์†๋ณผ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. Claude Code์—์„œ:

/plugin marketplace add sinwoo0225/Pawse
/plugin install pawse@leo

์ด์–ด์„œ /reload-plugins(๋˜๋Š” Claude Code ์žฌ์‹œ์ž‘). Stop + Notification hook์ด ${CLAUDE_PLUGIN_ROOT}๋กœ ์ž๋™ ์—ฐ๊ฒฐ๋ฉ๋‹ˆ๋‹ค.

์ˆ˜๋™ ์„ค์น˜ (fallback)

์ง์ ‘ ์—ฐ๊ฒฐํ•˜๋ ค๋ฉด ์ €์žฅ์†Œ๋ฅผ ํด๋ก ํ•œ ๋’ค ~/.claude/settings.json์˜ hooks์— ์œ„ ์˜์–ด ์„น์…˜์˜ JSON์„ ์ถ”๊ฐ€ํ•˜์„ธ์š”. <install-path>๋ฅผ ์ €์žฅ์†Œ ์ ˆ๋Œ€๊ฒฝ๋กœ๋กœ ๋ฐ”๊พธ๊ณ , ์Šคํฌ๋ฆฝํŠธ๊ฐ€ plugin\ ํ•˜์œ„์— ์žˆ์Œ์— ์ฃผ์˜(...\plugin\claude-widget.ps1). ๊ทธ ํ›„ Claude Code๋ฅผ ์žฌ์‹œ์ž‘ํ•˜์„ธ์š”.

WPF๋Š” STA ์Šค๋ ˆ๋“œ๊ฐ€ ํ•„์š”ํ•˜๋ฏ€๋กœ pwsh๊ฐ€ ์•„๋‹ˆ๋ผ powershell.exe(Windows PowerShell 5.1)๋กœ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

ํ”Œ๋Ÿฌ๊ทธ์ธ ์ด์ „์˜ ์ˆ˜๋™ ์„ค์น˜์—์„œ ์˜ฌ๋ผ์˜ค๋‚˜์š”? ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์ €์žฅ์†Œ ๋ฃจํŠธ์—์„œ plugin/์œผ๋กœ ์ด๋™ํ–ˆ์Šต๋‹ˆ๋‹ค. ์œ„ ํ”Œ๋Ÿฌ๊ทธ์ธ ์„ค์น˜๋กœ ์ „ํ™˜ํ•˜๊ฑฐ๋‚˜ settings.json hook ๊ฒฝ๋กœ์— \plugin์„ ์ถ”๊ฐ€ํ•˜์„ธ์š”.

์„ ํƒ: PreToolUse (์œ„ํ—˜ ๋ช…๋ น ํ™•์ธ)

๊ธฐ๋ณธ ์„ค์น˜์—๋Š” ํฌํ•จ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค โ€” pawse๋Š” ๋ช…๋ น ์‹คํ–‰ ์ง์ „์— ํ™•์ธ ์œ„์ ฏ์„ ๋„์šธ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ผœ๋ ค๋ฉด ๋‹ค๋ฅธ hook ์˜†์— PreToolUse hook์„ ์ถ”๊ฐ€ํ•˜์„ธ์š”:

"PreToolUse": [{ "matcher": "Bash", "hooks": [{ "type": "command", "timeout": 600,
  "command": "powershell.exe -NoProfile -ExecutionPolicy Bypass -File \"<install-path>\\plugin\\claude-widget.ps1\" -Event PreToolUse" }] }]

๊ทธ๋ฆฌ๊ณ  config.psd1์˜ DangerPattern ์ •๊ทœ์‹์œผ๋กœ ์–ด๋–ค ๋ช…๋ น์— ๋„์šธ์ง€ ์ •ํ•œ ๋’ค(์ถœ๊ณ  ๊ธฐ๋ณธ๊ฐ’ '.'์€ ๋ชจ๋“  ๋ช…๋ น์— ๋งค์น˜) Claude Code๋ฅผ ์žฌ์‹œ์ž‘ํ•˜์„ธ์š”.

PreToolUse ์œ„์ ฏ์€ ์–ธ์ œ ๋œจ๋‚˜

๋„๊ตฌ ์‹คํ–‰ ์ง์ „, hook์ด ์„ธ ๊ด€๋ฌธ์„ ๋ชจ๋‘ ํ†ต๊ณผํ•  ๋•Œ๋งŒ ํ™•์ธ ์œ„์ ฏ์„ ๋„์›๋‹ˆ๋‹ค. ํ•˜๋‚˜๋ผ๋„ ๊ฑธ๋ฆฌ๋ฉด ์กฐ์šฉํžˆ ์ข…๋ฃŒ(exit 0)ํ•˜๊ณ  Claude์˜ ํ‰์†Œ ๊ถŒํ•œ ํ๋ฆ„์œผ๋กœ ๋„˜์–ด๊ฐ‘๋‹ˆ๋‹ค:

        ๋„๊ตฌ ์‹คํ–‰ ์ง์ „
                โ”‚
                โ–ผ
   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   ์˜ˆ
   โ”‚ 1. permission_mode ๊ฐ€ auto/bypassPermissions/dontAsk ?    โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ–ถ exit 0  (์œ„์ ฏ ์—†์Œ)
   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                โ”‚ ์•„๋‹ˆ์˜ค
                โ–ผ
   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   ์˜ˆ
   โ”‚ 2. permissions.allow ๊ทœ์น™์— ํ•ด๋‹นํ•˜๋Š” ๋ช…๋ น์ธ๊ฐ€?            โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ–ถ exit 0  (์œ„์ ฏ ์—†์Œ)
   โ”‚    (Bash(...) ํ˜•์‹ โ€” hook matcher ๊ฐ€ "Bash")              โ”‚
   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                โ”‚ ์•„๋‹ˆ์˜ค
                โ–ผ
   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   ์•„๋‹ˆ์˜ค
   โ”‚ 3. DangerPattern ์— ๋งค์น˜๋˜๋Š”๊ฐ€?                          โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ–ถ exit 0  (ํ‰์†Œ ๊ถŒํ•œ ํ๋ฆ„)
   โ”‚    (๊ธฐ๋ณธ ์„ค์ • '.' โ‡’ ๋ชจ๋“  ๋ช…๋ น์ด ๋งค์น˜)                    โ”‚
   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                โ”‚ ์˜ˆ
                โ–ผ
        โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
        โ•‘   PreToolUse ์œ„์ ฏ ํ‘œ์‹œ         โ•‘
        โ•‘   ํ—ˆ์šฉ  /  ์ง์ ‘ ํ™•์ธ  /  ์ฐจ๋‹จ   โ•‘
        โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
                โ”‚
                โ–ผ
   permissionDecision: allow / ask / deny  โ”€โ–ถ Claude
  • ๊ด€๋ฌธ 1 (๋ชจ๋“œ): auto/bypassPermissions/dontAsk๋Š” ๋ฌป์ง€ ์•Š๊ณ  ์ง„ํ–‰ํ•˜๋Š” ๋ชจ๋“œ๋ผ ์œ„์ ฏ์ด ๋ผ์–ด๋“ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค. default/plan/acceptEdits์—์„  ๋œน๋‹ˆ๋‹ค.
  • ๊ด€๋ฌธ 2 (allowlist): ~/.claude์™€ ํ”„๋กœ์ ํŠธ .claude ์„ค์ •์˜ permissions.allow๋ฅผ ๋ฏธ๋Ÿฌ๋งํ•ด, ์ด๋ฏธ ์‹ ๋ขฐํ•˜๋Š” ๋ช…๋ น์—” ์œ„์ ฏ์ด ์•ˆ ๋œน๋‹ˆ๋‹ค. "ํ—ˆ์šฉํ•˜๊ณ  ๋‹ค์‹œ ๋ฌป์ง€ ์•Š๊ธฐ"๋ฅผ ๊ณ ๋ฅด๋ฉด ๊ทœ์น™์ด ์ž๋™ ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค.
  • ๊ด€๋ฌธ 3 (DangerPattern): ํ„ฐ๋ฏธ๋„ ๋ฏธ๋Ÿฌ ๋А๋‚Œ์„ ์œ„ํ•ด ๊ธฐ๋ณธ๊ฐ’ '.'(๋ชจ๋‘ ๋งค์น˜)๋กœ ์ถœ๊ณ ๋ฉ๋‹ˆ๋‹ค. config.psd1์—์„œ ์ •๊ทœ์‹์„ ์ง€์ •ํ•˜๋ฉด ์œ„ํ—˜ ๋ช…๋ น์—๋งŒ ์œ„์ ฏ์„ ๋„์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

hook์€ Claude Code์˜ ์ตœ์ข… ๊ถŒํ•œ ๊ฒฐ์ •์€ ๋ชป ๋ณด๊ณ (tool_name/tool_input/permission_mode๋งŒ ๋ฐ›์Œ), ๊ทธ๋ž˜์„œ ์ด๋Š” ์ตœ์„ ์˜ ๊ทผ์‚ฌ์ž…๋‹ˆ๋‹ค โ€” "์ด๋ฒˆ๋งŒ ํ—ˆ์šฉ" ๊ฐ™์€ ์„ธ์…˜ ๋‹จ์œ„ ์Šน์ธ๊ณผ ๋‚ด์žฅ ์•ˆ์ „-๋ช…๋ น ๋ถ„๋ฅ˜๊ธฐ๋Š” hook์— ๋ณด์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์„ค์ • (config.psd1)

ํ‚ค ์„ค๋ช…
Sound ์œ„์ ฏ ๋“ฑ์žฅ ์‹œ ์•Œ๋ฆผ์Œ
NotificationAutoCloseSeconds ํ† ์ŠคํŠธ ์ž๋™ ๋‹ซํž˜ ์‹œ๊ฐ„(์ดˆ)
PreviewMaxChars Stop ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์ตœ๋Œ€ ๊ธ€์ž ์ˆ˜(0์ด๋ฉด ๋ฌด์ œํ•œ)
Mode 'auto'(Windows ๋ผ์ดํŠธ/๋‹คํฌ ๋”ฐ๋ฆ„) ยท 'light' ยท 'dark'
Accent / AccentDark ๋ผ์ดํŠธ/๋‹คํฌ ๊ฐ•์กฐ์ƒ‰(Primary ๋ฒ„ํŠผยทํฌ์ปค์Šค). ๊ธฐ๋ณธ๊ฐ’์€ WCAG AA(โ‰ฅ4.5:1) ํ†ต๊ณผ
Animate ๋“ฑ์žฅ ์Šฌ๋ผ์ด๋“œ์ธ. ์ƒ๋žต ์‹œ Windows "์• ๋‹ˆ๋ฉ”์ด์…˜ ํ‘œ์‹œ" ์„ค์ •์„ ๋”ฐ๋ฆ„($true/$false๋กœ ๊ฐ•์ œ)
DangerPattern (PreToolUse ์ „์šฉ) ํ™•์ธ ์œ„์ ฏ์„ ๋„์šธ ๋ช…๋ น ์ •๊ทœ์‹. ๋ชจ๋“  Bash์— ๋„์šฐ๋ ค๋ฉด '.'. ์„ ํƒ ๊ธฐ๋Šฅ์ธ PreToolUse hook์„ ์ผœ์ง€ ์•Š์œผ๋ฉด ํšจ๊ณผ ์—†์Œ

config.psd1์€ ์œ„์ ฏ์ด ๋œฐ ๋•Œ๋งˆ๋‹ค ์ฝ์œผ๋ฏ€๋กœ Claude Code ์žฌ์‹œ์ž‘ ์—†์ด ๋ฐ˜์˜๋ฉ๋‹ˆ๋‹ค.

ํ”Œ๋Ÿฌ๊ทธ์ธ์œผ๋กœ ์„ค์น˜ํ•œ ๊ฒฝ์šฐ? ๋ฒˆ๋“ค config.psd1์€ ํ”Œ๋Ÿฌ๊ทธ์ธ ์บ์‹œ์— ์žˆ์–ด ์—…๋ฐ์ดํŠธ ์‹œ ๋ฎ์–ด์“ฐ์ž…๋‹ˆ๋‹ค. pawse๋Š” ์ฒซ ์‹คํ–‰ ๋•Œ ์ด๋ฅผ ํ”Œ๋Ÿฌ๊ทธ์ธ ๋ฐ์ดํ„ฐ ํด๋”(${CLAUDE_PLUGIN_DATA}\config.psd1)๋กœ ๋ณต์‚ฌํ•˜๋ฏ€๋กœ, ๊ทธ ์‚ฌ๋ณธ์„ ํŽธ์ง‘ํ•˜๋ฉด ์„ค์ •์ด ํ”Œ๋Ÿฌ๊ทธ์ธ ์—…๋ฐ์ดํŠธ์—๋„ ๋ณด์กด๋ฉ๋‹ˆ๋‹ค. (์ˆ˜๋™ ์„ค์น˜๋Š” plugin/config.psd1์„ ์ง์ ‘ ํŽธ์ง‘ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.)

์บ๋ฆญํ„ฐ(Leo) ๋ฐ”๊พธ๊ธฐ

plugin/assets/ ํด๋”์— ์‚ฌ์ž Leo์˜ ํ‘œ์ • 3์ข…(stop.png, notification.png, pretooluse.png)์ด ๋“ค์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์›ํ•˜๋Š” ํˆฌ๋ช… PNG(์ •์‚ฌ๊ฐํ˜• ๊ถŒ์žฅ)๋กœ ๊ต์ฒดํ•˜๋ฉด ์บ๋ฆญํ„ฐ๊ฐ€ ๋ฐ”๋€๋‹ˆ๋‹ค. ํŒŒ์ผ์„ ์ง€์šฐ๋ฉด ์Šคํฌ๋ฆฝํŠธ์— ๋‚ด์žฅ๋œ ๋ฒกํ„ฐ ์บ๋ฆญํ„ฐ๊ฐ€ ๋Œ€์‹  ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ํ”Œ๋Ÿฌ๊ทธ์ธ์œผ๋กœ ์„ค์น˜ํ–ˆ๋‹ค๋ฉด ์—…๋ฐ์ดํŠธ์—๋„ ๋ณด์กด๋˜๋„๋ก ${CLAUDE_PLUGIN_DATA}\assets\์— PNG๋ฅผ ๋„ฃ์œผ์„ธ์š”.

๋™์ž‘ ์›๋ฆฌ / ํ•œ๊ณ„

  • Stop: hook์ด {"decision":"block","reason":"<์ž…๋ ฅ>"}์„ stdout์œผ๋กœ ๋ฐ˜ํ™˜ํ•˜๋ฉด Claude๊ฐ€ ๊ทธ ์ง€์‹œ๋กœ ์ž‘์—…์„ ์žฌ๊ฐœํ•ฉ๋‹ˆ๋‹ค. stop_hook_active๊ฐ€ true๋ฉด(์ด๋ฏธ ์œ„์ ฏ์ด ์œ ๋ฐœํ•œ ์žฌ๊ฐœ ์ค‘) ์œ„์ ฏ์„ ๋„์šฐ์ง€ ์•Š์•„ ๋ฌดํ•œ ๋ฃจํ”„๋ฅผ ๋ง‰์Šต๋‹ˆ๋‹ค.
  • Notification์€ ์ •๋ณด ์ „์šฉ์ด๋ผ ๊ถŒํ•œ์„ ์ง์ ‘ ์‘๋‹ตํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. (์„ ํƒ ๊ธฐ๋Šฅ์ธ PreToolUse ์œ„์ ฏ์œผ๋กœ ๋ช…๋ น์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค โ€” ์œ„ ์„ ํƒ: PreToolUse ์ฐธ๊ณ .)
  • ์œ„์ ฏ์ด ์ž…๋ ฅ ๋Œ€๊ธฐ๋กœ ๋–  ์žˆ๋Š” ๋™์•ˆ Claude๋Š” ๊ธฐ๋‹ค๋ฆฝ๋‹ˆ๋‹ค. timeout(์ดˆ)์„ ๋„˜๊ธฐ๋ฉด hook์ด ์ข…๋ฃŒ๋˜๊ณ  ์œ„์ ฏ์ด ๋‹ซํžˆ๋ฏ€๋กœ Stop์€(์ผฐ๋‹ค๋ฉด PreToolUse๋„) 600 ๊ถŒ์žฅ.
  • ํ•œ๊ธ€ ๋“ฑ ๋น„ASCII๊ฐ€ ๊นจ์ง€์ง€ ์•Š๋„๋ก stdinยทstdoutยทํŠธ๋žœ์Šคํฌ๋ฆฝํŠธ ์ฝ๊ธฐยท์Šคํฌ๋ฆฝํŠธ ํŒŒ์ผ์„ ๋ชจ๋‘ UTF-8๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

made for Claude Code ยท PowerShell + WPF ยท Windows

About

An interactive WPF widget for Claude Code hooks - reply to Claude straight from a desktop popup (mascot: Leo the lion)

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages