長いターンが終わったときと、許可を待っているときに音とトーストで知らせる

English | 日本語
A marketplace of mods for Claude Code. A mod is a plugin that adds features to Claude Code through function hooks.
| Mod | What it does |
|---|---|
| branch-watch | Stops commits on a branch another session switched to, and lists each session's worktree and branch |
| push-gate | Holds git push and similar commands until a person approves |
| auto-worktree | Creates a worktree on the first prompt and starts the work there |
| session-diff | Shows the files this session edited and their diffs |
| pr-pane | Shows open pull requests and their CI results |
| side-question | /btw asks a side question without stopping the work |
| done-chime | Plays a sound when a long turn ends and when Claude waits for permission |
| ja-check | Tells you when a reply starts in English |
| usage-meter | Shows each turn's token counts and prompt cache rate |
claude plugin marketplace add yut0takagi/mods
claude plugin install branch-watch@yut0takagi-mods # one line per mod you want
Developed with Claude Code 2.1.289. Mods are an early access feature, so a Claude Code update may break them. The VS Code and Cursor extension draws no mod UI, so some mods are used differently there.
To change a mod, read CONTRIBUTING. Changes are listed in the CHANGELOG. Report security problems as described in SECURITY.
hooks/register.ts 35 lines1import type { Register } from 'claude-code'
2
3import { durationText } from './time'
4
5export const register: Register = (on, options) => {
6 const minMs = (typeof options.minSeconds === 'number' ? options.minSeconds : 60) * 1_000
7 const hasSound = options.sound !== false
8
9 on('turn.complete', async ($, e, next) => {
10 const done = await next(e)
11
12 // 自分で中断したターンと、サブエージェントのターンは知らせない
13 if (e.agentId !== undefined || e.reason === 'aborted' || e.durationMs < minMs) {
14 return done
15 }
16
17 const took = durationText(e.durationMs)
18 $.ui.toast(e.reason === 'answer' ? `完了しました(${took})` : `途中で止まりました(${took})`, { timeoutMs: 10_000 })
19
20 if (hasSound) {
21 void $.audio.play({ asset: 'sounds/done.wav' }).catch(() => undefined)
22 }
23
24 return done
25 })
26
27 on('classic.Notification', async ($, e, next) => {
28 if (hasSound && e.notification_type === 'permission_prompt') {
29 void $.audio.play({ asset: 'sounds/ask.wav' }).catch(() => undefined)
30 }
31
32 return next(e)
33 })
34}
35hooks/time.ts 8 lines1/** かかった時間を「2分13秒」の形で。 */
2export function durationText(ms: number): string {
3 const seconds = Math.round(ms / 1_000)
4 const minutes = Math.floor(seconds / 60)
5
6 return minutes === 0 ? `${seconds}秒` : `${minutes}分${seconds % 60}秒`
7}
8