agentvibes 4.2.0 → 4.4.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.
- package/.agentvibes/bmad/bmad-voices.md +69 -69
- package/.agentvibes/config.json +12 -0
- package/.claude/activation-instructions +54 -54
- package/.claude/audio/tracks/README.md +52 -52
- package/.claude/commands/agent-vibes/add.md +21 -21
- package/.claude/commands/agent-vibes/agent-vibes.md +101 -101
- package/.claude/commands/agent-vibes/agent.md +79 -79
- package/.claude/commands/agent-vibes/background-music.md +111 -111
- package/.claude/commands/agent-vibes/bmad.md +198 -198
- package/.claude/commands/agent-vibes/clean.md +18 -18
- package/.claude/commands/agent-vibes/cleanup.md +18 -18
- package/.claude/commands/agent-vibes/commands.json +145 -145
- package/.claude/commands/agent-vibes/effects.md +97 -97
- package/.claude/commands/agent-vibes/get.md +9 -9
- package/.claude/commands/agent-vibes/hide.md +91 -91
- package/.claude/commands/agent-vibes/language.md +23 -23
- package/.claude/commands/agent-vibes/learn.md +67 -67
- package/.claude/commands/agent-vibes/list.md +13 -13
- package/.claude/commands/agent-vibes/mute.md +37 -37
- package/.claude/commands/agent-vibes/preview.md +17 -17
- package/.claude/commands/agent-vibes/provider.md +68 -68
- package/.claude/commands/agent-vibes/replay-target.md +14 -14
- package/.claude/commands/agent-vibes/sample.md +12 -12
- package/.claude/commands/agent-vibes/set-favorite-voice.md +84 -84
- package/.claude/commands/agent-vibes/set-pretext.md +65 -65
- package/.claude/commands/agent-vibes/set-speed.md +41 -41
- package/.claude/commands/agent-vibes/show.md +84 -84
- package/.claude/commands/agent-vibes/switch.md +87 -87
- package/.claude/commands/agent-vibes/target-voice.md +26 -26
- package/.claude/commands/agent-vibes/target.md +30 -30
- package/.claude/commands/agent-vibes/translate.md +68 -68
- package/.claude/commands/agent-vibes/unmute.md +45 -45
- package/.claude/commands/agent-vibes/verbosity.md +89 -89
- package/.claude/commands/agent-vibes/whoami.md +7 -7
- package/.claude/commands/agent-vibes-bmad-voices.md +117 -117
- package/.claude/commands/agent-vibes-rdp.md +24 -24
- package/.claude/config/agentvibes.json +1 -0
- package/.claude/config/audio-effects.cfg +2 -2
- package/.claude/config/audio-effects.cfg.sample +52 -52
- package/.claude/config/background-music-volume.txt +1 -0
- package/.claude/config/intro-text.txt +1 -0
- package/.claude/config/piper-speech-rate.txt +4 -0
- package/.claude/config/piper-target-speech-rate.txt +1 -0
- package/.claude/config/reverb-level.txt +1 -0
- package/.claude/config/tts-speech-rate.txt +4 -0
- package/.claude/config/tts-target-speech-rate.txt +1 -0
- package/.claude/docs/TERMUX_SETUP.md +408 -408
- package/.claude/github-star-reminder.txt +1 -1
- package/.claude/hooks/README-TTS-QUEUE.md +135 -135
- package/.claude/hooks/audio-cache-utils.sh +246 -246
- package/.claude/hooks/audio-processor.sh +433 -433
- package/.claude/hooks/background-music-manager.sh +404 -404
- package/.claude/hooks/bmad-speak-enhanced.sh +165 -165
- package/.claude/hooks/bmad-speak.sh +269 -269
- package/.claude/hooks/bmad-tts-injector.sh +568 -568
- package/.claude/hooks/bmad-voice-manager.sh +928 -928
- package/.claude/hooks/clawdbot-receiver-SECURE.sh +129 -129
- package/.claude/hooks/clawdbot-receiver.sh +107 -107
- package/.claude/hooks/clean-audio-cache.sh +22 -22
- package/.claude/hooks/cleanup-cache.sh +106 -106
- package/.claude/hooks/configure-rdp-mode.sh +137 -137
- package/.claude/hooks/download-extra-voices.sh +244 -244
- package/.claude/hooks/effects-manager.sh +268 -268
- package/.claude/hooks/github-star-reminder.sh +154 -154
- package/.claude/hooks/language-manager.sh +362 -362
- package/.claude/hooks/learn-manager.sh +492 -492
- package/.claude/hooks/macos-voice-manager.sh +205 -205
- package/.claude/hooks/migrate-background-music.sh +125 -125
- package/.claude/hooks/migrate-to-agentvibes.sh +161 -161
- package/.claude/hooks/optimize-background-music.sh +87 -87
- package/.claude/hooks/path-resolver.sh +60 -60
- package/.claude/hooks/personality-manager.sh +448 -448
- package/.claude/hooks/piper-download-voices.sh +225 -225
- package/.claude/hooks/piper-installer.sh +292 -292
- package/.claude/hooks/piper-multispeaker-registry.sh +171 -171
- package/.claude/hooks/piper-voice-manager.sh +24 -3
- package/.claude/hooks/play-tts-agentvibes-receiver-for-voiceless-connections.sh +90 -90
- package/.claude/hooks/play-tts-enhanced.sh +105 -105
- package/.claude/hooks/play-tts-macos.sh +368 -368
- package/.claude/hooks/play-tts-piper.sh +679 -679
- package/.claude/hooks/play-tts-soprano.sh +356 -356
- package/.claude/hooks/play-tts-ssh-remote.sh +167 -167
- package/.claude/hooks/play-tts-termux-ssh.sh +169 -169
- package/.claude/hooks/play-tts.sh +301 -301
- package/.claude/hooks/prepare-release.sh +54 -54
- package/.claude/hooks/provider-commands.sh +617 -617
- package/.claude/hooks/provider-manager.sh +399 -399
- package/.claude/hooks/replay-target-audio.sh +95 -95
- package/.claude/hooks/requirements.txt +6 -6
- package/.claude/hooks/sentiment-manager.sh +201 -201
- package/.claude/hooks/session-start-tts.sh +81 -81
- package/.claude/hooks/soprano-gradio-synth.py +139 -139
- package/.claude/hooks/speed-manager.sh +291 -291
- package/.claude/hooks/stop-tts.sh +84 -84
- package/.claude/hooks/termux-installer.sh +261 -261
- package/.claude/hooks/translate-manager.sh +341 -341
- package/.claude/hooks/translator.py +237 -237
- package/.claude/hooks/tts-queue-worker.sh +145 -145
- package/.claude/hooks/tts-queue.sh +165 -165
- package/.claude/hooks/verbosity-manager.sh +178 -178
- package/.claude/hooks/voice-manager.sh +548 -548
- package/.claude/hooks-windows/audio-cache-utils.ps1 +119 -119
- package/.claude/hooks-windows/background-music-manager.ps1 +348 -0
- package/.claude/hooks-windows/clean-audio-cache.ps1 +53 -0
- package/.claude/hooks-windows/download-extra-voices.ps1 +185 -0
- package/.claude/hooks-windows/effects-manager.ps1 +294 -0
- package/.claude/hooks-windows/language-manager.ps1 +193 -0
- package/.claude/hooks-windows/learn-manager.ps1 +241 -0
- package/.claude/hooks-windows/personality-manager.ps1 +266 -0
- package/.claude/hooks-windows/play-tts-piper.ps1 +209 -0
- package/.claude/hooks-windows/play-tts-sapi.ps1 +108 -0
- package/.claude/hooks-windows/play-tts-soprano.ps1 +159 -158
- package/.claude/hooks-windows/play-tts-windows-piper.ps1 +50 -5
- package/.claude/hooks-windows/play-tts-windows-sapi.ps1 +108 -108
- package/.claude/hooks-windows/play-tts.ps1 +344 -266
- package/.claude/hooks-windows/provider-manager.ps1 +29 -10
- package/.claude/hooks-windows/session-start-tts.ps1 +124 -124
- package/.claude/hooks-windows/soprano-gradio-synth.py +153 -153
- package/.claude/hooks-windows/speed-manager.ps1 +166 -0
- package/.claude/hooks-windows/verbosity-manager.ps1 +119 -0
- package/.claude/hooks-windows/voice-manager-windows.ps1 +92 -8
- package/.claude/output-styles/agent-vibes.md +202 -202
- package/.claude/personalities/angry.md +14 -14
- package/.claude/personalities/annoying.md +14 -14
- package/.claude/personalities/crass.md +14 -14
- package/.claude/personalities/dramatic.md +14 -14
- package/.claude/personalities/dry-humor.md +50 -50
- package/.claude/personalities/flirty.md +20 -20
- package/.claude/personalities/funny.md +14 -14
- package/.claude/personalities/grandpa.md +32 -32
- package/.claude/personalities/millennial.md +14 -14
- package/.claude/personalities/moody.md +14 -14
- package/.claude/personalities/normal.md +16 -16
- package/.claude/personalities/pirate.md +14 -14
- package/.claude/personalities/poetic.md +14 -14
- package/.claude/personalities/professional.md +14 -14
- package/.claude/personalities/rapper.md +55 -55
- package/.claude/personalities/robot.md +14 -14
- package/.claude/personalities/sarcastic.md +38 -38
- package/.claude/personalities/sassy.md +14 -14
- package/.claude/personalities/surfer-dude.md +14 -14
- package/.claude/personalities/zen.md +14 -14
- package/.claude/settings.json +15 -15
- package/.claude/verbosity.txt +1 -1
- package/.clawdbot/README.md +105 -105
- package/.clawdbot/skill/SKILL.md +241 -241
- package/.mcp.json +12 -0
- package/CLAUDE.md +170 -170
- package/README.md +2029 -2007
- package/RELEASE_NOTES.md +1310 -1203
- package/WINDOWS-SETUP.md +208 -208
- package/bin/agent-vibes +39 -39
- package/bin/agentvibes-voice-browser.js +1840 -1840
- package/bin/agentvibes.js +48 -2
- package/bin/mcp-server.js +121 -121
- package/bin/mcp-server.sh +206 -206
- package/bin/test-bmad-pr +78 -78
- package/mcp-server/QUICK_START.md +203 -203
- package/mcp-server/README.md +345 -345
- package/mcp-server/WINDOWS_SETUP.md +260 -260
- package/mcp-server/docs/troubleshooting-audio.md +313 -313
- package/mcp-server/examples/claude_desktop_config.json +11 -11
- package/mcp-server/examples/claude_desktop_config_piper.json +9 -9
- package/mcp-server/examples/custom_instructions.md +169 -169
- package/mcp-server/install-deps.js +130 -130
- package/mcp-server/pyproject.toml +52 -52
- package/mcp-server/requirements.txt +2 -2
- package/mcp-server/server.py +1465 -1453
- package/mcp-server/test_server.py +395 -395
- package/mcp-server/test_windows_script_parity.py +336 -0
- package/package.json +110 -110
- package/setup-windows.ps1 +815 -815
- package/src/bmad-detector.js +71 -71
- package/src/cli/list-personalities.js +110 -110
- package/src/cli/list-voices.js +114 -114
- package/src/commands/bmad-voices.js +394 -394
- package/src/commands/install-mcp.js +476 -476
- package/src/console/app.js +824 -824
- package/src/console/audio-env.js +20 -1
- package/src/console/brand-colors.js +13 -13
- package/src/console/constants/personalities.js +44 -44
- package/src/console/footer-config.js +50 -50
- package/src/console/modals/modal-overlay.js +247 -247
- package/src/console/navigation.js +62 -62
- package/src/console/tabs/agents-tab.js +1684 -1516
- package/src/console/tabs/help-tab.js +261 -261
- package/src/console/tabs/install-tab.js +1007 -991
- package/src/console/tabs/music-tab.js +22 -8
- package/src/console/tabs/placeholder-tab.js +53 -53
- package/src/console/tabs/readme-tab.js +267 -267
- package/src/console/tabs/receiver-tab.js +1472 -1212
- package/src/console/tabs/settings-tab.js +208 -84
- package/src/console/tabs/voices-tab.js +100 -21
- package/src/console/widgets/destroy-list.js +25 -25
- package/src/console/widgets/format-utils.js +89 -89
- package/src/console/widgets/notice.js +55 -55
- package/src/console/widgets/personality-picker.js +185 -185
- package/src/console/widgets/reverb-picker.js +94 -94
- package/src/console/widgets/track-picker.js +285 -285
- package/src/installer/music-file-input.js +304 -304
- package/src/installer.js +5895 -5829
- package/src/services/agent-voice-store.js +423 -423
- package/src/services/config-service.js +264 -264
- package/src/services/navigation-service.js +123 -123
- package/src/services/provider-service.js +143 -132
- package/src/services/verbosity-service.js +157 -157
- package/src/utils/audio-duration-validator.js +298 -298
- package/src/utils/audio-format-validator.js +277 -277
- package/src/utils/dependency-checker.js +469 -466
- package/src/utils/file-ownership-verifier.js +358 -358
- package/src/utils/list-formatter.js +194 -194
- package/src/utils/music-file-validator.js +285 -285
- package/src/utils/preview-list-prompt.js +136 -136
- package/src/utils/provider-validator.js +96 -12
- package/src/utils/secure-music-storage.js +412 -412
- package/templates/agentvibes-receiver.sh +482 -482
- package/templates/audio/welcome-music.mp3 +0 -0
- package/voice-assignments.json +8244 -8244
- package/.claude/config/background-music-position.txt +0 -1
|
@@ -1,167 +1,167 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
#
|
|
3
|
-
# File: .claude/hooks/play-tts-ssh-remote.sh
|
|
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.
|
|
10
|
-
#
|
|
11
|
-
# Copyright (c) 2025 Paul Preibisch
|
|
12
|
-
# Licensed under the Apache License, Version 2.0
|
|
13
|
-
#
|
|
14
|
-
|
|
15
|
-
set -euo pipefail
|
|
16
|
-
|
|
17
|
-
TEXT="${1:-}"
|
|
18
|
-
VOICE="${2:-en_US-lessac-medium}"
|
|
19
|
-
AGENT_NAME="${3:-default}"
|
|
20
|
-
|
|
21
|
-
# Validate required input
|
|
22
|
-
if [[ -z "$TEXT" ]]; then
|
|
23
|
-
echo "Usage: $0 <text> [voice] [agent_name]" >&2
|
|
24
|
-
exit 1
|
|
25
|
-
fi
|
|
26
|
-
|
|
27
|
-
# Get script directory and project root
|
|
28
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
29
|
-
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
30
|
-
|
|
31
|
-
# Derive project name from directory
|
|
32
|
-
PROJECT_NAME=$(basename "$PROJECT_ROOT")
|
|
33
|
-
|
|
34
|
-
# ---------------------------------------------------------------------------
|
|
35
|
-
# Get SSH host from config
|
|
36
|
-
# ---------------------------------------------------------------------------
|
|
37
|
-
|
|
38
|
-
SSH_HOST=$(cat "$PROJECT_ROOT/.claude/ssh-remote-host.txt" 2>/dev/null || \
|
|
39
|
-
cat "$HOME/.claude/ssh-remote-host.txt" 2>/dev/null || echo "")
|
|
40
|
-
|
|
41
|
-
if [[ -z "$SSH_HOST" ]]; then
|
|
42
|
-
echo "SSH-Remote host not configured" >&2
|
|
43
|
-
echo "Set host: echo 'my-host' > .claude/ssh-remote-host.txt" >&2
|
|
44
|
-
exit 1
|
|
45
|
-
fi
|
|
46
|
-
|
|
47
|
-
# SECURITY: Validate SSH_HOST format
|
|
48
|
-
if [[ ! "$SSH_HOST" =~ ^[a-zA-Z0-9][a-zA-Z0-9._-]*$ ]]; then
|
|
49
|
-
echo "Invalid SSH host format: $SSH_HOST" >&2
|
|
50
|
-
exit 1
|
|
51
|
-
fi
|
|
52
|
-
|
|
53
|
-
# SECURITY: Validate VOICE
|
|
54
|
-
if [[ ! "$VOICE" =~ ^[a-zA-Z0-9_-]+$ ]]; then
|
|
55
|
-
echo "Invalid voice format: $VOICE" >&2
|
|
56
|
-
exit 1
|
|
57
|
-
fi
|
|
58
|
-
|
|
59
|
-
# SECURITY: Validate AGENT_NAME
|
|
60
|
-
if [[ ! "$AGENT_NAME" =~ ^[a-zA-Z0-9_\ -]+$ ]]; then
|
|
61
|
-
echo "Invalid agent name format: $AGENT_NAME" >&2
|
|
62
|
-
exit 1
|
|
63
|
-
fi
|
|
64
|
-
|
|
65
|
-
# ---------------------------------------------------------------------------
|
|
66
|
-
# Read audio effects config for this agent
|
|
67
|
-
# ---------------------------------------------------------------------------
|
|
68
|
-
|
|
69
|
-
SOX_EFFECTS=""
|
|
70
|
-
BG_FILE=""
|
|
71
|
-
BG_VOLUME="0.10"
|
|
72
|
-
|
|
73
|
-
EFFECTS_CFG="$PROJECT_ROOT/.claude/config/audio-effects.cfg"
|
|
74
|
-
if [[ -f "$EFFECTS_CFG" ]]; then
|
|
75
|
-
CONFIG_LINE=$(grep "^${AGENT_NAME}|" "$EFFECTS_CFG" 2>/dev/null || \
|
|
76
|
-
grep "^default|" "$EFFECTS_CFG" 2>/dev/null || true)
|
|
77
|
-
if [[ -n "$CONFIG_LINE" ]]; then
|
|
78
|
-
IFS='|' read -r _ SOX_EFFECTS BG_FILE BG_VOLUME <<< "$CONFIG_LINE"
|
|
79
|
-
fi
|
|
80
|
-
fi
|
|
81
|
-
|
|
82
|
-
# Read pretext if configured
|
|
83
|
-
PRETEXT=""
|
|
84
|
-
PRETEXT_FILE="$PROJECT_ROOT/.agentvibes/config/pretext.txt"
|
|
85
|
-
if [[ -f "$PRETEXT_FILE" ]]; then
|
|
86
|
-
PRETEXT=$(cat "$PRETEXT_FILE" 2>/dev/null || true)
|
|
87
|
-
fi
|
|
88
|
-
|
|
89
|
-
# Read speed if configured
|
|
90
|
-
SPEED=""
|
|
91
|
-
SPEED_FILE="$PROJECT_ROOT/.agentvibes/config/speed.txt"
|
|
92
|
-
if [[ -f "$SPEED_FILE" ]]; then
|
|
93
|
-
SPEED=$(cat "$SPEED_FILE" 2>/dev/null || true)
|
|
94
|
-
fi
|
|
95
|
-
|
|
96
|
-
# Read the TTS provider the RECEIVER should use to generate audio.
|
|
97
|
-
# This is separate from the sender's own provider (which is "ssh-remote").
|
|
98
|
-
# Check receiver-provider.txt first, then fall back to "piper".
|
|
99
|
-
PROVIDER=""
|
|
100
|
-
RECEIVER_PROVIDER_FILE="$PROJECT_ROOT/.agentvibes/config/receiver-provider.txt"
|
|
101
|
-
if [[ -f "$RECEIVER_PROVIDER_FILE" ]]; then
|
|
102
|
-
PROVIDER=$(cat "$RECEIVER_PROVIDER_FILE" 2>/dev/null || true)
|
|
103
|
-
fi
|
|
104
|
-
# Also check home-level config
|
|
105
|
-
if [[ -z "$PROVIDER" ]]; then
|
|
106
|
-
RECEIVER_PROVIDER_FILE="$HOME/.agentvibes/config/receiver-provider.txt"
|
|
107
|
-
if [[ -f "$RECEIVER_PROVIDER_FILE" ]]; then
|
|
108
|
-
PROVIDER=$(cat "$RECEIVER_PROVIDER_FILE" 2>/dev/null || true)
|
|
109
|
-
fi
|
|
110
|
-
fi
|
|
111
|
-
# Validate — only known TTS providers (not transport providers like ssh-remote)
|
|
112
|
-
case "${PROVIDER:-}" in
|
|
113
|
-
piper|soprano|macos|windows-sapi) ;;
|
|
114
|
-
*) PROVIDER="piper" ;;
|
|
115
|
-
esac
|
|
116
|
-
|
|
117
|
-
# ---------------------------------------------------------------------------
|
|
118
|
-
# Build JSON payload
|
|
119
|
-
# ---------------------------------------------------------------------------
|
|
120
|
-
|
|
121
|
-
# SECURITY: Use jq if available for safe JSON construction, else manual escaping
|
|
122
|
-
build_json_payload() {
|
|
123
|
-
if command -v jq &>/dev/null; then
|
|
124
|
-
jq -n \
|
|
125
|
-
--arg text "$TEXT" \
|
|
126
|
-
--arg voice "$VOICE" \
|
|
127
|
-
--arg effects "$SOX_EFFECTS" \
|
|
128
|
-
--arg music "$BG_FILE" \
|
|
129
|
-
--arg volume "$BG_VOLUME" \
|
|
130
|
-
--arg project "$PROJECT_NAME" \
|
|
131
|
-
--arg pretext "$PRETEXT" \
|
|
132
|
-
--arg speed "$SPEED" \
|
|
133
|
-
--arg provider "$PROVIDER" \
|
|
134
|
-
'{text: $text, voice: $voice, effects: $effects, music: $music, volume: $volume, project: $project, pretext: $pretext, speed: $speed, provider: $provider}'
|
|
135
|
-
else
|
|
136
|
-
# Manual JSON — escape double quotes and backslashes in text
|
|
137
|
-
local escaped_text
|
|
138
|
-
escaped_text=$(printf '%s' "$TEXT" | sed 's/\\/\\\\/g; s/"/\\"/g; s/\t/\\t/g')
|
|
139
|
-
local escaped_pretext
|
|
140
|
-
escaped_pretext=$(printf '%s' "$PRETEXT" | sed 's/\\/\\\\/g; s/"/\\"/g')
|
|
141
|
-
printf '{"text":"%s","voice":"%s","effects":"%s","music":"%s","volume":"%s","project":"%s","pretext":"%s","speed":"%s","provider":"%s"}' \
|
|
142
|
-
"$escaped_text" "$VOICE" "$SOX_EFFECTS" "$BG_FILE" "$BG_VOLUME" "$PROJECT_NAME" "$escaped_pretext" "$SPEED" "$PROVIDER"
|
|
143
|
-
fi
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
JSON_PAYLOAD=$(build_json_payload)
|
|
147
|
-
|
|
148
|
-
# SECURITY: Base64-encode entire payload — safe for SSH transport
|
|
149
|
-
# base64 -w 0 is Linux (GNU coreutils), -b 0 is macOS (BSD)
|
|
150
|
-
if base64 --help 2>&1 | grep -q '\-w'; then
|
|
151
|
-
ENCODED_PAYLOAD=$(printf '%s' "$JSON_PAYLOAD" | base64 -w 0)
|
|
152
|
-
else
|
|
153
|
-
ENCODED_PAYLOAD=$(printf '%s' "$JSON_PAYLOAD" | base64 -b 0 2>/dev/null || printf '%s' "$JSON_PAYLOAD" | base64 | tr -d '\n')
|
|
154
|
-
fi
|
|
155
|
-
|
|
156
|
-
# ---------------------------------------------------------------------------
|
|
157
|
-
# Send to receiver via SSH (fire and forget — backgrounded)
|
|
158
|
-
# ---------------------------------------------------------------------------
|
|
159
|
-
|
|
160
|
-
echo "Sending to $SSH_HOST..." >&2
|
|
161
|
-
|
|
162
|
-
# ForceCommand receiver: SSH_ORIGINAL_COMMAND passes the payload directly
|
|
163
|
-
ssh "$SSH_HOST" "$ENCODED_PAYLOAD" &
|
|
164
|
-
SSH_PID=$!
|
|
165
|
-
|
|
166
|
-
echo "Sent to $SSH_HOST (PID: $SSH_PID)" >&2
|
|
167
|
-
exit 0
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# File: .claude/hooks/play-tts-ssh-remote.sh
|
|
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.
|
|
10
|
+
#
|
|
11
|
+
# Copyright (c) 2025 Paul Preibisch
|
|
12
|
+
# Licensed under the Apache License, Version 2.0
|
|
13
|
+
#
|
|
14
|
+
|
|
15
|
+
set -euo pipefail
|
|
16
|
+
|
|
17
|
+
TEXT="${1:-}"
|
|
18
|
+
VOICE="${2:-en_US-lessac-medium}"
|
|
19
|
+
AGENT_NAME="${3:-default}"
|
|
20
|
+
|
|
21
|
+
# Validate required input
|
|
22
|
+
if [[ -z "$TEXT" ]]; then
|
|
23
|
+
echo "Usage: $0 <text> [voice] [agent_name]" >&2
|
|
24
|
+
exit 1
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
# Get script directory and project root
|
|
28
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
29
|
+
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
30
|
+
|
|
31
|
+
# Derive project name from directory
|
|
32
|
+
PROJECT_NAME=$(basename "$PROJECT_ROOT")
|
|
33
|
+
|
|
34
|
+
# ---------------------------------------------------------------------------
|
|
35
|
+
# Get SSH host from config
|
|
36
|
+
# ---------------------------------------------------------------------------
|
|
37
|
+
|
|
38
|
+
SSH_HOST=$(cat "$PROJECT_ROOT/.claude/ssh-remote-host.txt" 2>/dev/null || \
|
|
39
|
+
cat "$HOME/.claude/ssh-remote-host.txt" 2>/dev/null || echo "")
|
|
40
|
+
|
|
41
|
+
if [[ -z "$SSH_HOST" ]]; then
|
|
42
|
+
echo "SSH-Remote host not configured" >&2
|
|
43
|
+
echo "Set host: echo 'my-host' > .claude/ssh-remote-host.txt" >&2
|
|
44
|
+
exit 1
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
# SECURITY: Validate SSH_HOST format
|
|
48
|
+
if [[ ! "$SSH_HOST" =~ ^[a-zA-Z0-9][a-zA-Z0-9._-]*$ ]]; then
|
|
49
|
+
echo "Invalid SSH host format: $SSH_HOST" >&2
|
|
50
|
+
exit 1
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
# SECURITY: Validate VOICE
|
|
54
|
+
if [[ ! "$VOICE" =~ ^[a-zA-Z0-9_-]+$ ]]; then
|
|
55
|
+
echo "Invalid voice format: $VOICE" >&2
|
|
56
|
+
exit 1
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
# SECURITY: Validate AGENT_NAME
|
|
60
|
+
if [[ ! "$AGENT_NAME" =~ ^[a-zA-Z0-9_\ -]+$ ]]; then
|
|
61
|
+
echo "Invalid agent name format: $AGENT_NAME" >&2
|
|
62
|
+
exit 1
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
# ---------------------------------------------------------------------------
|
|
66
|
+
# Read audio effects config for this agent
|
|
67
|
+
# ---------------------------------------------------------------------------
|
|
68
|
+
|
|
69
|
+
SOX_EFFECTS=""
|
|
70
|
+
BG_FILE=""
|
|
71
|
+
BG_VOLUME="0.10"
|
|
72
|
+
|
|
73
|
+
EFFECTS_CFG="$PROJECT_ROOT/.claude/config/audio-effects.cfg"
|
|
74
|
+
if [[ -f "$EFFECTS_CFG" ]]; then
|
|
75
|
+
CONFIG_LINE=$(grep "^${AGENT_NAME}|" "$EFFECTS_CFG" 2>/dev/null || \
|
|
76
|
+
grep "^default|" "$EFFECTS_CFG" 2>/dev/null || true)
|
|
77
|
+
if [[ -n "$CONFIG_LINE" ]]; then
|
|
78
|
+
IFS='|' read -r _ SOX_EFFECTS BG_FILE BG_VOLUME <<< "$CONFIG_LINE"
|
|
79
|
+
fi
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
# Read pretext if configured
|
|
83
|
+
PRETEXT=""
|
|
84
|
+
PRETEXT_FILE="$PROJECT_ROOT/.agentvibes/config/pretext.txt"
|
|
85
|
+
if [[ -f "$PRETEXT_FILE" ]]; then
|
|
86
|
+
PRETEXT=$(cat "$PRETEXT_FILE" 2>/dev/null || true)
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
# Read speed if configured
|
|
90
|
+
SPEED=""
|
|
91
|
+
SPEED_FILE="$PROJECT_ROOT/.agentvibes/config/speed.txt"
|
|
92
|
+
if [[ -f "$SPEED_FILE" ]]; then
|
|
93
|
+
SPEED=$(cat "$SPEED_FILE" 2>/dev/null || true)
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
# Read the TTS provider the RECEIVER should use to generate audio.
|
|
97
|
+
# This is separate from the sender's own provider (which is "ssh-remote").
|
|
98
|
+
# Check receiver-provider.txt first, then fall back to "piper".
|
|
99
|
+
PROVIDER=""
|
|
100
|
+
RECEIVER_PROVIDER_FILE="$PROJECT_ROOT/.agentvibes/config/receiver-provider.txt"
|
|
101
|
+
if [[ -f "$RECEIVER_PROVIDER_FILE" ]]; then
|
|
102
|
+
PROVIDER=$(cat "$RECEIVER_PROVIDER_FILE" 2>/dev/null || true)
|
|
103
|
+
fi
|
|
104
|
+
# Also check home-level config
|
|
105
|
+
if [[ -z "$PROVIDER" ]]; then
|
|
106
|
+
RECEIVER_PROVIDER_FILE="$HOME/.agentvibes/config/receiver-provider.txt"
|
|
107
|
+
if [[ -f "$RECEIVER_PROVIDER_FILE" ]]; then
|
|
108
|
+
PROVIDER=$(cat "$RECEIVER_PROVIDER_FILE" 2>/dev/null || true)
|
|
109
|
+
fi
|
|
110
|
+
fi
|
|
111
|
+
# Validate — only known TTS providers (not transport providers like ssh-remote)
|
|
112
|
+
case "${PROVIDER:-}" in
|
|
113
|
+
piper|soprano|macos|windows-sapi) ;;
|
|
114
|
+
*) PROVIDER="piper" ;;
|
|
115
|
+
esac
|
|
116
|
+
|
|
117
|
+
# ---------------------------------------------------------------------------
|
|
118
|
+
# Build JSON payload
|
|
119
|
+
# ---------------------------------------------------------------------------
|
|
120
|
+
|
|
121
|
+
# SECURITY: Use jq if available for safe JSON construction, else manual escaping
|
|
122
|
+
build_json_payload() {
|
|
123
|
+
if command -v jq &>/dev/null; then
|
|
124
|
+
jq -n \
|
|
125
|
+
--arg text "$TEXT" \
|
|
126
|
+
--arg voice "$VOICE" \
|
|
127
|
+
--arg effects "$SOX_EFFECTS" \
|
|
128
|
+
--arg music "$BG_FILE" \
|
|
129
|
+
--arg volume "$BG_VOLUME" \
|
|
130
|
+
--arg project "$PROJECT_NAME" \
|
|
131
|
+
--arg pretext "$PRETEXT" \
|
|
132
|
+
--arg speed "$SPEED" \
|
|
133
|
+
--arg provider "$PROVIDER" \
|
|
134
|
+
'{text: $text, voice: $voice, effects: $effects, music: $music, volume: $volume, project: $project, pretext: $pretext, speed: $speed, provider: $provider}'
|
|
135
|
+
else
|
|
136
|
+
# Manual JSON — escape double quotes and backslashes in text
|
|
137
|
+
local escaped_text
|
|
138
|
+
escaped_text=$(printf '%s' "$TEXT" | sed 's/\\/\\\\/g; s/"/\\"/g; s/\t/\\t/g')
|
|
139
|
+
local escaped_pretext
|
|
140
|
+
escaped_pretext=$(printf '%s' "$PRETEXT" | sed 's/\\/\\\\/g; s/"/\\"/g')
|
|
141
|
+
printf '{"text":"%s","voice":"%s","effects":"%s","music":"%s","volume":"%s","project":"%s","pretext":"%s","speed":"%s","provider":"%s"}' \
|
|
142
|
+
"$escaped_text" "$VOICE" "$SOX_EFFECTS" "$BG_FILE" "$BG_VOLUME" "$PROJECT_NAME" "$escaped_pretext" "$SPEED" "$PROVIDER"
|
|
143
|
+
fi
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
JSON_PAYLOAD=$(build_json_payload)
|
|
147
|
+
|
|
148
|
+
# SECURITY: Base64-encode entire payload — safe for SSH transport
|
|
149
|
+
# base64 -w 0 is Linux (GNU coreutils), -b 0 is macOS (BSD)
|
|
150
|
+
if base64 --help 2>&1 | grep -q '\-w'; then
|
|
151
|
+
ENCODED_PAYLOAD=$(printf '%s' "$JSON_PAYLOAD" | base64 -w 0)
|
|
152
|
+
else
|
|
153
|
+
ENCODED_PAYLOAD=$(printf '%s' "$JSON_PAYLOAD" | base64 -b 0 2>/dev/null || printf '%s' "$JSON_PAYLOAD" | base64 | tr -d '\n')
|
|
154
|
+
fi
|
|
155
|
+
|
|
156
|
+
# ---------------------------------------------------------------------------
|
|
157
|
+
# Send to receiver via SSH (fire and forget — backgrounded)
|
|
158
|
+
# ---------------------------------------------------------------------------
|
|
159
|
+
|
|
160
|
+
echo "Sending to $SSH_HOST..." >&2
|
|
161
|
+
|
|
162
|
+
# ForceCommand receiver: SSH_ORIGINAL_COMMAND passes the payload directly
|
|
163
|
+
ssh "$SSH_HOST" "$ENCODED_PAYLOAD" &
|
|
164
|
+
SSH_PID=$!
|
|
165
|
+
|
|
166
|
+
echo "Sent to $SSH_HOST (PID: $SSH_PID)" >&2
|
|
167
|
+
exit 0
|