agentvibes 4.2.0 → 4.4.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.
Files changed (219) hide show
  1. package/.agentvibes/bmad/bmad-voices.md +69 -69
  2. package/.agentvibes/config.json +12 -0
  3. package/.claude/activation-instructions +54 -54
  4. package/.claude/audio/tracks/README.md +52 -52
  5. package/.claude/commands/agent-vibes/add.md +21 -21
  6. package/.claude/commands/agent-vibes/agent-vibes.md +101 -101
  7. package/.claude/commands/agent-vibes/agent.md +79 -79
  8. package/.claude/commands/agent-vibes/background-music.md +111 -111
  9. package/.claude/commands/agent-vibes/bmad.md +198 -198
  10. package/.claude/commands/agent-vibes/clean.md +18 -18
  11. package/.claude/commands/agent-vibes/cleanup.md +18 -18
  12. package/.claude/commands/agent-vibes/commands.json +145 -145
  13. package/.claude/commands/agent-vibes/effects.md +97 -97
  14. package/.claude/commands/agent-vibes/get.md +9 -9
  15. package/.claude/commands/agent-vibes/hide.md +91 -91
  16. package/.claude/commands/agent-vibes/language.md +23 -23
  17. package/.claude/commands/agent-vibes/learn.md +67 -67
  18. package/.claude/commands/agent-vibes/list.md +13 -13
  19. package/.claude/commands/agent-vibes/mute.md +37 -37
  20. package/.claude/commands/agent-vibes/preview.md +17 -17
  21. package/.claude/commands/agent-vibes/provider.md +68 -68
  22. package/.claude/commands/agent-vibes/replay-target.md +14 -14
  23. package/.claude/commands/agent-vibes/sample.md +12 -12
  24. package/.claude/commands/agent-vibes/set-favorite-voice.md +84 -84
  25. package/.claude/commands/agent-vibes/set-pretext.md +65 -65
  26. package/.claude/commands/agent-vibes/set-speed.md +41 -41
  27. package/.claude/commands/agent-vibes/show.md +84 -84
  28. package/.claude/commands/agent-vibes/switch.md +87 -87
  29. package/.claude/commands/agent-vibes/target-voice.md +26 -26
  30. package/.claude/commands/agent-vibes/target.md +30 -30
  31. package/.claude/commands/agent-vibes/translate.md +68 -68
  32. package/.claude/commands/agent-vibes/unmute.md +45 -45
  33. package/.claude/commands/agent-vibes/verbosity.md +89 -89
  34. package/.claude/commands/agent-vibes/whoami.md +7 -7
  35. package/.claude/commands/agent-vibes-bmad-voices.md +117 -117
  36. package/.claude/commands/agent-vibes-rdp.md +24 -24
  37. package/.claude/config/agentvibes.json +1 -0
  38. package/.claude/config/audio-effects.cfg +2 -2
  39. package/.claude/config/audio-effects.cfg.sample +52 -52
  40. package/.claude/config/background-music-volume.txt +1 -0
  41. package/.claude/config/intro-text.txt +1 -0
  42. package/.claude/config/piper-speech-rate.txt +4 -0
  43. package/.claude/config/piper-target-speech-rate.txt +1 -0
  44. package/.claude/config/reverb-level.txt +1 -0
  45. package/.claude/config/tts-speech-rate.txt +4 -0
  46. package/.claude/config/tts-target-speech-rate.txt +1 -0
  47. package/.claude/docs/TERMUX_SETUP.md +408 -408
  48. package/.claude/github-star-reminder.txt +1 -1
  49. package/.claude/hooks/README-TTS-QUEUE.md +135 -135
  50. package/.claude/hooks/audio-cache-utils.sh +246 -246
  51. package/.claude/hooks/audio-processor.sh +433 -433
  52. package/.claude/hooks/background-music-manager.sh +404 -404
  53. package/.claude/hooks/bmad-speak-enhanced.sh +165 -165
  54. package/.claude/hooks/bmad-speak.sh +269 -269
  55. package/.claude/hooks/bmad-tts-injector.sh +568 -568
  56. package/.claude/hooks/bmad-voice-manager.sh +928 -928
  57. package/.claude/hooks/clawdbot-receiver-SECURE.sh +129 -129
  58. package/.claude/hooks/clawdbot-receiver.sh +107 -107
  59. package/.claude/hooks/clean-audio-cache.sh +22 -22
  60. package/.claude/hooks/cleanup-cache.sh +106 -106
  61. package/.claude/hooks/configure-rdp-mode.sh +137 -137
  62. package/.claude/hooks/download-extra-voices.sh +244 -244
  63. package/.claude/hooks/effects-manager.sh +268 -268
  64. package/.claude/hooks/github-star-reminder.sh +154 -154
  65. package/.claude/hooks/language-manager.sh +362 -362
  66. package/.claude/hooks/learn-manager.sh +492 -492
  67. package/.claude/hooks/macos-voice-manager.sh +205 -205
  68. package/.claude/hooks/migrate-background-music.sh +125 -125
  69. package/.claude/hooks/migrate-to-agentvibes.sh +161 -161
  70. package/.claude/hooks/optimize-background-music.sh +87 -87
  71. package/.claude/hooks/path-resolver.sh +60 -60
  72. package/.claude/hooks/personality-manager.sh +448 -448
  73. package/.claude/hooks/piper-download-voices.sh +225 -225
  74. package/.claude/hooks/piper-installer.sh +292 -292
  75. package/.claude/hooks/piper-multispeaker-registry.sh +171 -171
  76. package/.claude/hooks/piper-voice-manager.sh +24 -3
  77. package/.claude/hooks/play-tts-agentvibes-receiver-for-voiceless-connections.sh +90 -90
  78. package/.claude/hooks/play-tts-enhanced.sh +105 -105
  79. package/.claude/hooks/play-tts-macos.sh +368 -368
  80. package/.claude/hooks/play-tts-piper.sh +679 -679
  81. package/.claude/hooks/play-tts-soprano.sh +356 -356
  82. package/.claude/hooks/play-tts-ssh-remote.sh +167 -167
  83. package/.claude/hooks/play-tts-termux-ssh.sh +169 -169
  84. package/.claude/hooks/play-tts.sh +301 -301
  85. package/.claude/hooks/prepare-release.sh +54 -54
  86. package/.claude/hooks/provider-commands.sh +617 -617
  87. package/.claude/hooks/provider-manager.sh +399 -399
  88. package/.claude/hooks/replay-target-audio.sh +95 -95
  89. package/.claude/hooks/requirements.txt +6 -6
  90. package/.claude/hooks/sentiment-manager.sh +201 -201
  91. package/.claude/hooks/session-start-tts.sh +81 -81
  92. package/.claude/hooks/soprano-gradio-synth.py +139 -139
  93. package/.claude/hooks/speed-manager.sh +291 -291
  94. package/.claude/hooks/stop-tts.sh +84 -84
  95. package/.claude/hooks/termux-installer.sh +261 -261
  96. package/.claude/hooks/translate-manager.sh +341 -341
  97. package/.claude/hooks/translator.py +237 -237
  98. package/.claude/hooks/tts-queue-worker.sh +145 -145
  99. package/.claude/hooks/tts-queue.sh +165 -165
  100. package/.claude/hooks/verbosity-manager.sh +178 -178
  101. package/.claude/hooks/voice-manager.sh +548 -548
  102. package/.claude/hooks-windows/audio-cache-utils.ps1 +119 -119
  103. package/.claude/hooks-windows/background-music-manager.ps1 +348 -0
  104. package/.claude/hooks-windows/clean-audio-cache.ps1 +53 -0
  105. package/.claude/hooks-windows/download-extra-voices.ps1 +185 -0
  106. package/.claude/hooks-windows/effects-manager.ps1 +294 -0
  107. package/.claude/hooks-windows/language-manager.ps1 +193 -0
  108. package/.claude/hooks-windows/learn-manager.ps1 +241 -0
  109. package/.claude/hooks-windows/personality-manager.ps1 +266 -0
  110. package/.claude/hooks-windows/play-tts-piper.ps1 +209 -0
  111. package/.claude/hooks-windows/play-tts-sapi.ps1 +108 -0
  112. package/.claude/hooks-windows/play-tts-soprano.ps1 +159 -158
  113. package/.claude/hooks-windows/play-tts-windows-piper.ps1 +50 -5
  114. package/.claude/hooks-windows/play-tts-windows-sapi.ps1 +108 -108
  115. package/.claude/hooks-windows/play-tts.ps1 +344 -266
  116. package/.claude/hooks-windows/provider-manager.ps1 +29 -10
  117. package/.claude/hooks-windows/session-start-tts.ps1 +124 -124
  118. package/.claude/hooks-windows/soprano-gradio-synth.py +153 -153
  119. package/.claude/hooks-windows/speed-manager.ps1 +166 -0
  120. package/.claude/hooks-windows/verbosity-manager.ps1 +119 -0
  121. package/.claude/hooks-windows/voice-manager-windows.ps1 +92 -8
  122. package/.claude/output-styles/agent-vibes.md +202 -202
  123. package/.claude/personalities/angry.md +14 -14
  124. package/.claude/personalities/annoying.md +14 -14
  125. package/.claude/personalities/crass.md +14 -14
  126. package/.claude/personalities/dramatic.md +14 -14
  127. package/.claude/personalities/dry-humor.md +50 -50
  128. package/.claude/personalities/flirty.md +20 -20
  129. package/.claude/personalities/funny.md +14 -14
  130. package/.claude/personalities/grandpa.md +32 -32
  131. package/.claude/personalities/millennial.md +14 -14
  132. package/.claude/personalities/moody.md +14 -14
  133. package/.claude/personalities/normal.md +16 -16
  134. package/.claude/personalities/pirate.md +14 -14
  135. package/.claude/personalities/poetic.md +14 -14
  136. package/.claude/personalities/professional.md +14 -14
  137. package/.claude/personalities/rapper.md +55 -55
  138. package/.claude/personalities/robot.md +14 -14
  139. package/.claude/personalities/sarcastic.md +38 -38
  140. package/.claude/personalities/sassy.md +14 -14
  141. package/.claude/personalities/surfer-dude.md +14 -14
  142. package/.claude/personalities/zen.md +14 -14
  143. package/.claude/settings.json +15 -15
  144. package/.claude/verbosity.txt +1 -1
  145. package/.clawdbot/README.md +105 -105
  146. package/.clawdbot/skill/SKILL.md +241 -241
  147. package/.mcp.json +12 -0
  148. package/CLAUDE.md +170 -170
  149. package/README.md +2029 -2007
  150. package/RELEASE_NOTES.md +1310 -1203
  151. package/WINDOWS-SETUP.md +208 -208
  152. package/bin/agent-vibes +39 -39
  153. package/bin/agentvibes-voice-browser.js +1840 -1840
  154. package/bin/agentvibes.js +48 -2
  155. package/bin/mcp-server.js +121 -121
  156. package/bin/mcp-server.sh +206 -206
  157. package/bin/test-bmad-pr +78 -78
  158. package/mcp-server/QUICK_START.md +203 -203
  159. package/mcp-server/README.md +345 -345
  160. package/mcp-server/WINDOWS_SETUP.md +260 -260
  161. package/mcp-server/docs/troubleshooting-audio.md +313 -313
  162. package/mcp-server/examples/claude_desktop_config.json +11 -11
  163. package/mcp-server/examples/claude_desktop_config_piper.json +9 -9
  164. package/mcp-server/examples/custom_instructions.md +169 -169
  165. package/mcp-server/install-deps.js +130 -130
  166. package/mcp-server/pyproject.toml +52 -52
  167. package/mcp-server/requirements.txt +2 -2
  168. package/mcp-server/server.py +1465 -1453
  169. package/mcp-server/test_server.py +395 -395
  170. package/mcp-server/test_windows_script_parity.py +336 -0
  171. package/package.json +110 -110
  172. package/setup-windows.ps1 +815 -815
  173. package/src/bmad-detector.js +71 -71
  174. package/src/cli/list-personalities.js +110 -110
  175. package/src/cli/list-voices.js +114 -114
  176. package/src/commands/bmad-voices.js +394 -394
  177. package/src/commands/install-mcp.js +476 -476
  178. package/src/console/app.js +824 -824
  179. package/src/console/audio-env.js +20 -1
  180. package/src/console/brand-colors.js +13 -13
  181. package/src/console/constants/personalities.js +44 -44
  182. package/src/console/footer-config.js +50 -50
  183. package/src/console/modals/modal-overlay.js +247 -247
  184. package/src/console/navigation.js +62 -62
  185. package/src/console/tabs/agents-tab.js +1684 -1516
  186. package/src/console/tabs/help-tab.js +261 -261
  187. package/src/console/tabs/install-tab.js +1007 -991
  188. package/src/console/tabs/music-tab.js +22 -8
  189. package/src/console/tabs/placeholder-tab.js +53 -53
  190. package/src/console/tabs/readme-tab.js +267 -267
  191. package/src/console/tabs/receiver-tab.js +1472 -1212
  192. package/src/console/tabs/settings-tab.js +152 -79
  193. package/src/console/tabs/voices-tab.js +100 -21
  194. package/src/console/widgets/destroy-list.js +25 -25
  195. package/src/console/widgets/format-utils.js +89 -89
  196. package/src/console/widgets/notice.js +55 -55
  197. package/src/console/widgets/personality-picker.js +185 -185
  198. package/src/console/widgets/reverb-picker.js +94 -94
  199. package/src/console/widgets/track-picker.js +285 -285
  200. package/src/installer/music-file-input.js +304 -304
  201. package/src/installer.js +5882 -5829
  202. package/src/services/agent-voice-store.js +423 -423
  203. package/src/services/config-service.js +264 -264
  204. package/src/services/navigation-service.js +123 -123
  205. package/src/services/provider-service.js +132 -132
  206. package/src/services/verbosity-service.js +157 -157
  207. package/src/utils/audio-duration-validator.js +298 -298
  208. package/src/utils/audio-format-validator.js +277 -277
  209. package/src/utils/dependency-checker.js +469 -466
  210. package/src/utils/file-ownership-verifier.js +358 -358
  211. package/src/utils/list-formatter.js +194 -194
  212. package/src/utils/music-file-validator.js +285 -285
  213. package/src/utils/preview-list-prompt.js +136 -136
  214. package/src/utils/provider-validator.js +96 -12
  215. package/src/utils/secure-music-storage.js +412 -412
  216. package/templates/agentvibes-receiver.sh +482 -482
  217. package/templates/audio/welcome-music.mp3 +0 -0
  218. package/voice-assignments.json +8244 -8244
  219. package/.claude/config/background-music-position.txt +0 -1
