agentvibes 5.3.0 → 5.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/LITE-MODE.md +236 -0
  2. package/.agentvibes/README.md +136 -0
  3. package/.agentvibes/backup/session-start-tts.sh.20251210_212814 +141 -0
  4. package/.agentvibes/backups/agents/analyst_20260204_144958.md +78 -0
  5. package/.agentvibes/backups/agents/architect_20260204_144958.md +72 -0
  6. package/.agentvibes/backups/agents/dev_20260204_144958.md +74 -0
  7. package/.agentvibes/backups/agents/pm_20260204_144958.md +72 -0
  8. package/.agentvibes/backups/agents/quick-flow-solo-dev_20260204_144958.md +64 -0
  9. package/.agentvibes/backups/agents/sm_20260204_144958.md +87 -0
  10. package/.agentvibes/backups/agents/tea_20260204_144958.md +79 -0
  11. package/.agentvibes/backups/agents/tech-writer_20260204_144958.md +82 -0
  12. package/.agentvibes/backups/agents/ux-designer_20260204_144958.md +80 -0
  13. package/.agentvibes/bmad/bmad-voices.md +69 -69
  14. package/.agentvibes/config/README-personality-defaults.md +162 -0
  15. package/.agentvibes/config/mode.txt +1 -0
  16. package/.agentvibes/config/personality-voice-defaults.default.json +21 -0
  17. package/.agentvibes/config/save-audio.txt +1 -0
  18. package/.agentvibes/config/voice-metadata.json +160 -0
  19. package/.agentvibes/config.json +24 -15
  20. package/.agentvibes/hooks/help.sh +191 -0
  21. package/.agentvibes/hooks/post-tool-use-lite.sh +111 -0
  22. package/.agentvibes/hooks/save-audio-manager.sh +162 -0
  23. package/.agentvibes/hooks/session-start-full-optimized.sh +102 -0
  24. package/.agentvibes/hooks/session-start-full.sh +142 -0
  25. package/.agentvibes/hooks/session-start-lite-v2.sh +34 -0
  26. package/.agentvibes/hooks/session-start-lite.sh +29 -0
  27. package/.agentvibes/hooks/stop-lite.sh +115 -0
  28. package/.agentvibes/hooks/switch-mode.sh +215 -0
  29. package/.agentvibes/output-styles/audio-summary.md +30 -0
  30. package/.claude/activation-instructions +54 -54
  31. package/.claude/audio/voice-samples/piper/alan.wav +0 -0
  32. package/.claude/audio/voice-samples/piper/amy.wav +0 -0
  33. package/.claude/audio/voice-samples/piper/charlotte.wav +0 -0
  34. package/.claude/audio/voice-samples/piper/joe.wav +0 -0
  35. package/.claude/audio/voice-samples/piper/john.wav +0 -0
  36. package/.claude/audio/voice-samples/piper/katherine.wav +0 -0
  37. package/.claude/audio/voice-samples/piper/kristin.wav +0 -0
  38. package/.claude/audio/voice-samples/piper/linda.wav +0 -0
  39. package/.claude/audio/voice-samples/piper/marcus.wav +0 -0
  40. package/.claude/audio/voice-samples/piper/ryan.wav +0 -0
  41. package/.claude/commands/agent-vibes/add.md +21 -21
  42. package/.claude/commands/agent-vibes/agent-vibes.md +101 -101
  43. package/.claude/commands/agent-vibes/agent.md +79 -79
  44. package/.claude/commands/agent-vibes/background-music.md +111 -111
  45. package/.claude/commands/agent-vibes/bmad.md +198 -198
  46. package/.claude/commands/agent-vibes/clean.md +18 -18
  47. package/.claude/commands/agent-vibes/cleanup.md +18 -18
  48. package/.claude/commands/agent-vibes/commands.json +145 -145
  49. package/.claude/commands/agent-vibes/effects.md +97 -97
  50. package/.claude/commands/agent-vibes/get.md +9 -9
  51. package/.claude/commands/agent-vibes/hide.md +91 -91
  52. package/.claude/commands/agent-vibes/language.md +23 -23
  53. package/.claude/commands/agent-vibes/learn.md +67 -67
  54. package/.claude/commands/agent-vibes/list.md +13 -13
  55. package/.claude/commands/agent-vibes/mute.md +37 -37
  56. package/.claude/commands/agent-vibes/preview.md +17 -17
  57. package/.claude/commands/agent-vibes/provider.md +68 -68
  58. package/.claude/commands/agent-vibes/replay-target.md +14 -14
  59. package/.claude/commands/agent-vibes/sample.md +12 -12
  60. package/.claude/commands/agent-vibes/set-favorite-voice.md +84 -84
  61. package/.claude/commands/agent-vibes/set-pretext.md +65 -65
  62. package/.claude/commands/agent-vibes/set-speed.md +41 -41
  63. package/.claude/commands/agent-vibes/show.md +84 -84
  64. package/.claude/commands/agent-vibes/switch.md +87 -87
  65. package/.claude/commands/agent-vibes/target-voice.md +26 -26
  66. package/.claude/commands/agent-vibes/target.md +30 -30
  67. package/.claude/commands/agent-vibes/translate.md +68 -68
  68. package/.claude/commands/agent-vibes/unmute.md +45 -45
  69. package/.claude/commands/agent-vibes/whoami.md +7 -7
  70. package/.claude/commands/agent-vibes-bmad-voices.md +117 -117
  71. package/.claude/commands/agent-vibes-rdp.md +24 -24
  72. package/.claude/config/audio-effects.cfg +4 -11
  73. package/.claude/config/audio-effects.cfg.sample +52 -52
  74. package/.claude/config/background-music-position.txt +27 -0
  75. package/.claude/config/background-music-volume.txt +1 -1
  76. package/.claude/config/background-music.cfg +1 -0
  77. package/.claude/config/background-music.txt +1 -0
  78. package/.claude/config/tts-speech-rate.txt +1 -4
  79. package/.claude/config/tts-verbosity.txt +1 -0
  80. package/.claude/docs/TERMUX_SETUP.md +408 -408
  81. package/.claude/github-star-reminder.txt +1 -1
  82. package/.claude/hooks/README-TTS-QUEUE.md +135 -135
  83. package/.claude/hooks/audio-cache-utils.sh +0 -0
  84. package/.claude/hooks/audio-processor.sh +60 -14
  85. package/.claude/hooks/background-music-manager.sh +0 -0
  86. package/.claude/hooks/bmad-party-manager.sh +225 -0
  87. package/.claude/hooks/bmad-speak-enhanced.sh +0 -0
  88. package/.claude/hooks/bmad-speak.sh +6 -13
  89. package/.claude/hooks/bmad-tts-injector.sh +0 -0
  90. package/.claude/hooks/bmad-voice-manager.sh +0 -0
  91. package/.claude/hooks/clawdbot-receiver-SECURE.sh +25 -23
  92. package/.claude/hooks/clawdbot-receiver.sh +4 -28
  93. package/.claude/hooks/clean-audio-cache.sh +0 -0
  94. package/.claude/hooks/cleanup-cache.sh +0 -0
  95. package/.claude/hooks/configure-rdp-mode.sh +0 -0
  96. package/.claude/hooks/download-extra-voices.sh +0 -0
  97. package/.claude/hooks/effects-manager.sh +0 -0
  98. package/.claude/hooks/github-star-reminder.sh +0 -0
  99. package/.claude/hooks/language-manager.sh +0 -0
  100. package/.claude/hooks/learn-manager.sh +0 -0
  101. package/.claude/hooks/macos-voice-manager.sh +0 -0
  102. package/.claude/hooks/migrate-background-music.sh +0 -0
  103. package/.claude/hooks/migrate-to-agentvibes.sh +0 -0
  104. package/.claude/hooks/optimize-background-music.sh +0 -0
  105. package/.claude/hooks/personality-manager.sh +0 -0
  106. package/.claude/hooks/piper-download-voices.sh +0 -0
  107. package/.claude/hooks/piper-installer.sh +1 -1
  108. package/.claude/hooks/piper-multispeaker-registry.sh +0 -0
  109. package/.claude/hooks/piper-voice-manager.sh +0 -0
  110. package/.claude/hooks/play-tts-enhanced.sh +0 -0
  111. package/.claude/hooks/play-tts-macos.sh +6 -12
  112. package/.claude/hooks/play-tts-piper.sh +50 -79
  113. package/.claude/hooks/play-tts-soprano.sh +9 -43
  114. package/.claude/hooks/play-tts-ssh-remote.sh +43 -215
  115. package/.claude/hooks/play-tts-termux-ssh.sh +0 -0
  116. package/.claude/hooks/play-tts.sh +31 -31
  117. package/.claude/hooks/post-response.sh +41 -0
  118. package/.claude/hooks/prepare-release.sh +0 -0
  119. package/.claude/hooks/provider-commands.sh +0 -0
  120. package/.claude/hooks/provider-manager.sh +0 -0
  121. package/.claude/hooks/replay-target-audio.sh +0 -0
  122. package/.claude/hooks/requirements.txt +6 -6
  123. package/.claude/hooks/sentiment-manager.sh +0 -0
  124. package/.claude/hooks/session-start-tts.sh +56 -39
  125. package/.claude/hooks/soprano-gradio-synth.py +139 -139
  126. package/.claude/hooks/speed-manager.sh +0 -0
  127. package/.claude/hooks/stop.sh +63 -0
  128. package/.claude/hooks/termux-installer.sh +0 -0
  129. package/.claude/hooks/translate-manager.sh +0 -0
  130. package/.claude/hooks/translator.py +237 -237
  131. package/.claude/hooks/tts-queue-worker.sh +0 -0
  132. package/.claude/hooks/tts-queue.sh +0 -0
  133. package/.claude/hooks/verbosity-manager.sh +0 -0
  134. package/.claude/hooks/voice-manager.sh +26 -4
  135. package/.claude/hooks-windows/audio-cache-utils.ps1 +119 -119
  136. package/.claude/hooks-windows/bmad-party-speak.ps1 +278 -278
  137. package/.claude/hooks-windows/bmad-speak.ps1 +264 -264
  138. package/.claude/hooks-windows/clean-audio-cache.ps1 +53 -53
  139. package/.claude/hooks-windows/effects-manager.ps1 +294 -294
  140. package/.claude/hooks-windows/language-manager.ps1 +193 -193
  141. package/.claude/hooks-windows/learn-manager.ps1 +241 -241
  142. package/.claude/hooks-windows/personality-manager.ps1 +266 -266
  143. package/.claude/hooks-windows/play-tts-soprano.ps1 +5 -5
  144. package/.claude/hooks-windows/play-tts-termux-ssh.ps1 +138 -138
  145. package/.claude/hooks-windows/play-tts-windows-piper.ps1 +164 -0
  146. package/.claude/hooks-windows/play-tts-windows-sapi.ps1 +108 -0
  147. package/.claude/hooks-windows/play-tts.ps1 +104 -513
  148. package/.claude/hooks-windows/provider-manager.ps1 +158 -192
  149. package/.claude/hooks-windows/session-start-tts.ps1 +55 -46
  150. package/.claude/hooks-windows/soprano-gradio-synth.py +153 -153
  151. package/.claude/hooks-windows/speed-manager.ps1 +166 -166
  152. package/.claude/hooks-windows/voice-manager-windows.ps1 +176 -260
  153. package/.claude/output-styles/agent-vibes.md +202 -202
  154. package/.claude/personalities/angry.md +14 -14
  155. package/.claude/personalities/annoying.md +14 -14
  156. package/.claude/personalities/crass.md +14 -14
  157. package/.claude/personalities/dramatic.md +14 -14
  158. package/.claude/personalities/dry-humor.md +50 -50
  159. package/.claude/personalities/flirty.md +20 -20
  160. package/.claude/personalities/funny.md +14 -14
  161. package/.claude/personalities/grandpa.md +32 -32
  162. package/.claude/personalities/millennial.md +14 -14
  163. package/.claude/personalities/moody.md +14 -14
  164. package/.claude/personalities/normal.md +16 -16
  165. package/.claude/personalities/pirate.md +14 -14
  166. package/.claude/personalities/poetic.md +14 -14
  167. package/.claude/personalities/professional.md +14 -14
  168. package/.claude/personalities/rapper.md +55 -55
  169. package/.claude/personalities/robot.md +14 -14
  170. package/.claude/personalities/sarcastic.md +38 -38
  171. package/.claude/personalities/sassy.md +14 -14
  172. package/.claude/personalities/surfer-dude.md +14 -14
  173. package/.claude/personalities/zen.md +14 -14
  174. package/.claude/piper-voices-dir.txt +1 -0
  175. package/.claude/settings.json +25 -15
  176. package/.claude/verbosity.txt +1 -1
  177. package/.clawdbot/README.md +105 -105
  178. package/.clawdbot/skill/SKILL.md +149 -145
  179. package/.mcp.json +30 -11
  180. package/CLAUDE.md +170 -215
  181. package/README.md +206 -525
  182. package/RELEASE_NOTES.md +1132 -1976
  183. package/WINDOWS-SETUP.md +208 -208
  184. package/bin/agent-vibes +0 -0
  185. package/bin/agentvibes-voice-browser.js +64 -1289
  186. package/bin/agentvibes.js +0 -0
  187. package/bin/ensure-soprano-running.sh +43 -0
  188. package/bin/mcp-server.js +121 -121
  189. package/bin/mcp-server.sh +0 -0
  190. package/bin/test-bmad-pr +78 -78
  191. package/mcp-server/QUICK_START.md +203 -203
  192. package/mcp-server/README.md +345 -345
  193. package/mcp-server/WINDOWS_SETUP.md +260 -260
  194. package/mcp-server/docs/troubleshooting-audio.md +313 -313
  195. package/mcp-server/examples/claude_desktop_config.json +11 -11
  196. package/mcp-server/examples/claude_desktop_config_piper.json +9 -9
  197. package/mcp-server/examples/custom_instructions.md +169 -169
  198. package/mcp-server/install-deps.js +130 -130
  199. package/mcp-server/pyproject.toml +52 -52
  200. package/mcp-server/requirements.txt +2 -2
  201. package/mcp-server/server.py +1451 -1578
  202. package/mcp-server/test_server.py +395 -395
  203. package/package.json +1 -3
  204. package/setup-windows.ps1 +815 -815
  205. package/src/installer.js +42 -5
  206. package/templates/agentvibes-receiver.sh +158 -483
  207. package/templates/audio/welcome-music.mp3 +0 -0
  208. package/.agentvibes/bmad-voice-map.json +0 -104
  209. package/.agentvibes/copilot-sessions.log +0 -4
  210. package/.claude/config/audio-effects-bmad.cfg +0 -50
  211. package/.claude/config/background-music-enabled.txt +0 -1
  212. package/.claude/config/intro-text.txt +0 -1
  213. package/.claude/config/personality.txt +0 -1
  214. package/.claude/config/piper-speech-rate.txt +0 -4
  215. package/.claude/config/piper-target-speech-rate.txt +0 -1
  216. package/.claude/config/reverb-level.txt +0 -1
  217. package/.claude/config/tts-target-speech-rate.txt +0 -1
  218. package/voice-assignments.json +0 -8245
  219. /package/{.claude → .agentvibes}/config/agentvibes.json +0 -0
