claude-code-sounds 1.6.0 → 1.6.1

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.
Files changed (3) hide show
  1. package/bin/cli.js +2 -6
  2. package/bin/lib.js +30 -14
  3. package/package.json +1 -1
package/bin/cli.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  const fs = require("fs");
4
4
  const path = require("path");
5
- const { execSync, spawn } = require("child_process");
5
+ const { execFileSync, spawn } = require("child_process");
6
6
  const p = require("@clack/prompts");
7
7
  const { Prompt } = require("@clack/core");
8
8
  const color = require("picocolors");
@@ -25,13 +25,9 @@ const installHooksConfig = () => lib.installHooksConfig(paths);
25
25
 
26
26
  // ─── Helpers ─────────────────────────────────────────────────────────────────
27
27
 
28
- function exec(cmd, opts = {}) {
29
- return execSync(cmd, { encoding: "utf-8", stdio: "pipe", ...opts });
30
- }
31
-
32
28
  function hasCommand(name) {
33
29
  try {
34
- exec(`which ${name}`);
30
+ execFileSync("which", [name], { stdio: "pipe" });
35
31
  return true;
36
32
  } catch {
37
33
  return false;
package/bin/lib.js CHANGED
@@ -67,7 +67,12 @@ function listThemes(paths) {
67
67
  for (const name of fs.readdirSync(paths.THEMES_DIR)) {
68
68
  const themeJson = path.join(paths.THEMES_DIR, name, "theme.json");
69
69
  if (!fs.existsSync(themeJson)) continue;
70
- const meta = JSON.parse(fs.readFileSync(themeJson, "utf-8"));
70
+ let meta;
71
+ try {
72
+ meta = JSON.parse(fs.readFileSync(themeJson, "utf-8"));
73
+ } catch {
74
+ continue;
75
+ }
71
76
  let soundCount = 0;
72
77
  if (meta.sounds) {
73
78
  for (const cat of Object.values(meta.sounds)) {
@@ -97,26 +102,34 @@ function resolveThemeSoundPath(themeName, fileName, paths) {
97
102
 
98
103
  function readSettings(paths) {
99
104
  if (fs.existsSync(paths.SETTINGS_PATH)) {
100
- return JSON.parse(fs.readFileSync(paths.SETTINGS_PATH, "utf-8"));
105
+ try {
106
+ return JSON.parse(fs.readFileSync(paths.SETTINGS_PATH, "utf-8"));
107
+ } catch {}
101
108
  }
102
109
  return {};
103
110
  }
104
111
 
105
112
  function writeSettings(settings, paths) {
106
113
  mkdirp(paths.CLAUDE_DIR);
107
- fs.writeFileSync(paths.SETTINGS_PATH, JSON.stringify(settings, null, 2) + "\n");
114
+ const tmp = paths.SETTINGS_PATH + ".tmp";
115
+ fs.writeFileSync(tmp, JSON.stringify(settings, null, 2) + "\n");
116
+ fs.renameSync(tmp, paths.SETTINGS_PATH);
108
117
  }
109
118
 
110
119
  function readInstalled(paths) {
111
120
  if (fs.existsSync(paths.INSTALLED_PATH)) {
112
- return JSON.parse(fs.readFileSync(paths.INSTALLED_PATH, "utf-8"));
121
+ try {
122
+ return JSON.parse(fs.readFileSync(paths.INSTALLED_PATH, "utf-8"));
123
+ } catch {}
113
124
  }
114
125
  return null;
115
126
  }
116
127
 
117
128
  function writeInstalled(data, paths) {
118
129
  mkdirp(paths.SOUNDS_DIR);
119
- fs.writeFileSync(paths.INSTALLED_PATH, JSON.stringify(data, null, 2) + "\n");
130
+ const tmp = paths.INSTALLED_PATH + ".tmp";
131
+ fs.writeFileSync(tmp, JSON.stringify(data, null, 2) + "\n");
132
+ fs.renameSync(tmp, paths.INSTALLED_PATH);
120
133
  }
121
134
 
122
135
  function isMuted(paths) {
@@ -221,23 +234,26 @@ function installSounds(selections, paths) {
221
234
  const catDir = path.join(paths.SOUNDS_DIR, cat);
222
235
  mkdirp(catDir);
223
236
 
224
- try {
225
- for (const f of fs.readdirSync(catDir)) {
226
- if (f.endsWith(".wav") || f.endsWith(".mp3")) {
227
- fs.unlinkSync(path.join(catDir, f));
228
- }
229
- }
230
- } catch {}
231
-
237
+ // Copy new files first
238
+ const newFiles = new Set();
232
239
  for (const item of items) {
233
240
  const srcPath = resolveThemeSoundPath(item.themeName, item.fileName, paths);
234
241
  const destPath = path.join(catDir, item.fileName);
235
-
236
242
  if (fs.existsSync(srcPath)) {
237
243
  fs.copyFileSync(srcPath, destPath);
238
244
  total++;
239
245
  }
246
+ newFiles.add(item.fileName);
240
247
  }
248
+
249
+ // Then remove old files not in the new set
250
+ try {
251
+ for (const f of fs.readdirSync(catDir)) {
252
+ if ((f.endsWith(".wav") || f.endsWith(".mp3")) && !newFiles.has(f)) {
253
+ fs.unlinkSync(path.join(catDir, f));
254
+ }
255
+ }
256
+ } catch {}
241
257
  }
242
258
 
243
259
  return total;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-sounds",
3
- "version": "1.6.0",
3
+ "version": "1.6.1",
4
4
  "description": "Sound themes for Claude Code lifecycle hooks",
5
5
  "bin": {
6
6
  "claude-code-sounds": "bin/cli.js"