claude-code-sounds 1.5.4 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +77 -49
- package/bin/cli.js +29 -0
- package/bin/lib.js +43 -0
- package/hooks/play-sound.sh +9 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -39,18 +39,6 @@ The bash installer requires `jq` (`brew install jq`).
|
|
|
39
39
|
|
|
40
40
|
</details>
|
|
41
41
|
|
|
42
|
-
## Usage
|
|
43
|
-
|
|
44
|
-
```bash
|
|
45
|
-
npx claude-code-sounds # Interactive install
|
|
46
|
-
npx claude-code-sounds --theme portal # Install a specific theme directly
|
|
47
|
-
npx claude-code-sounds --mix # Jump to sound assignment grid
|
|
48
|
-
npx claude-code-sounds --yes # Install defaults, skip all prompts
|
|
49
|
-
npx claude-code-sounds --list # List available themes
|
|
50
|
-
npx claude-code-sounds --uninstall # Remove all sounds and hooks
|
|
51
|
-
npx claude-code-sounds --help # Show help
|
|
52
|
-
```
|
|
53
|
-
|
|
54
42
|
## Themes
|
|
55
43
|
|
|
56
44
|
| Theme | Sounds | Vibe |
|
|
@@ -73,7 +61,78 @@ npx claude-code-sounds --help # Show help
|
|
|
73
61
|
|
|
74
62
|
Each theme maps sounds across all 11 Claude Code lifecycle events.
|
|
75
63
|
|
|
76
|
-
##
|
|
64
|
+
## Usage
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
npx claude-code-sounds # Interactive install
|
|
68
|
+
npx claude-code-sounds --theme portal # Install a specific theme directly
|
|
69
|
+
npx claude-code-sounds --mix # Jump to sound assignment grid
|
|
70
|
+
npx claude-code-sounds --yes # Install defaults, skip all prompts
|
|
71
|
+
npx claude-code-sounds --list # List available themes
|
|
72
|
+
npx claude-code-sounds --mute # Mute all sounds
|
|
73
|
+
npx claude-code-sounds --unmute # Unmute all sounds
|
|
74
|
+
npx claude-code-sounds --dnd # Auto-mute when in video calls
|
|
75
|
+
npx claude-code-sounds --no-dnd # Disable auto-mute
|
|
76
|
+
npx claude-code-sounds --uninstall # Remove all sounds and hooks
|
|
77
|
+
npx claude-code-sounds --help # Show help
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Muting
|
|
81
|
+
|
|
82
|
+
Mute sounds without uninstalling — three ways:
|
|
83
|
+
|
|
84
|
+
- **Slash command** (inside Claude Code): type `/mute` or `/unmute`
|
|
85
|
+
- **CLI flag**: `npx claude-code-sounds --mute` or `--unmute`
|
|
86
|
+
- **Interactive menu**: run `npx claude-code-sounds` and select "Mute sounds" / "Unmute sounds"
|
|
87
|
+
|
|
88
|
+
Muting creates a sentinel file at `~/.claude/sounds/.muted`. The hook script checks for it and exits immediately, so there's zero overhead when muted.
|
|
89
|
+
|
|
90
|
+
### Do Not Disturb
|
|
91
|
+
|
|
92
|
+
Sounds are automatically muted when active video calls are detected (Zoom, FaceTime, Webex). This is enabled by default.
|
|
93
|
+
|
|
94
|
+
Edit `~/.claude/sounds/.dnd` to add or remove app names — one process name per line, `#` for comments.
|
|
95
|
+
|
|
96
|
+
To disable: `npx claude-code-sounds --no-dnd` or use the interactive menu. Re-enable with `--dnd`.
|
|
97
|
+
|
|
98
|
+
## Customizing
|
|
99
|
+
|
|
100
|
+
Re-run with `--mix` to open the sound assignment grid, where you can reassign sounds to hooks, add themes, or preview clips:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
npx claude-code-sounds --mix
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+