@@ -2,11 +2,8 @@
2
2
  #
3
3
  # File: .claude/hooks/play-tts-ssh-remote.sh
4
4
  #
5
- # AgentVibes - SSH-Remote TTS Provider (v2 — JSON payload)
6
- # Sends text + effects config to remote device via SSH for local playback
7
- #
8
- # The sender reads local audio-effects.cfg and bundles everything into a
9
- # single base64-encoded JSON payload. The receiver is a thin executor.
5
+ # AgentVibes - SSH-Remote TTS Provider
6
+ # Sends text to remote device via SSH for local AgentVibes playback
10
7
  #
11
8
  # Copyright (c) 2025 Paul Preibisch
12
9
  # Licensed under the Apache License, Version 2.0
@@ -14,249 +11,80 @@
14
11
 
15
12
  set -euo pipefail
16
13
 
17
- # ---------------------------------------------------------------------------
18
- # Argument parsing — supports both positional (backward compat) and flags.
19
- #
20
- # Positional (legacy):
21
- # play-tts-ssh-remote.sh "text" [voice] [agent_name]
22
- #
23
- # Flag-based (full per-call control):
24
- # play-tts-ssh-remote.sh --text "hello" --voice "en_US-ryan-high" \
25
- # --pretext "Winston here" --music "track.mp3" \
26
- # --volume 0.25 --effects "reverb 40 60 80" \
27
- # --speed 1.1 --provider piper --agent "winston"
28
- #
29
- # Flags override config-file values. Any flag omitted → falls back to config.
30
- # --pretext "" (empty string) explicitly suppresses pretext (no fallback).
31
- # ---------------------------------------------------------------------------
32
-
33
- TEXT=""
34
- VOICE=""
35
- AGENT_NAME=""
36
- PRETEXT_OVERRIDE=""
37
- PRETEXT_SET=0 # whether --pretext was explicitly provided
38
- MUSIC_OVERRIDE=""
39
- VOLUME_OVERRIDE=""
40
- EFFECTS_OVERRIDE=""
41
- SPEED_OVERRIDE=""
42
- PROVIDER_OVERRIDE=""
43
-
44
- # Detect flag-based vs positional usage: if first arg starts with --, use flags.
45
- if [[ "${1:-}" == --* ]]; then
46
- while [[ $# -gt 0 ]]; do
47
- case "$1" in
48
- --text) TEXT="${2:-}"; shift 2 ;;
49
- --voice) VOICE="${2:-}"; shift 2 ;;
50
- --agent) AGENT_NAME="${2:-}"; shift 2 ;;
51
- --pretext) PRETEXT_OVERRIDE="${2:-}"; PRETEXT_SET=1; shift 2 ;;
52
- --music) MUSIC_OVERRIDE="${2:-}"; shift 2 ;;
53
- --volume) VOLUME_OVERRIDE="${2:-}"; shift 2 ;;
54
- --effects) EFFECTS_OVERRIDE="${2:-}"; shift 2 ;;
55
- --speed) SPEED_OVERRIDE="${2:-}"; shift 2 ;;
56
- --provider) PROVIDER_OVERRIDE="${2:-}"; shift 2 ;;
57
- *) echo "Unknown flag: $1" >&2; exit 1 ;;
58
- esac
59
- done
60
- else
61
- TEXT="${1:-}"
62
- VOICE="${2:-}"
63
- AGENT_NAME="${3:-}"
64
- fi
65
-
66
- # Defaults for still-empty values
67
- VOICE="${VOICE:-en_US-lessac-medium}"
68
- AGENT_NAME="${AGENT_NAME:-default}"
14
+ TEXT="${1:-}"
15
+ VOICE="${2:-en_US-lessac-medium}"
16
+ AGENT_NAME="${3:-default}"
69
17
 