@@ -1,246 +1,246 @@
1
- #!/usr/bin/env bash
2
- # AgentVibes Audio Cache Utility Functions
3
- # Provides common functions for file counting, sizing, and cleanup operations
4
-
5
- # Get the audio directory path with priority order
6
- # Returns: Absolute path to audio directory
7
- get_audio_dir() {
8
- local audio_dir=""
9
-
10
- # Priority 1: Project-local directory (if CLAUDE_PROJECT_DIR is set)
11
- if [[ -n "${CLAUDE_PROJECT_DIR:-}" ]]; then
12
- audio_dir="$CLAUDE_PROJECT_DIR/.claude/audio"
13
- else
14
- # Priority 2: Walk up directory tree to find .claude
15
- local current_dir="$PWD"
16
- while [[ "$current_dir" != "/" ]]; do
17
- if [[ -d "$current_dir/.claude" ]]; then
18
- audio_dir="$current_dir/.claude/audio"
19
- break
20
- fi
21
- current_dir=$(dirname "$current_dir")
22
- done
23
- fi
24
-
25
- # Priority 3: Fallback to global ~/.claude/audio
26
- if [[ -z "$audio_dir" ]]; then
27
- audio_dir="$HOME/.claude/audio"
28
- fi
29
-
30
- echo "$audio_dir"
31
- }
32
-
33
- # Count TTS audio files (excludes background music tracks in tracks/ subdirectory)
34
- # Args: $1 = audio_dir (optional, defaults to get_audio_dir)
35
- # Returns: Integer count
36
- count_tts_files() {
37
- local audio_dir="${1:-$(get_audio_dir)}"
38
-
39
- if [[ ! -d "$audio_dir" ]]; then
40
- echo "0"
41
- return
42
- fi
43
-
44
- # Count TTS output files only (excludes subdirectories like tracks/)
45
- local count=0
46
- count=$(find "$audio_dir" -maxdepth 1 -type f \( \
47
- -name "tts-*.wav" -o \
48
- -name "tts-*.mp3" -o \
49
- -name "tts-*.aiff" -o \
50
- -name "tts-padded-*.mp3" -o \
51
- -name "tts-padded-*.wav" \
52
- \) 2>/dev/null | wc -l)
53
-
54
- echo "$count"
55
- }
56
-
57
- # Calculate total size of TTS audio files in bytes
58
- # Args: $1 = audio_dir (optional, defaults to get_audio_dir)
59
- # Returns: Size in bytes (integer)
60
- calculate_tts_size_bytes() {
61
- local audio_dir="${1:-$(get_audio_dir)}"
62
-
63
- if [[ ! -d "$audio_dir" ]]; then
64
- echo "0"
65
- return
66
- fi
67
-
68
- local total_bytes=0
69
- local stat_cmd=""
70
-
71
- # Detect stat command format (BSD vs GNU)
72
- if stat -c%s /dev/null >/dev/null 2>&1; then
73
- stat_cmd="stat -c%s"
74
- else
75
- stat_cmd="stat -f%z"
76
- fi
77
-
78
- # Sum file sizes for all TTS files
79
- while IFS= read -r file; do
80
- if [[ -f "$file" ]]; then
81
- local size=$($stat_cmd "$file" 2>/dev/null || echo "0")
82
- total_bytes=$((total_bytes + size))
83
- fi
84
- done < <(find "$audio_dir" -maxdepth 1 -type f \( \
85
- -name "tts-*.wav" -o \
86
- -name "tts-*.mp3" -o \
87
- -name "tts-*.aiff" -o \
88
- -name "tts-padded-*.mp3" -o \
89
- -name "tts-padded-*.wav" \
90
- \) 2>/dev/null)
91
-
92
- echo "$total_bytes"
93
- }
94
-
95
- # Convert bytes to human-readable format (e.g., "1.4MB", "230KB")
96
- # Args: $1 = bytes
97
- # Returns: Human-readable string (B, KB, MB, GB)
98
- bytes_to_human() {
99
- local bytes="${1:-0}"
100
-
101
- if [[ ! "$bytes" =~ ^[0-9]+$ ]]; then
102
- bytes="0"
103
- fi
104
-
105
- if [[ $bytes -lt 1024 ]]; then
106
- echo "${bytes}B"
107
- elif [[ $bytes -lt 1048576 ]]; then
108
- awk "BEGIN {printf \"%.1fKB\", $bytes/1024}"
109
- elif [[ $bytes -lt 1073741824 ]]; then
110
- awk "BEGIN {printf \"%.1fMB\", $bytes/1048576}"
111
- else
112
- awk "BEGIN {printf \"%.1fGB\", $bytes/1073741824}"
113
- fi
114
- }
115
-
116
- # Get auto-cleanup threshold (number of files before cleanup triggers)
117
- # Returns: Integer threshold (default: 50)
118
- get_auto_clean_threshold() {
119
- local threshold_file=""
120
- local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
121
-
122
- # Priority order for config file
123
- if [[ -n "${CLAUDE_PROJECT_DIR:-}" ]] && [[ -f "$CLAUDE_PROJECT_DIR/.claude/tts-auto-clean-threshold.txt" ]]; then
124
- threshold_file="$CLAUDE_PROJECT_DIR/.claude/tts-auto-clean-threshold.txt"
125
- elif [[ -f "$script_dir/../tts-auto-clean-threshold.txt" ]]; then
126
- threshold_file="$script_dir/../tts-auto-clean-threshold.txt"
127
- elif [[ -f "$HOME/.claude/tts-auto-clean-threshold.txt" ]]; then
128
- threshold_file="$HOME/.claude/tts-auto-clean-threshold.txt"
129
- fi
130
-
131
- if [[ -n "$threshold_file" ]]; then
132
- local threshold=$(grep -v '^\s*#' "$threshold_file" 2>/dev/null | grep -v '^\s*$' | head -1)
133
- if [[ "$threshold" =~ ^[0-9]+$ ]]; then
134
- echo "$threshold"
135
- return
136
- fi
137
- fi
138
-
139
- # Default threshold
140
- echo "50"
141
- }
142
-
143
- # Delete oldest TTS files to stay under size threshold (in MB)
144
- # Args: $1 = audio_dir, $2 = threshold (size in MB)
145
- # Returns: Number of files deleted
146
- auto_clean_old_files() {
147
- local audio_dir="${1:-$(get_audio_dir)}"
148
- local threshold_mb="${2:-15}"
149
- local threshold_bytes=$((threshold_mb * 1048576))
150
-
151
- if [[ ! -d "$audio_dir" ]]; then
152
- echo "0"
153
- return
154
- fi
155
-
156
- local current_size=$(calculate_tts_size_bytes "$audio_dir")
157
-
158
- if [[ $current_size -le $threshold_bytes ]]; then
159
- echo "0"
160
- return
161
- fi
162
-
163
- # SAFETY CHECK: Skip cleanup if any TTS files have active write locks
164
- # Check for .lock files that indicate in-progress TTS generation
165
- local lock_count=$(find "$audio_dir" -maxdepth 1 -name "tts-*.lock" -type f 2>/dev/null | wc -l)
166
- if [[ $lock_count -gt 0 ]]; then
167
- # Active TTS generation in progress, skip cleanup to avoid race condition
168
- return 0
169
- fi
170
-
171
- local files_deleted=0
172
- local current_size_bytes=$current_size
173
-
174
- # Delete oldest files until under threshold
175
- # IMPORTANT: Only delete auto-generated TTS files, NOT project assets like welcome-multivoice-final.wav
176
- while [[ $current_size_bytes -gt $threshold_bytes ]]; do
177
- # Find the oldest file (only tts-processed-* and tts-padded-* files, not other project assets)
178
- local oldest_file=$(find "$audio_dir" -maxdepth 1 -type f \( \
179
- -name "tts-processed-*.wav" -o \
180
- -name "tts-processed-*.mp3" -o \
181
- -name "tts-padded-*.mp3" -o \
182
- -name "tts-padded-*.wav" \
183
- \) -printf '%T+ %p\n' 2>/dev/null | sort | head -1 | cut -d' ' -f2-)
184
-
185
- if [[ -z "$oldest_file" ]]; then
186
- break
187
- fi
188
-
189
- # Get file size and delete it
190
- local file_size=$(stat -c%s "$oldest_file" 2>/dev/null || stat -f%z "$oldest_file" 2>/dev/null || echo "0")
191
- rm -f "$oldest_file" 2>/dev/null || true
192
- current_size_bytes=$((current_size_bytes - file_size))
193
- files_deleted=$((files_deleted + 1))
194
- done
195
-
196
- echo "$files_deleted"
197
- }
198
-
199
- # Clean all TTS audio files and report stats
200
- # Args: $1 = audio_dir (optional, defaults to get_audio_dir)
201
- # Returns: Formatted output with cleanup stats
202
- clean_all_tts_files() {
203
- local audio_dir="${1:-$(get_audio_dir)}"
204
-
205
- # Color codes
206
- local RED='\033[0;31m'
207
- local GREEN='\033[0;32m'
208
- local YELLOW='\033[1;33m'
209
- local BLUE='\033[0;34m'
210
- local NC='\033[0m' # No Color
211
-
212
- # Get stats before cleanup
213
- local count_before=$(count_tts_files "$audio_dir")
214
- local size_before=$(calculate_tts_size_bytes "$audio_dir")
215
- local human_before=$(bytes_to_human "$size_before")
216
-
217
- if [[ $count_before -eq 0 ]]; then
218
- echo -e "${GREEN}✅ Cache is already clean! No TTS files found.${NC}"
219
- return
220
- fi
221
-
222
- # Delete auto-generated TTS files only (preserve project assets like welcome-multivoice-final.wav)
223
- find "$audio_dir" -maxdepth 1 -type f \( \
224
- -name "tts-processed-*.wav" -o \
225
- -name "tts-processed-*.mp3" -o \
226
- -name "tts-padded-*.mp3" -o \
227
- -name "tts-padded-*.wav" \
228
- \) -delete 2>/dev/null || true
229
-
230
- # Also delete BMAD party mode recordings if they exist
231
- if [[ -d "$audio_dir/bmad-party-mode-recordings" ]]; then
232
- rm -rf "$audio_dir/bmad-party-mode-recordings" 2>/dev/null || true
233
- fi
234
-
235
- # Get stats after cleanup
236
- local count_after=$(count_tts_files "$audio_dir")
237
- local size_after=$(calculate_tts_size_bytes "$audio_dir")
238
- local human_after=$(bytes_to_human "$size_after")
239
- local freed=$((size_before - size_after))
240
- local human_freed=$(bytes_to_human "$freed")
241
-
242
- echo -e "${GREEN}✅ Cleanup complete!${NC}"
243
- echo " • Files deleted: ${YELLOW}$count_before${NC}"
244
- echo " • Space freed: ${YELLOW}$human_freed${NC}"
245
- echo " • Before: $human_before | After: $human_after"
246
- }
1
+ #!/usr/bin/env bash
2
+ # AgentVibes Audio Cache Utility Functions
3
+ # Provides common functions for file counting, sizing, and cleanup operations
4
+
5
+ # Get the audio directory path with priority order
6
+ # Returns: Absolute path to audio directory
7
+ get_audio_dir() {
8
+ local audio_dir=""
9
+
10
+ # Priority 1: Project-local directory (if CLAUDE_PROJECT_DIR is set)
11
+ if [[ -n "${CLAUDE_PROJECT_DIR:-}" ]]; then
12
+ audio_dir="$CLAUDE_PROJECT_DIR/.claude/audio"
13
+ else
14
+ # Priority 2: Walk up directory tree to find .claude
15
+ local current_dir="$PWD"
16
+ while [[ "$current_dir" != "/" ]]; do
17
+ if [[ -d "$current_dir/.claude" ]]; then
18
+ audio_dir="$current_dir/.claude/audio"
19
+ break
20
+ fi
21
+ current_dir=$(dirname "$current_dir")
22
+ done
23
+ fi
24
+
25
+ # Priority 3: Fallback to global ~/.claude/audio
26
+ if [[ -z "$audio_dir" ]]; then
27
+ audio_dir="$HOME/.claude/audio"
28
+ fi
29
+
30
+ echo "$audio_dir"
31
+ }
32
+
33
+ # Count TTS audio files (excludes background music tracks in tracks/ subdirectory)
34
+ # Args: $1 = audio_dir (optional, defaults to get_audio_dir)
35
+ # Returns: Integer count
36
+ count_tts_files() {
37
+ local audio_dir="${1:-$(get_audio_dir)}"
38
+
39
+ if [[ ! -d "$audio_dir" ]]; then
40
+ echo "0"
41
+ return
42
+ fi
43
+
44
+ # Count TTS output files only (excludes subdirectories like tracks/)
45
+ local count=0
46
+ count=$(find "$audio_dir" -maxdepth 1 -type f \( \
47
+ -name "tts-*.wav" -o \
48
+ -name "tts-*.mp3" -o \
49
+ -name "tts-*.aiff" -o \
50
+ -name "tts-padded-*.mp3" -o \
51
+ -name "tts-padded-*.wav" \
52
+ \) 2>/dev/null | wc -l)
53
+
54
+ echo "$count"
55
+ }
56
+
57
+ # Calculate total size of TTS audio files in bytes
58
+ # Args: $1 = audio_dir (optional, defaults to get_audio_dir)
59
+ # Returns: Size in bytes (integer)
60
+ calculate_tts_size_bytes() {
61
+ local audio_dir="${1:-$(get_audio_dir)}"
62
+
63
+ if [[ ! -d "$audio_dir" ]]; then
64
+ echo "0"
65
+ return
66
+ fi
67
+
68
+ local total_bytes=0
69
+ local stat_cmd=""
70
+
71
+ # Detect stat command format (BSD vs GNU)
72
+ if stat -c%s /dev/null >/dev/null 2>&1; then
73
+ stat_cmd="stat -c%s"
74
+ else
75
+ stat_cmd="stat -f%z"
76
+ fi
77
+
78
+ # Sum file sizes for all TTS files
79
+ while IFS= read -r file; do
80
+ if [[ -f "$file" ]]; then
81
+ local size=$($stat_cmd "$file" 2>/dev/null || echo "0")
82
+ total_bytes=$((total_bytes + size))
83
+ fi
84
+ done < <(find "$audio_dir" -maxdepth 1 -type f \( \
85
+ -name "tts-*.wav" -o \
86
+ -name "tts-*.mp3" -o \
87
+ -name "tts-*.aiff" -o \
88
+ -name "tts-padded-*.mp3" -o \
89
+ -name "tts-padded-*.wav" \
90
+ \) 2>/dev/null)
91
+
92
+ echo "$total_bytes"
93
+ }
94
+
95
+ # Convert bytes to human-readable format (e.g., "1.4MB", "230KB")
96
+ # Args: $1 = bytes
97
+ # Returns: Human-readable string (B, KB, MB, GB)
98
+ bytes_to_human() {
99
+ local bytes="${1:-0}"
100
+
101
+ if [[ ! "$bytes" =~ ^[0-9]+$ ]]; then
102
+ bytes="0"
103
+ fi
104
+
105
+ if [[ $bytes -lt 1024 ]]; then
106
+ echo "${bytes}B"
107
+ elif [[ $bytes -lt 1048576 ]]; then
108
+ awk "BEGIN {printf \"%.1fKB\", $bytes/1024}"
109
+ elif [[ $bytes -lt 1073741824 ]]; then
110
+ awk "BEGIN {printf \"%.1fMB\", $bytes/1048576}"
111
+ else
112
+ awk "BEGIN {printf \"%.1fGB\", $bytes/1073741824}"
113
+ fi
114
+ }
115
+
116
+ # Get auto-cleanup threshold (number of files before cleanup triggers)
117
+ # Returns: Integer threshold (default: 50)
118
+ get_auto_clean_threshold() {
119
+ local threshold_file=""
120
+ local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
121
+
122
+ # Priority order for config file
123
+ if [[ -n "${CLAUDE_PROJECT_DIR:-}" ]] && [[ -f "$CLAUDE_PROJECT_DIR/.claude/tts-auto-clean-threshold.txt" ]]; then
124
+ threshold_file="$CLAUDE_PROJECT_DIR/.claude/tts-auto-clean-threshold.txt"
125
+ elif [[ -f "$script_dir/../tts-auto-clean-threshold.txt" ]]; then
126
+ threshold_file="$script_dir/../tts-auto-clean-threshold.txt"
127
+ elif [[ -f "$HOME/.claude/tts-auto-clean-threshold.txt" ]]; then
128
+ threshold_file="$HOME/.claude/tts-auto-clean-threshold.txt"
129
+ fi
130
+
131
+ if [[ -n "$threshold_file" ]]; then
132
+ local threshold=$(grep -v '^\s*#' "$threshold_file" 2>/dev/null | grep -v '^\s*$' | head -1)
133
+ if [[ "$threshold" =~ ^[0-9]+$ ]]; then
134
+ echo "$threshold"
135
+ return
136
+ fi
137
+ fi
138
+
139
+ # Default threshold
140
+ echo "50"
141
+ }
142
+
143
+ # Delete oldest TTS files to stay under size threshold (in MB)
144
+ # Args: $1 = audio_dir, $2 = threshold (size in MB)
145
+ # Returns: Number of files deleted
146
+ auto_clean_old_files() {
147
+ local audio_dir="${1:-$(get_audio_dir)}"
148
+ local threshold_mb="${2:-15}"
149
+ local threshold_bytes=$((threshold_mb * 1048576))
150
+
151
+ if [[ ! -d "$audio_dir" ]]; then
152
+ echo "0"
153
+ return
154
+ fi
155
+
156
+ local current_size=$(calculate_tts_size_bytes "$audio_dir")
157
+
158
+ if [[ $current_size -le $threshold_bytes ]]; then
159
+ echo "0"
160
+ return
161
+ fi
162
+
163
+ # SAFETY CHECK: Skip cleanup if any TTS files have active write locks
164
+ # Check for .lock files that indicate in-progress TTS generation
165
+ local lock_count=$(find "$audio_dir" -maxdepth 1 -name "tts-*.lock" -type f 2>/dev/null | wc -l)
166
+ if [[ $lock_count -gt 0 ]]; then
167
+ # Active TTS generation in progress, skip cleanup to avoid race condition
168
+ return 0
169
+ fi
170
+
171
+ local files_deleted=0
172
+ local current_size_bytes=$current_size
173
+
174
+ # Delete oldest files until under threshold
175
+ # IMPORTANT: Only delete auto-generated TTS files, NOT project assets like welcome-multivoice-final.wav
176
+ while [[ $current_size_bytes -gt $threshold_bytes ]]; do
177
+ # Find the oldest file (only tts-processed-* and tts-padded-* files, not other project assets)
178
+ local oldest_file=$(find "$audio_dir" -maxdepth 1 -type f \( \
179
+ -name "tts-processed-*.wav" -o \
180
+ -name "tts-processed-*.mp3" -o \
181
+ -name "tts-padded-*.mp3" -o \
182
+ -name "tts-padded-*.wav" \
183
+ \) -printf '%T+ %p\n' 2>/dev/null | sort | head -1 | cut -d' ' -f2-)
184
+
185
+ if [[ -z "$oldest_file" ]]; then
186
+ break
187
+ fi
188
+
189
+ # Get file size and delete it
190
+ local file_size=$(stat -c%s "$oldest_file" 2>/dev/null || stat -f%z "$oldest_file" 2>/dev/null || echo "0")
191
+ rm -f "$oldest_file" 2>/dev/null || true
192
+ current_size_bytes=$((current_size_bytes - file_size))
193
+ files_deleted=$((files_deleted + 1))
194
+ done
195
+
196
+ echo "$files_deleted"
197
+ }
198
+
199
+ # Clean all TTS audio files and report stats
200
+ # Args: $1 = audio_dir (optional, defaults to get_audio_dir)
201
+ # Returns: Formatted output with cleanup stats
202
+ clean_all_tts_files() {
203
+ local audio_dir="${1:-$(get_audio_dir)}"
204
+
205
+ # Color codes
206
+ local RED='\033[0;31m'
207
+ local GREEN='\033[0;32m'
208
+ local YELLOW='\033[1;33m'
209
+ local BLUE='\033[0;34m'
210
+ local NC='\033[0m' # No Color
211
+
212
+ # Get stats before cleanup
213
+ local count_before=$(count_tts_files "$audio_dir")
214
+ local size_before=$(calculate_tts_size_bytes "$audio_dir")
215
+ local human_before=$(bytes_to_human "$size_before")
216
+
217
+ if [[ $count_before -eq 0 ]]; then
218
+ echo -e "${GREEN}✅ Cache is already clean! No TTS files found.${NC}"
219
+ return
220
+ fi
221
+
222
+ # Delete auto-generated TTS files only (preserve project assets like welcome-multivoice-final.wav)
223
+ find "$audio_dir" -maxdepth 1 -type f \( \
224
+ -name "tts-processed-*.wav" -o \
225
+ -name "tts-processed-*.mp3" -o \
226
+ -name "tts-padded-*.mp3" -o \
227
+ -name "tts-padded-*.wav" \
228
+ \) -delete 2>/dev/null || true
229
+
230
+ # Also delete BMAD party mode recordings if they exist
231
+ if [[ -d "$audio_dir/bmad-party-mode-recordings" ]]; then
232
+ rm -rf "$audio_dir/bmad-party-mode-recordings" 2>/dev/null || true
233
+ fi
234
+
235
+ # Get stats after cleanup
236
+ local count_after=$(count_tts_files "$audio_dir")
237
+ local size_after=$(calculate_tts_size_bytes "$audio_dir")
238
+ local human_after=$(bytes_to_human "$size_after")
239
+ local freed=$((size_before - size_after))
240
+ local human_freed=$(bytes_to_human "$freed")
241
+
242
+ echo -e "${GREEN}✅ Cleanup complete!${NC}"
243
+ echo " • Files deleted: ${YELLOW}$count_before${NC}"
244
+ echo " • Space freed: ${YELLOW}$human_freed${NC}"
245
+ echo " • Before: $human_before | After: $human_after"
246
+ }