|
|
107
|
+
|
|
108
|
+
You can also drop any `.wav` or `.mp3` into the sound directories manually:
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
~/.claude/sounds/
|
|
112
|
+
├── start/ # add files here for session start
|
|
113
|
+
├── stop/ # add files here for response complete
|
|
114
|
+
├── error/ # add files here for failures
|
|
115
|
+
└── ...
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
The script picks randomly from whatever files are in each directory.
|
|
119
|
+
|
|
120
|
+
## Uninstalling
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
npx claude-code-sounds --uninstall
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
This removes all sound files, the hook script, and the hooks config from `settings.json`.
|
|
127
|
+
|
|
128
|
+
<details>
|
|
129
|
+
<summary><h2 style="display:inline">How It Works</h2></summary>
|
|
130
|
+
|
|
131
|
+
A single script (`~/.claude/hooks/play-sound.sh`) handles all events. It takes a category name as an argument, picks a random `.wav` or `.mp3` from `~/.claude/sounds/<category>/`, and plays it with `afplay`.
|
|
132
|
+
|
|
133
|
+
Hooks are configured in `~/.claude/settings.json` — each Claude Code lifecycle event calls the script with the appropriate category.
|
|
134
|
+
|
|
135
|
+
### Hook Events
|
|
77
136
|
|
|
78
137
|
| Event | Hook | When |
|
|
79
138
|
|---|---|---|
|
|
@@ -89,7 +148,10 @@ Each theme maps sounds across all 11 Claude Code lifecycle events.
|
|
|
89
148
|
| `compact` | `PreCompact` | Context compaction |
|
|
90
149
|
| `teammate-idle` | `TeammateIdle` | Teammate went idle |
|
|
91
150
|
|
|
92
|
-
|
|
151
|
+
</details>
|
|
152
|
+
|
|
153
|
+
<details>
|
|
154
|
+
<summary><h2 style="display:inline">Creating a Theme</h2></summary>
|
|
93
155
|
|
|
94
156
|
Themes live in `themes/<name>/` with two items:
|
|
95
157
|
|
|
@@ -116,41 +178,7 @@ Defines metadata and maps sound files to hook categories:
|
|
|
116
178
|
|
|
117
179
|
Place audio files (`.wav` or `.mp3`) in `themes/<name>/sounds/` with filenames matching the `name` field in `theme.json`.
|
|
118
180
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
A single script (`~/.claude/hooks/play-sound.sh`) handles all events. It takes a category name as an argument, picks a random `.wav` or `.mp3` from `~/.claude/sounds/<category>/`, and plays it with `afplay`.
|
|
122
|
-
|
|
123
|
-
Hooks are configured in `~/.claude/settings.json` — each Claude Code lifecycle event calls the script with the appropriate category.
|
|
124
|
-
|
|
125
|
-
## Customizing
|
|
126
|
-
|
|
127
|
-
Re-run with `--mix` to open the sound assignment grid, where you can reassign sounds to hooks, add themes, or preview clips:
|
|
128
|
-
|
|
129
|
-
```bash
|
|
130
|
-
npx claude-code-sounds --mix
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-

|
|
134
|
-
|
|
135
|
-
You can also drop any `.wav` or `.mp3` into the sound directories manually:
|
|
136
|
-
|
|
137
|
-
```
|
|
138
|
-
~/.claude/sounds/
|
|
139
|
-
├── start/ # add files here for session start
|
|
140
|
-
├── stop/ # add files here for response complete
|
|
141
|
-
├── error/ # add files here for failures
|
|
142
|
-
└── ...
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
The script picks randomly from whatever files are in each directory.
|
|
146
|
-
|
|
147
|
-
## Uninstalling
|
|
148
|
-
|
|
149
|
-
```bash
|
|
150
|
-
npx claude-code-sounds --uninstall
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
This removes all sound files, the hook script, and the hooks config from `settings.json`.
|
|
181
|
+
</details>
|
|
154
182
|
|
|
155
183
|
## Disclaimer
|
|
156
184
|
|
package/bin/cli.js
CHANGED
|
@@ -381,6 +381,8 @@ function showHelp() {
|
|
|
381
381
|
npx claude-code-sounds --list List available themes
|
|
382
382
|
npx claude-code-sounds --mute Mute all sounds
|
|
383
383
|
npx claude-code-sounds --unmute Unmute all sounds
|
|
384
|
+
npx claude-code-sounds --dnd Auto-mute when in video calls
|
|
385
|
+
npx claude-code-sounds --no-dnd Disable auto-mute
|
|
384
386
|
npx claude-code-sounds --uninstall Remove all sounds and hooks
|
|
385
387
|
npx claude-code-sounds --help Show this help
|
|
386
388
|
|
|
@@ -391,6 +393,8 @@ function showHelp() {
|
|
|
391
393
|
-l, --list List available themes
|
|
392
394
|
--mute Mute all sounds
|
|
393
395
|
--unmute Unmute all sounds
|
|
396
|
+
--dnd Auto-mute when in video calls
|
|
397
|
+
--no-dnd Disable auto-mute
|
|
394
398
|
-h, --help Show this help
|
|
395
399
|
`);
|
|
396
400
|
}
|
|
@@ -636,11 +640,17 @@ async function interactiveInstall(autoYes) {
|
|
|
636
640
|
? { value: "unmute", label: "Unmute sounds", hint: "Sounds are currently muted" }
|
|
637
641
|
: { value: "mute", label: "Mute sounds", hint: "Silence sounds without uninstalling" };
|
|
638
642
|
|
|
643
|
+
const dnd = lib.isDnd(paths);
|
|
644
|
+
const dndOption = dnd
|
|
645
|
+
? { value: "dnd-off", label: "Disable Do Not Disturb", hint: "Stop auto-muting during calls" }
|
|
646
|
+
: { value: "dnd-on", label: "Enable Do Not Disturb", hint: "Auto-mute during video calls" };
|
|
647
|
+
|
|
639
648
|
const action = await p.select({
|
|
640
649
|
message: "What would you like to do?",
|
|
641
650
|
options: [
|
|
642
651
|
{ value: "modify", label: "Modify install", hint: "Add themes, change sounds" },
|
|
643
652
|
muteOption,
|
|
653
|
+
dndOption,
|
|
644
654
|
{ value: "fresh", label: "Fresh install", hint: "Start over from scratch" },
|
|
645
655
|
{ value: "uninstall", label: "Uninstall", hint: "Remove all sounds and hooks" },
|
|
646
656
|
],
|
|
@@ -663,6 +673,18 @@ async function interactiveInstall(autoYes) {
|
|
|
663
673
|
return;
|
|
664
674
|
}
|
|
665
675
|
|
|
676
|
+
if (action === "dnd-on") {
|
|
677
|
+
lib.setDnd(true, paths);
|
|
678
|
+
p.outro("Do Not Disturb enabled. Edit ~/.claude/sounds/.dnd to customize.");
|
|
679
|
+
return;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
if (action === "dnd-off") {
|
|
683
|
+
lib.setDnd(false, paths);
|
|
684
|
+
p.outro("Do Not Disturb disabled.");
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
687
|
+
|
|
666
688
|
if (action === "uninstall") {
|
|
667
689
|
uninstallAll();
|
|
668
690
|
p.outro("All sounds removed.");
|
|
@@ -839,6 +861,13 @@ if (flags.has("--help") || flags.has("-h")) {
|
|
|
839
861
|
} else if (flags.has("--unmute")) {
|
|
840
862
|
lib.setMuted(false, paths);
|
|
841
863
|
console.log(" Sounds unmuted.");
|
|
864
|
+
} else if (flags.has("--dnd")) {
|
|
865
|
+
lib.setDnd(true, paths);
|
|
866
|
+
console.log(" Do Not Disturb enabled. Sounds auto-mute when video call apps are detected.");
|
|
867
|
+
console.log(" Edit ~/.claude/sounds/.dnd to customize the app list.");
|
|
868
|
+
} else if (flags.has("--no-dnd")) {
|
|
869
|
+
lib.setDnd(false, paths);
|
|
870
|
+
console.log(" Do Not Disturb disabled.");
|
|
842
871
|
} else if (flags.has("--uninstall") || flags.has("--remove")) {
|
|
843
872
|
p.intro(color.bold("claude-code-sounds"));
|
|
844
873
|
uninstallAll();
|
package/bin/lib.js
CHANGED
|
@@ -133,6 +133,41 @@ function setMuted(muted, paths) {
|
|
|
133
133
|
}
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
+
const DND_DEFAULTS = [
|
|
137
|
+
"# Auto-mute during active calls",
|
|
138
|
+
"# One process name per line, # for comments",
|
|
139
|
+
"# Tip: use meeting-specific processes, not main apps (they stay open after calls)",
|
|
140
|
+
"# Find process names with: pgrep -la <app>",
|
|
141
|
+
"CptHost",
|
|
142
|
+
"FaceTime",
|
|
143
|
+
"Webex",
|
|
144
|
+
];
|
|
145
|
+
|
|
146
|
+
function isDnd(paths) {
|
|
147
|
+
return fs.existsSync(path.join(paths.SOUNDS_DIR, ".dnd"));
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function setDnd(enabled, paths) {
|
|
151
|
+
const dndPath = path.join(paths.SOUNDS_DIR, ".dnd");
|
|
152
|
+
if (enabled) {
|
|
153
|
+
mkdirp(paths.SOUNDS_DIR);
|
|
154
|
+
fs.writeFileSync(dndPath, DND_DEFAULTS.join("\n") + "\n");
|
|
155
|
+
// Ensure the installed hook script supports DND
|
|
156
|
+
_updateHookScript(paths);
|
|
157
|
+
} else if (fs.existsSync(dndPath)) {
|
|
158
|
+
fs.unlinkSync(dndPath);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function _updateHookScript(paths) {
|
|
163
|
+
const hookSrc = path.join(paths.PKG_DIR, "hooks", "play-sound.sh");
|
|
164
|
+
const hookDest = path.join(paths.HOOKS_DIR, "play-sound.sh");
|
|
165
|
+
if (fs.existsSync(hookDest) && fs.existsSync(hookSrc)) {
|
|
166
|
+
fs.copyFileSync(hookSrc, hookDest);
|
|
167
|
+
fs.chmodSync(hookDest, 0o755);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
136
171
|
// ─── Detect Existing Install ─────────────────────────────────────────────────
|
|
137
172
|
|
|
138
173
|
function detectExistingInstall(paths) {
|
|
@@ -230,6 +265,11 @@ function installHooksConfig(paths) {
|
|
|
230
265
|
}
|
|
231
266
|
}
|
|
232
267
|
}
|
|
268
|
+
|
|
269
|
+
// Enable Do Not Disturb by default (auto-mute during video calls)
|
|
270
|
+
if (!isDnd(paths)) {
|
|
271
|
+
setDnd(true, paths);
|
|
272
|
+
}
|
|
233
273
|
}
|
|
234
274
|
|
|
235
275
|
function uninstallAll(paths) {
|
|
@@ -300,6 +340,9 @@ module.exports = {
|
|
|
300
340
|
writeInstalled,
|
|
301
341
|
isMuted,
|
|
302
342
|
setMuted,
|
|
343
|
+
DND_DEFAULTS,
|
|
344
|
+
isDnd,
|
|
345
|
+
setDnd,
|
|
303
346
|
detectExistingInstall,
|
|
304
347
|
installSounds,
|
|
305
348
|
installHooksConfig,
|
package/hooks/play-sound.sh
CHANGED
|
@@ -6,6 +6,15 @@ CATEGORY="${1:-}"
|
|
|
6
6
|
cat > /dev/null 2>&1
|
|
7
7
|
|
|
8
8
|
[[ -f "$SOUNDS_DIR/.muted" ]] && exit 0
|
|
9
|
+
|
|
10
|
+
# Auto-mute: skip when video call apps are running
|
|
11
|
+
if [[ -f "$SOUNDS_DIR/.dnd" ]]; then
|
|
12
|
+
while IFS= read -r proc || [[ -n "$proc" ]]; do
|
|
13
|
+
[[ -z "$proc" || "$proc" == \#* ]] && continue
|
|
14
|
+
pgrep -xi "$proc" > /dev/null 2>&1 && exit 0
|
|
15
|
+
done < "$SOUNDS_DIR/.dnd"
|
|
16
|
+
fi
|
|
17
|
+
|
|
9
18
|
[[ -z "$CATEGORY" ]] && exit 0
|
|
10
19
|
DIR="$SOUNDS_DIR/$CATEGORY"
|
|
11
20
|
[[ ! -d "$DIR" ]] && exit 0
|