70
18
  # Validate required input
71
19
  if [[ -z "$TEXT" ]]; then
72
- echo "Usage (positional): $0 <text> [voice] [agent_name]" >&2
73
- echo "Usage (flags): $0 --text <text> [--voice X --pretext Y --music Z --volume N --effects E --speed S --provider P --agent A]" >&2
20
+ echo " No text provided" >&2
21
+ echo "Usage: $0 <text> [voice] [agent_name]" >&2
74
22
  exit 1
75
23
  fi
76
24
 
77
- # Get script directory and project root
25
+ # Get script directory
78
26
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
79
27
  PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
80
28
 
81
- # Derive project name from directory
82
- PROJECT_NAME=$(basename "$PROJECT_ROOT")
83
-
84
- # ---------------------------------------------------------------------------
85
29
  # Get SSH host from config
86
- # ---------------------------------------------------------------------------
87
-
88
30
  SSH_HOST=$(cat "$PROJECT_ROOT/.claude/ssh-remote-host.txt" 2>/dev/null || \
89
31
  cat "$HOME/.claude/ssh-remote-host.txt" 2>/dev/null || echo "")
90
32
 
91
33
  if [[ -z "$SSH_HOST" ]]; then
92
- echo "SSH-Remote host not configured" >&2
93
- echo "Set host: echo 'my-host' > .claude/ssh-remote-host.txt" >&2
34
+ echo "SSH-Remote host not configured" >&2
35
+ echo "💡 Set host: echo 'android' > ~/.claude/ssh-remote-host.txt" >&2
94
36
  exit 1
