Claude Codeμ λͺ¨λ hook μ΄λ²€νΈλ₯Ό μλμΌλ‘ κΈ°λ‘νκ³ , μΉ λμ보λμμ μκ°μ μΌλ‘ λΆμν μ μλ μμ€ν μ λλ€.
- μλ μ΄λ²€νΈ λ‘κΉ β 10κ°μ§ Claude Code hook μ΄λ²€νΈλ₯Ό JSONL νμμΌλ‘ κΈ°λ‘
- μΉ λμ보λ β μΈμ νμλΌμΈ, λꡬ μ¬μ© μ°¨νΈ, μΈν°λ½νΈ/κ³ μ κ°μ§ μκ°ν
- AI μ±ν λΆμ β Claude SDK κΈ°λ° SSE μ€νΈλ¦¬λ° μ±ν μΌλ‘ λ‘κ·Έ λ°μ΄ν° λΆμ
- MCP λꡬ β 6κ°μ ꡬ쑰νλ 쿼리 λκ΅¬λ‘ AIκ° μ§μ λ°μ΄ν°λ₯Ό μ‘°ν
- CLI λΆμ λꡬ β ν°λ―Έλμμ λΉ λ₯Έ λΆμ
- μμ ν μ€μ λ³ν© β κΈ°μ‘΄ hooksμ settingsλ₯Ό νκ΄΄νμ§ μλ λΉνκ΄΄μ λ³ν©
- λ‘κ·Έ λ‘ν μ΄μ β μλ λ‘κ·Έ νμΌ κ΄λ¦¬
- μ컀맨λ μ€μΉ/μ κ±°
- jq β μ Έ μ€ν¬λ¦½νΈ JSON μ²λ¦¬
- Node.js 18+ β μλ² λ° λΉλ
- pnpm β ν¨ν€μ§ λ§€λμ
- Claude Code β hook μ΄λ²€νΈ μμ€
git clone https://github.com/devstefancho/claude-pulse.git
cd claude-pulse
pnpm install
./install.shinstall.shκ° μννλ μμ
:
- μμ‘΄μ± νμΈ (jq, Node.js 18+)
- TypeScript λΉλ (
pnpm run build) - hook μ€ν¬λ¦½νΈλ₯Ό
~/.claude/hooks/μ λ³΅μ¬ hooks-config.jsonμ~/.claude/settings.jsonμ λ³ν©- λ‘κ·Έ λλ ν 리
~/.claude/claude-pulse/μμ±
# λμ보λ μμ (κΈ°λ³Έ ν¬νΈ: 7777)
~/.claude/hooks/log-viewer.sh --open
# ν¬νΈ λ³κ²½
~/.claude/hooks/log-viewer.sh --open --port 8080
# μλ² μν νμΈ
~/.claude/hooks/log-viewer.sh --status
# μλ² μ€μ§
~/.claude/hooks/log-viewer.sh --stophttp://localhost:7777μμ λμ보λμ μ κ·Όν μ μμ΅λλ€.
| κ΅¬μ± μμ | μ€λͺ |
|---|---|
| StatBar | μ΄ μ΄λ²€νΈ μ, μΈμ (νμ±/λΉνμ±/μ’ λ£), λꡬ μ¬μ©, μΈν°λ½νΈ, κ³ μ νΈμΆ ν΅κ³ |
| SessionList | μΌμͺ½ μ¬μ΄λλ°μμ μΈμ λͺ©λ‘ μ‘°ν λ° νν°λ§ |
| EventTimeline | μκ°μ μ΄λ²€νΈ νμλΌμΈ (λ©μΈ μμ) |
| LeftTabs | μ΄μ(μΈν°λ½νΈ/κ³ μ), λꡬ μ¬μ©λ, μ€ν¬ μ¬μ©λ ν |
| ChatPanel | AI κΈ°λ° λ‘κ·Έ λΆμ μ±ν (SSE μ€νΈλ¦¬λ°) |
- Live β SessionStart μ΄ν 5λΆ μ΄λ΄ νλμ΄ μλ μΈμ
- Stale β SessionStart μ΄ν 5λΆ μ΄μ νλμ΄ μλ μΈμ
- Ended β SessionEnd μ΄λ²€νΈκ° μλ μΈμ
# μ€λ λ‘κ·Έ μμ½
~/.claude/hooks/analyze-interrupts.sh
# νΉμ μΈμ
νμλΌμΈ
~/.claude/hooks/analyze-interrupts.sh <logfile> <session_id_prefix>
# μΈν°λ½νΈλ§ νμ
~/.claude/hooks/analyze-interrupts.sh --interrupts
# κ³ μ λꡬ νΈμΆ (PreToolUseμ λ§€μΉλλ PostToolUseκ° μλ κ²½μ°)
~/.claude/hooks/analyze-interrupts.sh --orphans
# μΈμ
μμ½ ν
μ΄λΈ
~/.claude/hooks/analyze-interrupts.sh --sessionsevent-logger.shλ Claude Codeμ hook μ΄λ²€νΈλ₯Ό stdinμΌλ‘ JSONμ μμ νμ¬ μ²λ¦¬ν©λλ€.
| Event | Timing | Async | Data Fields |
|---|---|---|---|
SessionStart |
μΈμ μμ | Sync | source, model |
SessionEnd |
μΈμ μ’ λ£ | Async | reason |
UserPromptSubmit |
μ¬μ©μ ν둬ννΈ μ μ‘ | Sync | prompt (500μ truncate), prompt_length |
PreToolUse |
λꡬ μ€ν μ | Async | tool_name, tool_use_id, tool_input_summary |
PostToolUse |
λꡬ μ±κ³΅ ν | Async | tool_name, tool_use_id, success |
PostToolUseFailure |
λꡬ μ€ν¨ ν | Async | tool_name, tool_use_id, error, is_interrupt |
Notification |
μμ€ν μλ¦Ό | Async | notification_type, message |
Stop |
μμ΄μ νΈ μ μ§ | Async | stop_hook_active |
SubagentStart |
μλΈμμ΄μ νΈ μμ± | Async | agent_id, agent_type |
SubagentStop |
μλΈμμ΄μ νΈ μ’ λ£ | Async | agent_id, agent_type |
λꡬλ³λ‘ μλ―Έ μλ μμ½ μ 보λ₯Ό μΆμΆν©λλ€:
| Tool | μΆμΆ λ΄μ© |
|---|---|
| Bash | λͺ λ Ήμ΄ (μ²μ 200μ) |
| Read / Write / Edit | νμΌ κ²½λ‘ |
| Glob / Grep | ν¨ν΄ |
| WebFetch | URL |
| WebSearch | κ²μ 쿼리 |
| Skill | μ€ν¬ μ΄λ¦ |
| Task | νμ€ν¬ μ€λͺ |
λ‘κ·Έλ JSONL (ν μ€μ νλμ JSON κ°μ²΄) νμμΌλ‘ ~/.claude/claude-pulse/hook-events.jsonlμ μ μ₯λ©λλ€.
{
"ts": "2025-01-15T09:30:00.000Z",
"event": "PreToolUse",
"session_id": "abc123-def456",
"cwd": "/Users/you/project",
"permission_mode": "default",
"data": {
"tool_name": "Read",
"tool_use_id": "tool_01ABC",
"tool_input_summary": "/src/index.ts"
}
}κ³΅ν΅ νλ: ts (ISO 8601), event, session_id, cwd, permission_mode
μ΄λ²€νΈλ³ νλ: data κ°μ²΄ μμ μ΄λ²€νΈ νμ
μ λ°λΌ λ€λ₯Έ νλκ° ν¬ν¨λ©λλ€.
AI μ±ν μμ μ¬μ© κ°λ₯ν 6κ°μ MCP λꡬ:
| Tool | μ€λͺ |
|---|---|
get_dashboard_summary |
μ 체 λμ보λ ν΅κ³ μμ½ |
list_sessions |
μΈμ λͺ©λ‘ μ‘°ν (μνλ³ νν°: live/stale/ended) |
get_session_detail |
νΉμ μΈμ μ μ΄λ²€νΈ λ° λꡬ μ¬μ© μμΈ |
get_recent_activity |
μκ° λ²μ κΈ°λ° μ΅κ·Ό νλ μμ½ |
get_tool_skill_usage |
λꡬ/μ€ν¬ μ¬μ© ν΅κ³ |
search_events |
μ΄λ²€νΈ κ²μ (νμ , λꡬ, ν μ€νΈ νν°) |
Claude Code Session
β (hook μ΄λ²€νΈ νΈλ¦¬κ±°)
βΌ
event-logger.sh (stdinμΌλ‘ JSON μμ )
β (μ΄λ²€νΈλ³ λ°μ΄ν° μΆμΆ)
βΌ
~/.claude/claude-pulse/hook-events.jsonl (JSONL append)
β
ββββΆ Web Dashboard (localhost:7777)
β βββ REST API (/api/files, /api/events, /api/summary)
β βββ SSE Chat (/api/chat) + MCP Tools
β βββ React SPA (μΈμ
λͺ©λ‘, νμλΌμΈ, μ°¨νΈ, μ±ν
)
β
ββββΆ CLI Tools
βββ log-viewer.sh β μλ² μμ/μ€μ§/μν
βββ analyze-interrupts.sh β ν°λ―Έλ λΆμ
claude-pulse/
βββ hooks/ # Hook μ΄λ²€νΈ λ‘κΉ
μ
Έ μ€ν¬λ¦½νΈ
β βββ event-logger.sh # μ΄λ²€νΈ μμ λ° JSONL κΈ°λ‘
β βββ rotate-logs.sh # λ‘κ·Έ λ‘ν
μ΄μ
βββ lib/ # Node.js λΌμ΄λΈλ¬λ¦¬
β βββ settings-merge.ts # settings.json λΉνκ΄΄μ λ³ν©
β βββ settings-merge-cli.ts
βββ viewer/ # μΉ μλ² λ°±μλ
β βββ server.ts # HTTP μλ² + REST API + SSE
β βββ data.ts # JSONL νμ±, ν΅κ³, νν°λ§
β βββ mcp-tools.ts # MCP λꡬ νΈλ€λ¬
β βββ start.ts # μλ² μμ μ§μ
μ
βββ web/ # React νλ‘ νΈμλ (Vite + React 19)
β βββ src/
β βββ App.tsx # λ©μΈ μ± (λ μ΄μμ, μν κ΄λ¦¬)
β βββ components/ # UI μ»΄ν¬λνΈ (11κ°)
β βββ hooks/ # 컀μ€ν
ν
(useLogData, useAutoRefresh, useChat)
β βββ utils/ # μ νΈλ¦¬ν° (μμ, ν¬λ§·ν
)
β βββ types.ts # TypeScript νμ
μ μ
βββ test/ # ν
μ€νΈ μ€μνΈ (9κ° νμΌ)
βββ tools/ # CLI μ νΈλ¦¬ν°
β βββ log-viewer.sh # λμ보λ μλ² κ΄λ¦¬
β βββ analyze-interrupts.sh
βββ install.sh # μ€μΉ μ€ν¬λ¦½νΈ
βββ uninstall.sh # μ κ±° μ€ν¬λ¦½νΈ
βββ hooks-config.json # Hook μ΄λ²€νΈ λ±λ‘ μ€μ
βββ justfile # κ°λ° λͺ
λ Ήμ΄ λ¨μΆν€
βββ package.json
| Category | Technology |
|---|---|
| Language | TypeScript (strict), Bash |
| Frontend | React 19, Vite 6 |
| Backend | Node.js HTTP (Express μμ) |
| AI | @anthropic-ai/claude-agent-sdk |
| Validation | Zod 4 |
| Markdown | react-markdown |
| Package Manager | pnpm |
| Test | Node.js built-in test runner + tsx |
| Build | tsc (μλ²) + Vite (νλ‘ νΈμλ) |
| Shell JSON | jq |
# νλ‘ νΈμλ dev μλ² (ν¬νΈ 5173, /apiλ₯Ό 7777λ‘ νλ‘μ)
pnpm run dev
# λ°±μλ μλ² (ν¬νΈ 7777)
pnpm run dev:serverpnpm run build # tsc μ»΄νμΌ + Vite λΉλ β dist/
pnpm run build:check # νμ
체ν¬λ§ (tsc --noEmit)
pnpm test # μ 체 ν
μ€νΈ μ€ν
pnpm run test:coverage # 컀λ²λ¦¬μ§ 리ν¬νΈjustκ° μ€μΉλμ΄ μλ€λ©΄ λ¨μΆ λͺ λ Ήμ΄λ₯Ό μ¬μ©ν μ μμ΅λλ€:
just build # λΉλ
just build-check # νμ
체ν¬
just test # ν
μ€νΈ
just test-coverage # 컀λ²λ¦¬μ§ ν
μ€νΈ
just dev # λΉλ ν μλ² μμ
just viewer # λμ보λ μ΄κΈ°
just viewer-stop # λμ보λ μλ² μ€μ§
just viewer-status # μλ² μν νμΈ
just analyze # CLI λΆμ
just clean # dist/ μμ
just install # hook μ€μΉ
just uninstall # hook μ κ±°μ΄μ λ²μ (Claude Hook Logger)μμ μ λ°μ΄νΈνλ κ²½μ°:
# 1. κΈ°μ‘΄ λ‘κ·Έ λ°μ΄ν° λ§μ΄κ·Έλ μ΄μ
mv ~/.claude/hook-logger ~/.claude/claude-pulse
# 2. κΈ°μ‘΄ hook μ€μ μ κ±° ν μ¬μ€μΉ
./uninstall.sh
./install.shλ³κ²½ μ¬ν:
| νλͺ© | μ΄μ | νμ¬ |
|---|---|---|
| λ‘κ·Έ λλ ν 리 | ~/.claude/hook-logger/ |
~/.claude/claude-pulse/ |
| MCP μλ²λͺ | hook-logger |
claude-pulse |
| MCP λꡬ μ λμ¬ | mcp__hook-logger__* |
mcp__claude-pulse__* |
Note: λ‘κ·Έ λλ ν 리λ₯Ό λ§μ΄κ·Έλ μ΄μ νμ§ μμΌλ©΄ κΈ°μ‘΄ λ‘κ·Έ λ°μ΄ν°λ₯Ό λμ보λμμ λ³Ό μ μμ΅λλ€.
cd claude-pulse
./uninstall.shNote: λ‘κ·Έ νμΌμ
~/.claude/claude-pulse/μ 보쑴λ©λλ€. νμ μλ€λ©΄ μλμΌλ‘ μμ νμΈμ.
MIT