95
37
  fi
96
38
 
97
- # SECURITY: Validate SSH_HOST format
39
+ # SECURITY: Validate SSH_HOST to prevent option injection
40
+ # Must be a valid hostname, IP address, or SSH config alias (alphanumeric, dots, hyphens, underscores)
98
41
  if [[ ! "$SSH_HOST" =~ ^[a-zA-Z0-9][a-zA-Z0-9._-]*$ ]]; then
99
- echo "Invalid SSH host format: $SSH_HOST" >&2
42
+ echo "Invalid SSH host format: $SSH_HOST" >&2
43
+ echo "💡 Host must be alphanumeric (may contain dots, hyphens, underscores)" >&2
100
44
  exit 1
101
45
  fi
102
46
 
103
- # SECURITY: Validate VOICE (allow :: for multi-speaker, . for locale, space for names)
104
- _voice_re='^[a-zA-Z0-9_.: -]+$'
105
- if [[ ! "$VOICE" =~ $_voice_re ]]; then
106
- echo "Invalid voice format: $VOICE" >&2
47
+ # SECURITY: Reject hosts starting with hyphen (SSH option injection)
48
+ if [[ "$SSH_HOST" == -* ]]; then
49
+ echo "❌ Invalid SSH host: cannot start with hyphen" >&2
107
50
  exit 1
108
51
  fi
109
52
 
110
- # SECURITY: Validate AGENT_NAME
111
- if [[ ! "$AGENT_NAME" =~ ^[a-zA-Z0-9_\ -]+$ ]]; then
112
- echo "Invalid agent name format: $AGENT_NAME" >&2
53
+ # SECURITY: Validate VOICE to prevent injection (alphanumeric, hyphens, underscores only)
54
+ if [[ ! "$VOICE" =~ ^[a-zA-Z0-9_-]+$ ]]; then
55
+ echo "Invalid voice format: $VOICE" >&2
113
56
  exit 1
114
57
  fi
115
58
 
116
- # ---------------------------------------------------------------------------
117
- # Read audio effects config for this agent
118
- # ---------------------------------------------------------------------------
119
-
120
- SOX_EFFECTS=""
121
- BG_FILE=""
122
- BG_VOLUME="0.10"
123
-
124
- EFFECTS_CFG="$PROJECT_ROOT/.claude/config/audio-effects.cfg"
125
- if [[ -f "$EFFECTS_CFG" ]]; then
126
- CONFIG_LINE=$(grep "^${AGENT_NAME}|" "$EFFECTS_CFG" 2>/dev/null || \
127
- grep "^default|" "$EFFECTS_CFG" 2>/dev/null || true)
128
- if [[ -n "$CONFIG_LINE" ]]; then
129
- IFS='|' read -r _ SOX_EFFECTS BG_FILE BG_VOLUME <<< "$CONFIG_LINE"
130
- fi
131
- fi
132
-
133
- # Read pretext if configured
134
- PRETEXT=""
135
- PRETEXT_FILE="$PROJECT_ROOT/.agentvibes/config/pretext.txt"
136
- if [[ -f "$PRETEXT_FILE" ]]; then
137
- PRETEXT=$(cat "$PRETEXT_FILE" 2>/dev/null || true)
138
- fi
139
-
140
- # Read speed if configured
141
- SPEED=""
142
- SPEED_FILE="$PROJECT_ROOT/.agentvibes/config/speed.txt"
143
- if [[ -f "$SPEED_FILE" ]]; then
144
- SPEED=$(cat "$SPEED_FILE" 2>/dev/null || true)
145
- fi
146
-
147
- # Read the TTS provider the RECEIVER should use to generate audio.
148
- # This is separate from the sender's own provider (which is "ssh-remote").
149
- # Check receiver-provider.txt first, then fall back to "piper".
150
- PROVIDER=""
151
- RECEIVER_PROVIDER_FILE="$PROJECT_ROOT/.agentvibes/config/receiver-provider.txt"
152
- if [[ -f "$RECEIVER_PROVIDER_FILE" ]]; then
153
- PROVIDER=$(cat "$RECEIVER_PROVIDER_FILE" 2>/dev/null || true)
154
- fi
155
- # Also check home-level config
156
- if [[ -z "$PROVIDER" ]]; then
157
- RECEIVER_PROVIDER_FILE="$HOME/.agentvibes/config/receiver-provider.txt"
158
- if [[ -f "$RECEIVER_PROVIDER_FILE" ]]; then
159
- PROVIDER=$(cat "$RECEIVER_PROVIDER_FILE" 2>/dev/null || true)
160
- fi
161
- fi
162
- # Validate — only known TTS providers (not transport providers like ssh-remote)
163
- case "${PROVIDER:-}" in
164
- piper|soprano|macos|windows-sapi) ;;
165
- *) PROVIDER="piper" ;;
166
- esac
167
-
168
- # ---------------------------------------------------------------------------
169
- # Apply CLI flag overrides (flags win over config files)
170
- # ---------------------------------------------------------------------------
171
- # Validate effects (prevent injection — only alphanumeric, spaces, dots, hyphens)
172
- if [[ -n "$EFFECTS_OVERRIDE" ]]; then
173
- if [[ "$EFFECTS_OVERRIDE" =~ ^[a-zA-Z0-9\ ._-]+$ ]]; then
174
- SOX_EFFECTS="$EFFECTS_OVERRIDE"
175
- else
176
- echo "Invalid effects format: $EFFECTS_OVERRIDE (alphanumeric/space/.-_ only)" >&2
177
- exit 1
178
- fi
179
- fi
180
- [[ -n "$MUSIC_OVERRIDE" ]] && BG_FILE="$MUSIC_OVERRIDE"
181
- [[ -n "$VOLUME_OVERRIDE" ]] && BG_VOLUME="$VOLUME_OVERRIDE"
182
- [[ -n "$SPEED_OVERRIDE" ]] && SPEED="$SPEED_OVERRIDE"
183
- [[ -n "$PROVIDER_OVERRIDE" ]] && PROVIDER="$PROVIDER_OVERRIDE"
184
- # Pretext: explicit --pretext wins even when empty string (suppresses pretext)
185
- if [[ "$PRETEXT_SET" == "1" ]]; then
186
- PRETEXT="$PRETEXT_OVERRIDE"
187
- fi
188
-
189
- # Re-validate provider after override (in case user passed bad value)
190
- case "${PROVIDER:-}" in
191
- piper|soprano|macos|windows-sapi) ;;
192
- *) PROVIDER="piper" ;;
193
- esac
194
- # Validate music filename (prevent path injection through JSON → receiver)
195
- # Allows spaces in track names like "Late Night Hip Hop Groove.mp3"
196
- if [[ -n "$BG_FILE" && ! "$BG_FILE" =~ ^[a-zA-Z0-9_\.\ -]+$ ]]; then
197
- echo "Invalid music filename format: $BG_FILE (alphanumeric/space/.-_ only)" >&2
198
- exit 1
199
- fi
200
- # Validate volume
201
- if [[ -n "$BG_VOLUME" && ! "$BG_VOLUME" =~ ^[0-9]+(\.[0-9]+)?$ ]]; then
202
- echo "Invalid volume: $BG_VOLUME (numeric only)" >&2
203
- exit 1
204
- fi
205
- # Validate speed
206
- if [[ -n "$SPEED" && ! "$SPEED" =~ ^[0-9]+(\.[0-9]+)?$ ]]; then
207
- echo "Invalid speed: $SPEED (numeric only)" >&2
59
+ # SECURITY: Validate AGENT_NAME to prevent injection (alphanumeric, hyphens, underscores, spaces only)
60
+ if [[ ! "$AGENT_NAME" =~ ^[a-zA-Z0-9_\ -]+$ ]]; then
61
+ echo "❌ Invalid agent name format: $AGENT_NAME" >&2
208
62
  exit 1
209
63
  fi
210
64
 
211
- # ---------------------------------------------------------------------------
212
- # Build JSON payload
213
- # ---------------------------------------------------------------------------
214
-
215
- # SECURITY: Use jq if available for safe JSON construction, else manual escaping
216
- build_json_payload() {
217
- if command -v jq &>/dev/null; then
218
- jq -n \
219
- --arg text "$TEXT" \
220
- --arg voice "$VOICE" \
221
- --arg effects "$SOX_EFFECTS" \
222
- --arg music "$BG_FILE" \
223
- --arg volume "$BG_VOLUME" \
224
- --arg project "$PROJECT_NAME" \
225
- --arg pretext "$PRETEXT" \
226
- --arg speed "$SPEED" \
227
- --arg provider "$PROVIDER" \
228
- '{text: $text, voice: $voice, effects: $effects, music: $music, volume: $volume, project: $project, pretext: $pretext, speed: $speed, provider: $provider}'
229
- else
230
- # Manual JSON — escape all interpolated fields (backslash, double-quote, newline, tab)
231
- _esc() { printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g; s/\t/\\t/g' | tr '\n' ' '; }
232
- local e_text e_voice e_effects e_music e_vol e_proj e_pre e_spd e_prov
233
- e_text=$(_esc "$TEXT"); e_voice=$(_esc "$VOICE"); e_effects=$(_esc "$SOX_EFFECTS")
234
- e_music=$(_esc "$BG_FILE"); e_vol=$(_esc "$BG_VOLUME"); e_proj=$(_esc "$PROJECT_NAME")
235
- e_pre=$(_esc "$PRETEXT"); e_spd=$(_esc "$SPEED"); e_prov=$(_esc "$PROVIDER")
236
- printf '{"text":"%s","voice":"%s","effects":"%s","music":"%s","volume":"%s","project":"%s","pretext":"%s","speed":"%s","provider":"%s"}' \
237
- "$e_text" "$e_voice" "$e_effects" "$e_music" "$e_vol" "$e_proj" "$e_pre" "$e_spd" "$e_prov"
238
- fi
239
- }
65
+ # SECURITY: Encode text and agent name as base64 to prevent command injection
66
+ # The receiver will decode these safely
67
+ ENCODED_TEXT=$(printf '%s' "$TEXT" | base64 -w 0)
68
+ ENCODED_AGENT=$(printf '%s' "$AGENT_NAME" | base64 -w 0)
240
69
 
241
- JSON_PAYLOAD=$(build_json_payload)
70
+ # Send text to remote for local AgentVibes playback
71
+ echo "📱 Sending to $SSH_HOST for local playback..." >&2
242
72
 
243
- # SECURITY: Base64-encode entire payload safe for SSH transport
244
- # base64 -w 0 is Linux (GNU coreutils), -b 0 is macOS (BSD)
245
- if base64 --help 2>&1 | grep -q '\-w'; then
246
- ENCODED_PAYLOAD=$(printf '%s' "$JSON_PAYLOAD" | base64 -w 0)
73
+ # Determine which receiver script exists and send encoded text, voice, and agent name
74
+ # SECURITY: Base64-encoded values are safe to pass as arguments (no shell metacharacters)
75
+ # The receiver auto-detects and decodes base64 input
76
+ if ssh "$SSH_HOST" "test -f ~/.termux/agentvibes-play.sh" 2>/dev/null; then
77
+ ssh "$SSH_HOST" "bash ~/.termux/agentvibes-play.sh '$ENCODED_TEXT' '$VOICE' '$ENCODED_AGENT'" &
78
+ SSH_PID=$!
79
+ elif ssh "$SSH_HOST" "test -f ~/.agentvibes/play-remote.sh" 2>/dev/null; then
80
+ ssh "$SSH_HOST" "bash ~/.agentvibes/play-remote.sh '$ENCODED_TEXT' '$VOICE' '$ENCODED_AGENT'" &
81
+ SSH_PID=$!
247
82
  else
248
- ENCODED_PAYLOAD=$(printf '%s' "$JSON_PAYLOAD" | base64 -b 0 2>/dev/null || printf '%s' "$JSON_PAYLOAD" | base64 | tr -d '\n')
83
+ echo "⚠️ Receiver script not found on $SSH_HOST" >&2
84
+ echo "💡 Install: agentvibes install --ssh-receiver" >&2
85
+ exit 1
249
86
  fi
250
87
 
251
- # ---------------------------------------------------------------------------
252
- # Send to receiver via SSH (fire and forget backgrounded)
253
- # ---------------------------------------------------------------------------
254
-
255
- echo "Sending to $SSH_HOST..." >&2
256
-
257
- # ForceCommand receiver: SSH_ORIGINAL_COMMAND passes the payload directly
258
- ssh "$SSH_HOST" "$ENCODED_PAYLOAD" &
259
- SSH_PID=$!
260
-
261
- echo "Sent to $SSH_HOST (PID: $SSH_PID)" >&2
88
+ # Log the background PID for debugging (non-blocking)
89
+ echo "✓ Sent to $SSH_HOST (PID: $SSH_PID, playing remotely)" >&2
262
90
  exit 0
File without changes
@@ -39,15 +39,41 @@
39
39
  # @patterns Provider pattern - delegates to provider-specific implementations, auto-detects provider from voice name
40
40
  # @related provider-manager.sh, play-tts-piper.sh, learn-manager.sh, translate-manager.sh
41
41
  #
42
+ # **CRITICAL: This script MUST ALWAYS be called with `run_in_background: true` in Bash tool**
43
+ # Do NOT wait for TTS playback to complete. Run in background so other tasks continue immediately.
44
+ # Example: Bash (background): .claude/hooks/play-tts.sh "Acknowledging task start"
45
+ #
46
+
47
+ set -euo pipefail
42
48
 
43
49
  set -euo pipefail
44
50
 
45
51
  # Fix locale warnings
46
52
  export LC_ALL=C
47
53
 
48
- # Get script directory (needed for mute file check)
49
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
50
- PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
54
+ # Get script directory - handle symlinks correctly with readlink -f
55
+ # This resolves: symlinks, relative paths, and working directory changes
56
+ SCRIPT_PATH="$(readlink -f "${BASH_SOURCE[0]}")"
57
+ SCRIPT_DIR="$(dirname "$SCRIPT_PATH")"
58
+
59
+ # Find PROJECT_ROOT by searching up the directory tree for .claude/hooks
60
+ # This handles non-standard installations and directory structures
61
+ PROJECT_ROOT="$SCRIPT_DIR"
62
+ while [[ "$PROJECT_ROOT" != "/" ]]; do
63
+ if [[ -d "$PROJECT_ROOT/.claude/hooks" ]]; then
64
+ break # PROJECT_ROOT is already the project root when its .claude/hooks child exists
65
+ fi
66
+ PROJECT_ROOT="$(dirname "$PROJECT_ROOT")"
67
+ done
68
+
69
+ # Verify PROJECT_ROOT is valid
70
+ if [[ ! -d "$PROJECT_ROOT/.claude/hooks" ]]; then
71
+ echo "❌ ERROR: Could not find AgentVibes .claude/hooks directory" >&2
72
+ echo " Script path: $SCRIPT_PATH" >&2
73
+ echo " Searched up from: $SCRIPT_DIR" >&2
74
+ exit 1
75
+ fi
76
+
51
77
  export PROJECT_ROOT # Export for child scripts
52
78
 
53
79
  # Check if muted (persists across sessions)
@@ -77,34 +103,8 @@ elif [[ -f "$GLOBAL_MUTE_FILE" ]]; then
77
103
  exit 0
78
104
  fi
79
105
 
80
- # Parse arguments: positional + optional --llm <provider>
81
- TEXT=""
82
- VOICE_OVERRIDE=""
83
- AGENT_PROFILE_FILE=""
84
- LLM_PROVIDER=""
85
-
86
- _positional=()
87
- while [[ $# -gt 0 ]]; do
88
- case "$1" in
89
- --llm)
90
- LLM_PROVIDER="${2:-}"
91
- # Security: Validate LLM provider name (alphanumeric, hyphens, underscores only)
92
- if [[ -n "$LLM_PROVIDER" ]] && [[ ! "$LLM_PROVIDER" =~ ^[a-zA-Z0-9][a-zA-Z0-9_-]*$ ]]; then
93
- echo "Error: Invalid LLM provider name" >&2
94
- exit 1
95
- fi
96
- shift 2
97
- ;;
98
- *)
99
- _positional+=("$1")
100
- shift
101
- ;;
102
- esac
103
- done
104
-
105
- TEXT="${_positional[0]:-}"
106
- VOICE_OVERRIDE="${_positional[1]:-}"
107
- AGENT_PROFILE_FILE="${_positional[2]:-}"
106
+ TEXT="${1:-}"
107
+ VOICE_OVERRIDE="${2:-}" # Optional: voice name or ID
108
108
 
109
109
  # Security: Validate inputs
110
110
  if [[ -z "$TEXT" ]]; then
@@ -0,0 +1,41 @@
1
+ #!/bin/bash
2
+ # AgentVibes TTS Hook - Triggers on assistant responses
3
+ # This hook is called after Claude generates a response
4
+
5
+ set -euo pipefail
6
+
7
+ # Get the hooks directory
8
+ HOOKS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
9
+ PROJECT_ROOT="$(dirname "$(dirname "$HOOKS_DIR")")"
10
+
11
+ # Check if AgentVibes is muted for this project
12
+ if [[ -f "$PROJECT_ROOT/.claude/agentvibes-muted" ]]; then
13
+ exit 0 # Silently skip TTS
14
+ fi
15
+
16
+ # Check if unmuted flag exists (overrides global mute)
17
+ if [[ ! -f "$PROJECT_ROOT/.claude/agentvibes-unmuted" ]]; then
18
+ # Check global mute
19
+ if [[ -f "$HOME/.agentvibes-muted" ]]; then
20
+ exit 0 # Silently skip TTS
21
+ fi
22
+ fi
23
+
24
+ # Get the assistant's response text from stdin or arguments
25
+ RESPONSE_TEXT="${1:-}"
26
+ if [[ -z "$RESPONSE_TEXT" ]]; then
27
+ # Try reading from stdin if available
28
+ if [[ -p /dev/stdin ]]; then
29
+ RESPONSE_TEXT=$(cat)
30
+ fi
31
+ fi
32
+
33
+ # Skip if no text
34
+ if [[ -z "$RESPONSE_TEXT" ]]; then
35
+ exit 0
36
+ fi
37
+
38
+ # Play TTS using the main play-tts script
39
+ "$HOOKS_DIR/play-tts.sh" "$RESPONSE_TEXT" &
40
+
41
+ exit 0
File without changes
File without changes
File without changes
File without changes
@@ -1,6 +1,6 @@
1
- # AgentVibes TTS Hooks Requirements
2
- # Install with: pip install -r requirements.txt
3
-
4
- # Translation support for multi-language TTS and learning mode
5
- deep-translator>=1.11.4
6
- langdetect>=1.0.9
1
+ # AgentVibes TTS Hooks Requirements
2
+ # Install with: pip install -r requirements.txt
3
+
4
+ # Translation support for multi-language TTS and learning mode
5
+ deep-translator>=1.11.4
6
+ langdetect>=1.0.9
File without changes
@@ -4,7 +4,7 @@ set -euo pipefail
4
4
  # File: .claude/hooks/session-start-tts.sh
5
5
  #
6
6
  # AgentVibes SessionStart Hook - Optimized (Issue #80, Phase 1)
7
- # Outputs JSON with additionalContext for reliable context injection
7
+ # Token target: ~250 (down from ~500)
8
8
  #
9
9
 
10
10
  # Fix locale warnings
@@ -33,52 +33,69 @@ fi
33
33
  # Get verbosity level (Issue #32)
34
34
  VERBOSITY=$(cat .claude/tts-verbosity.txt 2>/dev/null || cat ~/.claude/tts-verbosity.txt 2>/dev/null || echo "low")
35
35
 
36
- # Build context string
37
- CONTEXT="# AgentVibes TTS Protocol\n\n"
38
- CONTEXT+="**CRITICAL: You MUST execute TTS at TWO points for EVERY user interaction:**\n\n"
39
- CONTEXT+="1. **Acknowledgment** - Start of task: \`Bash: .claude/hooks/play-tts.sh \"[action]\" --llm claude-code\`\n"
40
- CONTEXT+="2. **Completion** - End of task: \`Bash: .claude/hooks/play-tts.sh \"[result + key details]\" --llm claude-code\`\n\n"
41
- CONTEXT+="**Example:**\n\`\`\`\n[Bash: .claude/hooks/play-tts.sh \"Checking git status\" --llm claude-code]\n[work...]\n"
42
- CONTEXT+="[Bash: .claude/hooks/play-tts.sh \"Repository is clean, no changes\" --llm claude-code]\n\`\`\`\n\n"
36
+ # Output optimized TTS protocol
37
+ cat <<'EOF'
43
38
 
44
- # Add verbosity-specific protocol
39
+ # AgentVibes TTS Protocol
40
+
41
+ **CRITICAL: You MUST execute TTS at TWO points for EVERY user interaction:**
42
+
43
+ 1. **Acknowledgment** - Start of task: `Bash: .claude/hooks/play-tts.sh "[action]"`
44
+ 2. **Completion** - End of task: `Bash: .claude/hooks/play-tts.sh "[result + key details]"`
45
+
46
+ **IMPORTANT: ALWAYS run TTS commands with `run_in_background: true` so they never block your work. Never wait for TTS to finish before continuing.**
47
+
48
+ **Example:**
49
+ ```
50
+ [Bash (background): .claude/hooks/play-tts.sh "Checking git status"]
51
+ [work...]
52
+ [Bash (background): .claude/hooks/play-tts.sh "Repository is clean, no changes"]
53
+ ```
54
+
55
+ EOF
56
+
57
+ # Add verbosity-specific protocol (Issue #32)
45
58
  case "$VERBOSITY" in
46
59
  low)
47
- CONTEXT+="## Verbosity: LOW\n- Acknowledgment: Action only\n- Completion: Result + errors only\n- Skip: Reasoning, decisions\n\n"
60
+ cat <<'EOF'
61
+ ## Verbosity: LOW
62
+ - Acknowledgment: Action only
63
+ - Completion: Result + errors only
64
+ - Skip: Reasoning, decisions
65
+
66
+ EOF
48
67
  ;;
49
68
  medium)
50
- CONTEXT+="## Verbosity: MEDIUM\n- Acknowledgment: Action + key approach\n- Completion: Result + important decisions\n- Include: Major choices only\n\n"
69
+ cat <<'EOF'
70
+ ## Verbosity: MEDIUM
71
+ - Acknowledgment: Action + key approach
72
+ - Completion: Result + important decisions
73
+ - Include: Major choices only
74
+
75
+ EOF
51
76
  ;;
52
77
  high)
53
- CONTEXT+="## Verbosity: HIGH\n- Acknowledgment: Action + approach + why\n- Completion: Result + decisions + trade-offs\n- Include: Full reasoning, alternatives\n\n"
54
- ;;
55
- caveman)
56
- CONTEXT+="## Verbosity: CAVEMAN\n- Respond terse. All technical substance stays. Only fluff dies.\n- Drop: articles (a/an/the), filler (just/really/basically), pleasantries, hedging\n- Abbreviate: DB/auth/config/req/res/fn/impl. Use arrows (X -> Y). Strip conjunctions.\n- Fragments OK. Short synonyms. Technical terms exact. Code unchanged.\n- Pattern: [thing] [action] [reason]. [next step].\n- TTS: Ultra-short. Max 60 chars.\n\n"
78
+ cat <<'EOF'
79
+ ## Verbosity: HIGH
80
+ - Acknowledgment: Action + approach + why
81
+ - Completion: Result + decisions + trade-offs
82
+ - Include: Full reasoning, alternatives
83
+
84
+ EOF
57
85
  ;;
58
86
  esac
59
87
 
60
88
  # Add style info and rules
61
- CONTEXT+="## Style: $STYLE\n\n"
62
- CONTEXT+="## Rules\n"
63
- CONTEXT+="1. Never skip acknowledgment TTS\n"
64
- CONTEXT+="2. Never skip completion TTS\n"
65
- CONTEXT+="3. Match verbosity level\n"
66
- CONTEXT+="4. Keep under 150 chars\n"
67
- CONTEXT+="5. Always include errors\n\n"
68
- CONTEXT+="Quick Ref: low=action+result | medium=+key decisions | high=+full reasoning | caveman=ultra-terse fragments"
69
-
70
- # Add BMAD agent voice routing instructions
71
- CONTEXT+="\n\n## BMAD Agent Voice Routing\n"
72
- CONTEXT+="If \`.bmad-agent-context\` exists, check its content:\n\n"
73
- CONTEXT+="**Single agent mode** (content is an agent ID like \"analyst\"):\n"
74
- CONTEXT+="Use \`bmad-speak.sh\` instead of \`play-tts.sh\`:\n\n\n"
75
- CONTEXT+="**Party mode** (content is \"party-mode\"):\n"
76
- CONTEXT+="Each agent speaks via \`bmad-speak.sh\` with their display name. The queue system ensures sequential playback — agents speak one at a time, not overlapping:\n\n"
77
- CONTEXT+="IMPORTANT: In party mode, do NOT use \`play-tts.sh\`. Always use \`bmad-speak.sh\` with the agent's display name. Do NOT call multiple bmad-speak.sh in parallel — call them sequentially so the queue processes them in order.\n\n"
78
- CONTEXT+="If \`.bmad-agent-context\` does NOT exist, use \`play-tts.sh\` as normal."
79
-
80
- # Escape for JSON (handle newlines, quotes, backslashes)
81
- ESCAPED=$(printf '%s' "$CONTEXT" | sed 's/\\/\\\\/g; s/"/\\"/g; s/\t/\\t/g')
82
-
83
- # Output structured JSON for reliable context injection
84
- printf '{"hookSpecificOutput":{"hookEventName":"SessionStart","additionalContext":"%s"}}\n' "$ESCAPED"
89
+ cat << EOF
90
+ ## Style: $STYLE
91
+
92
+ ## Rules
93
+ 1. Never skip acknowledgment TTS
94
+ 2. Never skip completion TTS
95
+ 3. Match verbosity level
96
+ 4. Keep under 150 chars
97
+ 5. Always include errors
98
+
99
+ Quick Ref: low=action+result | medium=+key decisions | high=+full reasoning
100
+
101
+ EOF