agentvibes 2.0.8 → 2.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/RELEASE_NOTES.md +23 -0
- package/package.json +1 -1
- package/src/installer.js +57 -31
- package/agentvibes.org/.claude/commands/agent-vibes/add.md +0 -21
- package/agentvibes.org/.claude/commands/agent-vibes/agent-vibes.md +0 -68
- package/agentvibes.org/.claude/commands/agent-vibes/commands.json +0 -53
- package/agentvibes.org/.claude/commands/agent-vibes/get.md +0 -9
- package/agentvibes.org/.claude/commands/agent-vibes/list.md +0 -13
- package/agentvibes.org/.claude/commands/agent-vibes/personality.md +0 -79
- package/agentvibes.org/.claude/commands/agent-vibes/preview.md +0 -16
- package/agentvibes.org/.claude/commands/agent-vibes/provider.md +0 -54
- package/agentvibes.org/.claude/commands/agent-vibes/replay.md +0 -19
- package/agentvibes.org/.claude/commands/agent-vibes/sample.md +0 -12
- package/agentvibes.org/.claude/commands/agent-vibes/sentiment.md +0 -52
- package/agentvibes.org/.claude/commands/agent-vibes/set-language.md +0 -47
- package/agentvibes.org/.claude/commands/agent-vibes/set-pretext.md +0 -65
- package/agentvibes.org/.claude/commands/agent-vibes/switch.md +0 -53
- package/agentvibes.org/.claude/commands/agent-vibes/update.md +0 -20
- package/agentvibes.org/.claude/commands/agent-vibes/version.md +0 -10
- package/agentvibes.org/.claude/commands/agent-vibes/whoami.md +0 -7
- package/agentvibes.org/.claude/hooks/bmad-voice-manager.sh +0 -278
- package/agentvibes.org/.claude/hooks/language-manager.sh +0 -190
- package/agentvibes.org/.claude/hooks/personality-manager.sh +0 -279
- package/agentvibes.org/.claude/hooks/piper-download-voices.sh +0 -133
- package/agentvibes.org/.claude/hooks/piper-voice-manager.sh +0 -227
- package/agentvibes.org/.claude/hooks/play-tts-elevenlabs.sh +0 -201
- package/agentvibes.org/.claude/hooks/play-tts-piper.sh +0 -175
- package/agentvibes.org/.claude/hooks/play-tts.sh +0 -138
- package/agentvibes.org/.claude/hooks/provider-commands.sh +0 -374
- package/agentvibes.org/.claude/hooks/provider-manager.sh +0 -196
- package/agentvibes.org/.claude/hooks/sentiment-manager.sh +0 -163
- package/agentvibes.org/.claude/hooks/voice-manager.sh +0 -349
- package/agentvibes.org/.claude/hooks/voices-config.sh +0 -33
- package/agentvibes.org/.claude/journal/2025-10-07.html +0 -373
- package/agentvibes.org/.claude/journal/index.html +0 -91
- package/agentvibes.org/.claude/output-styles/agent-vibes.md +0 -203
- package/agentvibes.org/.claude/personalities/angry.md +0 -16
- package/agentvibes.org/.claude/personalities/annoying.md +0 -16
- package/agentvibes.org/.claude/personalities/crass.md +0 -16
- package/agentvibes.org/.claude/personalities/dramatic.md +0 -16
- package/agentvibes.org/.claude/personalities/dry-humor.md +0 -52
- package/agentvibes.org/.claude/personalities/flirty.md +0 -22
- package/agentvibes.org/.claude/personalities/funny.md +0 -16
- package/agentvibes.org/.claude/personalities/grandpa.md +0 -34
- package/agentvibes.org/.claude/personalities/millennial.md +0 -16
- package/agentvibes.org/.claude/personalities/moody.md +0 -16
- package/agentvibes.org/.claude/personalities/normal.md +0 -18
- package/agentvibes.org/.claude/personalities/pirate.md +0 -16
- package/agentvibes.org/.claude/personalities/poetic.md +0 -16
- package/agentvibes.org/.claude/personalities/professional.md +0 -16
- package/agentvibes.org/.claude/personalities/robot.md +0 -16
- package/agentvibes.org/.claude/personalities/sarcastic.md +0 -40
- package/agentvibes.org/.claude/personalities/sassy.md +0 -16
- package/agentvibes.org/.claude/personalities/surfer-dude.md +0 -16
- package/agentvibes.org/.claude/personalities/zen.md +0 -16
- package/agentvibes.org/.mcp-minimal.json +0 -60
- package/agentvibes.org/CHANGELOG.md +0 -56
- package/agentvibes.org/README.md +0 -93
- package/agentvibes.org/app/(auth)/layout.tsx +0 -15
- package/agentvibes.org/app/(auth)/reset-password/page.tsx +0 -45
- package/agentvibes.org/app/(auth)/signin/page.tsx +0 -82
- package/agentvibes.org/app/(auth)/signup/page.tsx +0 -104
- package/agentvibes.org/app/(default)/layout.tsx +0 -31
- package/agentvibes.org/app/(default)/page.tsx +0 -20
- package/agentvibes.org/app/api/hello/route.ts +0 -3
- package/agentvibes.org/app/css/additional-styles/theme.css +0 -82
- package/agentvibes.org/app/css/additional-styles/utility-patterns.css +0 -55
- package/agentvibes.org/app/css/style.css +0 -100
- package/agentvibes.org/app/layout.tsx +0 -63
- package/agentvibes.org/components/cta.tsx +0 -58
- package/agentvibes.org/components/features.tsx +0 -256
- package/agentvibes.org/components/hero-home.tsx +0 -133
- package/agentvibes.org/components/modal-video.tsx +0 -137
- package/agentvibes.org/components/page-illustration.tsx +0 -55
- package/agentvibes.org/components/spotlight.tsx +0 -77
- package/agentvibes.org/components/testimonials.tsx +0 -282
- package/agentvibes.org/components/ui/footer.tsx +0 -82
- package/agentvibes.org/components/ui/header.tsx +0 -53
- package/agentvibes.org/components/ui/logo.tsx +0 -10
- package/agentvibes.org/components/workflows.tsx +0 -176
- package/agentvibes.org/next.config.js +0 -4
- package/agentvibes.org/package-lock.json +0 -1974
- package/agentvibes.org/package.json +0 -30
- package/agentvibes.org/pnpm-lock.yaml +0 -1141
- package/agentvibes.org/postcss.config.js +0 -5
- package/agentvibes.org/public/audio/02-sarcastic.mp3 +0 -0
- package/agentvibes.org/public/audio/03-angry.mp3 +0 -0
- package/agentvibes.org/public/audio/04-grandpa.mp3 +0 -0
- package/agentvibes.org/public/audio/05-sarcastic-example2.mp3 +0 -0
- package/agentvibes.org/public/audio/french-rachel.mp3 +0 -0
- package/agentvibes.org/public/audio/spanish-antoni.mp3 +0 -0
- package/agentvibes.org/public/favicon.ico +0 -0
- package/agentvibes.org/public/fonts/nacelle-italic.woff2 +0 -0
- package/agentvibes.org/public/fonts/nacelle-regular.woff2 +0 -0
- package/agentvibes.org/public/fonts/nacelle-semibold.woff2 +0 -0
- package/agentvibes.org/public/fonts/nacelle-semibolditalic.woff2 +0 -0
- package/agentvibes.org/public/images/blurred-shape-gray.svg +0 -1
- package/agentvibes.org/public/images/blurred-shape.svg +0 -1
- package/agentvibes.org/public/images/client-logo-01.svg +0 -1
- package/agentvibes.org/public/images/client-logo-02.svg +0 -1
- package/agentvibes.org/public/images/client-logo-03.svg +0 -1
- package/agentvibes.org/public/images/client-logo-04.svg +0 -1
- package/agentvibes.org/public/images/client-logo-05.svg +0 -1
- package/agentvibes.org/public/images/client-logo-06.svg +0 -1
- package/agentvibes.org/public/images/client-logo-07.svg +0 -1
- package/agentvibes.org/public/images/client-logo-08.svg +0 -1
- package/agentvibes.org/public/images/client-logo-09.svg +0 -1
- package/agentvibes.org/public/images/features.png +0 -0
- package/agentvibes.org/public/images/footer-illustration.svg +0 -1
- package/agentvibes.org/public/images/hero-image-01.jpg +0 -0
- package/agentvibes.org/public/images/logo.svg +0 -1
- package/agentvibes.org/public/images/page-illustration.svg +0 -1
- package/agentvibes.org/public/images/secondary-illustration.svg +0 -1
- package/agentvibes.org/public/images/testimonial-01.jpg +0 -0
- package/agentvibes.org/public/images/testimonial-02.jpg +0 -0
- package/agentvibes.org/public/images/testimonial-03.jpg +0 -0
- package/agentvibes.org/public/images/testimonial-04.jpg +0 -0
- package/agentvibes.org/public/images/testimonial-05.jpg +0 -0
- package/agentvibes.org/public/images/testimonial-06.jpg +0 -0
- package/agentvibes.org/public/images/testimonial-07.jpg +0 -0
- package/agentvibes.org/public/images/testimonial-08.jpg +0 -0
- package/agentvibes.org/public/images/testimonial-09.jpg +0 -0
- package/agentvibes.org/public/images/workflow-01.png +0 -0
- package/agentvibes.org/public/images/workflow-02.png +0 -0
- package/agentvibes.org/public/images/workflow-03.png +0 -0
- package/agentvibes.org/public/videos/video.mp4 +0 -0
- package/agentvibes.org/tsconfig.json +0 -28
- package/agentvibes.org/utils/useMasonry.tsx +0 -67
- package/agentvibes.org/utils/useMousePosition.tsx +0 -27
|
@@ -1,279 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# Personality manager for AgentVibes - adds character to TTS messages
|
|
3
|
-
|
|
4
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
-
PERSONALITIES_DIR="$SCRIPT_DIR/../personalities"
|
|
6
|
-
|
|
7
|
-
# Project-local file first, global fallback
|
|
8
|
-
# Use logical path (not physical) to handle symlinked .claude directories
|
|
9
|
-
# Script is at .claude/hooks/personality-manager.sh, so .claude is ..
|
|
10
|
-
CLAUDE_DIR="$(cd "$SCRIPT_DIR/.." 2>/dev/null && pwd)"
|
|
11
|
-
|
|
12
|
-
# Check if we have a project-local .claude directory
|
|
13
|
-
if [[ -d "$CLAUDE_DIR" ]] && [[ "$CLAUDE_DIR" != "$HOME/.claude" ]]; then
|
|
14
|
-
PERSONALITY_FILE="$CLAUDE_DIR/tts-personality.txt"
|
|
15
|
-
else
|
|
16
|
-
PERSONALITY_FILE="$HOME/.claude/tts-personality.txt"
|
|
17
|
-
fi
|
|
18
|
-
|
|
19
|
-
# Function to get personality data from markdown file
|
|
20
|
-
get_personality_data() {
|
|
21
|
-
local personality="$1"
|
|
22
|
-
local field="$2"
|
|
23
|
-
local file="$PERSONALITIES_DIR/${personality}.md"
|
|
24
|
-
|
|
25
|
-
if [[ ! -f "$file" ]]; then
|
|
26
|
-
return 1
|
|
27
|
-
fi
|
|
28
|
-
|
|
29
|
-
case "$field" in
|
|
30
|
-
prefix)
|
|
31
|
-
sed -n '/^## Prefix/,/^##/p' "$file" | sed '1d;$d' | tr -d '\n' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'
|
|
32
|
-
;;
|
|
33
|
-
suffix)
|
|
34
|
-
sed -n '/^## Suffix/,/^##/p' "$file" | sed '1d;$d' | tr -d '\n' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'
|
|
35
|
-
;;
|
|
36
|
-
description)
|
|
37
|
-
grep "^description:" "$file" | cut -d: -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'
|
|
38
|
-
;;
|
|
39
|
-
voice)
|
|
40
|
-
grep "^voice:" "$file" | cut -d: -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'
|
|
41
|
-
;;
|
|
42
|
-
instructions)
|
|
43
|
-
sed -n '/^## AI Instructions/,/^##/p' "$file" | sed '1d;$d'
|
|
44
|
-
;;
|
|
45
|
-
esac
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
# Function to list all available personalities
|
|
49
|
-
list_personalities() {
|
|
50
|
-
local personalities=()
|
|
51
|
-
|
|
52
|
-
# Find all .md files in personalities directory
|
|
53
|
-
if [[ -d "$PERSONALITIES_DIR" ]]; then
|
|
54
|
-
for file in "$PERSONALITIES_DIR"/*.md; do
|
|
55
|
-
if [[ -f "$file" ]]; then
|
|
56
|
-
basename "$file" .md
|
|
57
|
-
fi
|
|
58
|
-
done
|
|
59
|
-
fi
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
case "$1" in
|
|
63
|
-
list)
|
|
64
|
-
echo "🎭 Available Personalities:"
|
|
65
|
-
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
66
|
-
|
|
67
|
-
# Get current personality
|
|
68
|
-
CURRENT="normal"
|
|
69
|
-
if [ -f "$PERSONALITY_FILE" ]; then
|
|
70
|
-
CURRENT=$(cat "$PERSONALITY_FILE")
|
|
71
|
-
fi
|
|
72
|
-
|
|
73
|
-
# List personalities from markdown files
|
|
74
|
-
echo "Built-in personalities:"
|
|
75
|
-
for personality in $(list_personalities | sort); do
|
|
76
|
-
desc=$(get_personality_data "$personality" "description")
|
|
77
|
-
if [[ "$personality" == "$CURRENT" ]]; then
|
|
78
|
-
echo " ✓ $personality - $desc (current)"
|
|
79
|
-
else
|
|
80
|
-
echo " - $personality - $desc"
|
|
81
|
-
fi
|
|
82
|
-
done
|
|
83
|
-
|
|
84
|
-
# Add random option
|
|
85
|
-
if [[ "$CURRENT" == "random" ]]; then
|
|
86
|
-
echo " ✓ random - Picks randomly each time (current)"
|
|
87
|
-
else
|
|
88
|
-
echo " - random - Picks randomly each time"
|
|
89
|
-
fi
|
|
90
|
-
|
|
91
|
-
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
92
|
-
echo ""
|
|
93
|
-
echo "Usage: /agent-vibes:personality <name>"
|
|
94
|
-
echo " /agent-vibes:personality add <name>"
|
|
95
|
-
echo " /agent-vibes:personality edit <name>"
|
|
96
|
-
;;
|
|
97
|
-
|
|
98
|
-
set|switch)
|
|
99
|
-
PERSONALITY="$2"
|
|
100
|
-
|
|
101
|
-
if [[ -z "$PERSONALITY" ]]; then
|
|
102
|
-
echo "❌ Please specify a personality name"
|
|
103
|
-
echo "Usage: $0 set <personality>"
|
|
104
|
-
exit 1
|
|
105
|
-
fi
|
|
106
|
-
|
|
107
|
-
# Check if personality file exists (unless it's random)
|
|
108
|
-
if [[ "$PERSONALITY" != "random" ]]; then
|
|
109
|
-
if [[ ! -f "$PERSONALITIES_DIR/${PERSONALITY}.md" ]]; then
|
|
110
|
-
echo "❌ Personality not found: $PERSONALITY"
|
|
111
|
-
echo ""
|
|
112
|
-
echo "Available personalities:"
|
|
113
|
-
for p in $(list_personalities | sort); do
|
|
114
|
-
echo " • $p"
|
|
115
|
-
done
|
|
116
|
-
exit 1
|
|
117
|
-
fi
|
|
118
|
-
fi
|
|
119
|
-
|
|
120
|
-
# Save the personality
|
|
121
|
-
echo "$PERSONALITY" > "$PERSONALITY_FILE"
|
|
122
|
-
echo "🎭 Personality set to: $PERSONALITY"
|
|
123
|
-
|
|
124
|
-
# Check if personality has an assigned voice
|
|
125
|
-
ASSIGNED_VOICE=$(get_personality_data "$PERSONALITY" "voice")
|
|
126
|
-
if [[ -n "$ASSIGNED_VOICE" ]]; then
|
|
127
|
-
# Switch to the assigned voice (silently - personality will do the talking)
|
|
128
|
-
VOICE_MANAGER="$SCRIPT_DIR/voice-manager.sh"
|
|
129
|
-
if [[ -x "$VOICE_MANAGER" ]]; then
|
|
130
|
-
echo "🎤 Switching to assigned voice: $ASSIGNED_VOICE"
|
|
131
|
-
"$VOICE_MANAGER" switch "$ASSIGNED_VOICE" --silent >/dev/null 2>&1
|
|
132
|
-
fi
|
|
133
|
-
fi
|
|
134
|
-
|
|
135
|
-
# Make a personality-appropriate remark with TTS
|
|
136
|
-
if [[ "$PERSONALITY" != "random" ]]; then
|
|
137
|
-
echo ""
|
|
138
|
-
|
|
139
|
-
# Get TTS script path
|
|
140
|
-
TTS_SCRIPT="$SCRIPT_DIR/play-tts.sh"
|
|
141
|
-
|
|
142
|
-
# Try to get acknowledgment from personality file
|
|
143
|
-
PERSONALITY_FILE_PATH="$PERSONALITIES_DIR/${PERSONALITY}.md"
|
|
144
|
-
REMARK=""
|
|
145
|
-
|
|
146
|
-
if [[ -f "$PERSONALITY_FILE_PATH" ]]; then
|
|
147
|
-
# Extract example responses from personality file (lines starting with "- ")
|
|
148
|
-
mapfile -t EXAMPLES < <(grep '^- "' "$PERSONALITY_FILE_PATH" | sed 's/^- "//; s/"$//')
|
|
149
|
-
|
|
150
|
-
if [[ ${#EXAMPLES[@]} -gt 0 ]]; then
|
|
151
|
-
# Pick a random example
|
|
152
|
-
REMARK="${EXAMPLES[$RANDOM % ${#EXAMPLES[@]}]}"
|
|
153
|
-
fi
|
|
154
|
-
fi
|
|
155
|
-
|
|
156
|
-
# Fallback if no examples found
|
|
157
|
-
if [[ -z "$REMARK" ]]; then
|
|
158
|
-
REMARK="Personality set to ${PERSONALITY}!"
|
|
159
|
-
fi
|
|
160
|
-
|
|
161
|
-
echo "💬 $REMARK"
|
|
162
|
-
"$TTS_SCRIPT" "$REMARK"
|
|
163
|
-
|
|
164
|
-
echo ""
|
|
165
|
-
echo "Note: AI will generate unique ${PERSONALITY} responses - no fixed templates!"
|
|
166
|
-
fi
|
|
167
|
-
;;
|
|
168
|
-
|
|
169
|
-
get)
|
|
170
|
-
if [ -f "$PERSONALITY_FILE" ]; then
|
|
171
|
-
CURRENT=$(cat "$PERSONALITY_FILE")
|
|
172
|
-
echo "Current personality: $CURRENT"
|
|
173
|
-
|
|
174
|
-
if [[ "$CURRENT" != "random" ]]; then
|
|
175
|
-
desc=$(get_personality_data "$CURRENT" "description")
|
|
176
|
-
[[ -n "$desc" ]] && echo "Description: $desc"
|
|
177
|
-
fi
|
|
178
|
-
else
|
|
179
|
-
echo "Current personality: normal (default)"
|
|
180
|
-
fi
|
|
181
|
-
;;
|
|
182
|
-
|
|
183
|
-
add)
|
|
184
|
-
NAME="$2"
|
|
185
|
-
if [[ -z "$NAME" ]]; then
|
|
186
|
-
echo "❌ Please specify a personality name"
|
|
187
|
-
echo "Usage: $0 add <name>"
|
|
188
|
-
exit 1
|
|
189
|
-
fi
|
|
190
|
-
|
|
191
|
-
FILE="$PERSONALITIES_DIR/${NAME}.md"
|
|
192
|
-
if [[ -f "$FILE" ]]; then
|
|
193
|
-
echo "❌ Personality '$NAME' already exists"
|
|
194
|
-
echo "Use 'edit' to modify it"
|
|
195
|
-
exit 1
|
|
196
|
-
fi
|
|
197
|
-
|
|
198
|
-
# Create new personality file
|
|
199
|
-
cat > "$FILE" << 'EOF'
|
|
200
|
-
---
|
|
201
|
-
name: NAME
|
|
202
|
-
description: Custom personality
|
|
203
|
-
---
|
|
204
|
-
|
|
205
|
-
# NAME Personality
|
|
206
|
-
|
|
207
|
-
## Prefix
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
## Suffix
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
## AI Instructions
|
|
214
|
-
Describe how the AI should generate messages for this personality.
|
|
215
|
-
|
|
216
|
-
## Example Responses
|
|
217
|
-
- "Example response 1"
|
|
218
|
-
- "Example response 2"
|
|
219
|
-
EOF
|
|
220
|
-
|
|
221
|
-
# Replace NAME with actual name
|
|
222
|
-
sed -i "s/NAME/$NAME/g" "$FILE"
|
|
223
|
-
|
|
224
|
-
echo "✅ Created new personality: $NAME"
|
|
225
|
-
echo "📝 Edit the file: $FILE"
|
|
226
|
-
echo ""
|
|
227
|
-
echo "You can now customize:"
|
|
228
|
-
echo " • Prefix: Text before messages"
|
|
229
|
-
echo " • Suffix: Text after messages"
|
|
230
|
-
echo " • AI Instructions: How AI should speak"
|
|
231
|
-
echo " • Example Responses: Sample messages"
|
|
232
|
-
;;
|
|
233
|
-
|
|
234
|
-
edit)
|
|
235
|
-
NAME="$2"
|
|
236
|
-
if [[ -z "$NAME" ]]; then
|
|
237
|
-
echo "❌ Please specify a personality name"
|
|
238
|
-
echo "Usage: $0 edit <name>"
|
|
239
|
-
exit 1
|
|
240
|
-
fi
|
|
241
|
-
|
|
242
|
-
FILE="$PERSONALITIES_DIR/${NAME}.md"
|
|
243
|
-
if [[ ! -f "$FILE" ]]; then
|
|
244
|
-
echo "❌ Personality '$NAME' not found"
|
|
245
|
-
echo "Use 'add' to create it first"
|
|
246
|
-
exit 1
|
|
247
|
-
fi
|
|
248
|
-
|
|
249
|
-
echo "📝 Edit this file to customize the personality:"
|
|
250
|
-
echo "$FILE"
|
|
251
|
-
;;
|
|
252
|
-
|
|
253
|
-
reset)
|
|
254
|
-
echo "normal" > "$PERSONALITY_FILE"
|
|
255
|
-
echo "🎭 Personality reset to: normal"
|
|
256
|
-
;;
|
|
257
|
-
|
|
258
|
-
*)
|
|
259
|
-
# If a single argument is provided and it's not a command, treat it as "set <personality>"
|
|
260
|
-
if [[ -n "$1" ]] && [[ -f "$PERSONALITIES_DIR/${1}.md" || "$1" == "random" ]]; then
|
|
261
|
-
# Call set with the personality name
|
|
262
|
-
exec "$0" set "$1"
|
|
263
|
-
else
|
|
264
|
-
echo "AgentVibes Personality Manager"
|
|
265
|
-
echo ""
|
|
266
|
-
echo "Commands:"
|
|
267
|
-
echo " list - List all personalities"
|
|
268
|
-
echo " set/switch <name> - Set personality"
|
|
269
|
-
echo " add <name> - Create new personality"
|
|
270
|
-
echo " edit <name> - Show path to edit personality"
|
|
271
|
-
echo " get - Show current personality"
|
|
272
|
-
echo " reset - Reset to normal"
|
|
273
|
-
echo ""
|
|
274
|
-
echo "Examples:"
|
|
275
|
-
echo " /agent-vibes:personality flirty"
|
|
276
|
-
echo " /agent-vibes:personality add cowboy"
|
|
277
|
-
fi
|
|
278
|
-
;;
|
|
279
|
-
esac
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
#
|
|
3
|
-
# @fileoverview Piper Voice Model Downloader
|
|
4
|
-
# @context Downloads Piper TTS voice models from HuggingFace
|
|
5
|
-
# @purpose Batch download popular voices after installation
|
|
6
|
-
# @dependencies piper-voice-manager.sh, piper binary
|
|
7
|
-
# @usage ./piper-download-voices.sh [--yes|-y]
|
|
8
|
-
# --yes|-y: Skip confirmation prompt (auto-download)
|
|
9
|
-
#
|
|
10
|
-
|
|
11
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
12
|
-
source "$SCRIPT_DIR/piper-voice-manager.sh"
|
|
13
|
-
|
|
14
|
-
# Parse command line arguments
|
|
15
|
-
AUTO_YES=false
|
|
16
|
-
if [[ "$1" == "--yes" ]] || [[ "$1" == "-y" ]]; then
|
|
17
|
-
AUTO_YES=true
|
|
18
|
-
fi
|
|
19
|
-
|
|
20
|
-
# Common voice models to download
|
|
21
|
-
COMMON_VOICES=(
|
|
22
|
-
"en_US-lessac-medium" # Default, clear male
|
|
23
|
-
"en_US-amy-medium" # Warm female
|
|
24
|
-
"en_US-joe-medium" # Professional male
|
|
25
|
-
"en_US-ryan-high" # Expressive male
|
|
26
|
-
"en_US-libritts-high" # Premium quality
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
echo "🎙️ Piper Voice Model Downloader"
|
|
30
|
-
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
31
|
-
echo ""
|
|
32
|
-
echo "This will download the most commonly used Piper voice models."
|
|
33
|
-
echo "Each voice is approximately 25MB."
|
|
34
|
-
echo ""
|
|
35
|
-
|
|
36
|
-
# Check if piper is installed
|
|
37
|
-
if ! command -v piper &> /dev/null; then
|
|
38
|
-
echo "❌ Error: Piper TTS not installed"
|
|
39
|
-
echo "Install with: pipx install piper-tts"
|
|
40
|
-
exit 1
|
|
41
|
-
fi
|
|
42
|
-
|
|
43
|
-
# Get storage directory
|
|
44
|
-
VOICE_DIR=$(get_voice_storage_dir)
|
|
45
|
-
|
|
46
|
-
echo "📂 Storage location: $VOICE_DIR"
|
|
47
|
-
echo ""
|
|
48
|
-
|
|
49
|
-
# Count already downloaded
|
|
50
|
-
ALREADY_DOWNLOADED=0
|
|
51
|
-
ALREADY_DOWNLOADED_LIST=()
|
|
52
|
-
NEED_DOWNLOAD=()
|
|
53
|
-
|
|
54
|
-
for voice in "${COMMON_VOICES[@]}"; do
|
|
55
|
-
if verify_voice "$voice" 2>/dev/null; then
|
|
56
|
-
((ALREADY_DOWNLOADED++))
|
|
57
|
-
ALREADY_DOWNLOADED_LIST+=("$voice")
|
|
58
|
-
else
|
|
59
|
-
NEED_DOWNLOAD+=("$voice")
|
|
60
|
-
fi
|
|
61
|
-
done
|
|
62
|
-
|
|
63
|
-
echo "📊 Status:"
|
|
64
|
-
echo " Already downloaded: $ALREADY_DOWNLOADED voice(s)"
|
|
65
|
-
echo " Need to download: ${#NEED_DOWNLOAD[@]} voice(s)"
|
|
66
|
-
echo ""
|
|
67
|
-
|
|
68
|
-
# Show already downloaded voices
|
|
69
|
-
if [[ $ALREADY_DOWNLOADED -gt 0 ]]; then
|
|
70
|
-
echo "✅ Already downloaded (skipped):"
|
|
71
|
-
for voice in "${ALREADY_DOWNLOADED_LIST[@]}"; do
|
|
72
|
-
echo " ✓ $voice"
|
|
73
|
-
done
|
|
74
|
-
echo ""
|
|
75
|
-
fi
|
|
76
|
-
|
|
77
|
-
if [[ ${#NEED_DOWNLOAD[@]} -eq 0 ]]; then
|
|
78
|
-
echo "🎉 All common voices ready to use!"
|
|
79
|
-
exit 0
|
|
80
|
-
fi
|
|
81
|
-
|
|
82
|
-
echo "Voices to download:"
|
|
83
|
-
for voice in "${NEED_DOWNLOAD[@]}"; do
|
|
84
|
-
echo " • $voice (~25MB)"
|
|
85
|
-
done
|
|
86
|
-
echo ""
|
|
87
|
-
|
|
88
|
-
# Ask for confirmation (skip if --yes flag provided)
|
|
89
|
-
if [[ "$AUTO_YES" == "false" ]]; then
|
|
90
|
-
read -p "Download ${#NEED_DOWNLOAD[@]} voice model(s)? [Y/n]: " -n 1 -r
|
|
91
|
-
echo
|
|
92
|
-
|
|
93
|
-
if [[ ! $REPLY =~ ^[Yy]$ ]] && [[ -n $REPLY ]]; then
|
|
94
|
-
echo "❌ Download cancelled"
|
|
95
|
-
exit 0
|
|
96
|
-
fi
|
|
97
|
-
else
|
|
98
|
-
echo "Auto-downloading ${#NEED_DOWNLOAD[@]} voice model(s)..."
|
|
99
|
-
echo ""
|
|
100
|
-
fi
|
|
101
|
-
|
|
102
|
-
# Download each voice
|
|
103
|
-
DOWNLOADED=0
|
|
104
|
-
FAILED=0
|
|
105
|
-
|
|
106
|
-
for voice in "${NEED_DOWNLOAD[@]}"; do
|
|
107
|
-
echo ""
|
|
108
|
-
echo "📥 Downloading: $voice..."
|
|
109
|
-
|
|
110
|
-
if download_voice "$voice"; then
|
|
111
|
-
((DOWNLOADED++))
|
|
112
|
-
echo "✅ Downloaded: $voice"
|
|
113
|
-
else
|
|
114
|
-
((FAILED++))
|
|
115
|
-
echo "❌ Failed: $voice"
|
|
116
|
-
fi
|
|
117
|
-
done
|
|
118
|
-
|
|
119
|
-
echo ""
|
|
120
|
-
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
121
|
-
echo "📊 Download Summary:"
|
|
122
|
-
echo " ✅ Successfully downloaded: $DOWNLOADED"
|
|
123
|
-
echo " ❌ Failed: $FAILED"
|
|
124
|
-
echo " 📦 Total voices available: $((ALREADY_DOWNLOADED + DOWNLOADED))"
|
|
125
|
-
echo ""
|
|
126
|
-
|
|
127
|
-
if [[ $DOWNLOADED -gt 0 ]]; then
|
|
128
|
-
echo "✨ Ready to use Piper TTS with downloaded voices!"
|
|
129
|
-
echo ""
|
|
130
|
-
echo "Try it:"
|
|
131
|
-
echo " /agent-vibes:provider switch piper"
|
|
132
|
-
echo " /agent-vibes:preview"
|
|
133
|
-
fi
|
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
#
|
|
3
|
-
# @fileoverview Piper Voice Model Management
|
|
4
|
-
# @context Manages downloading, caching, and validating Piper ONNX voice models
|
|
5
|
-
# @architecture Voice model lifecycle management for Piper provider
|
|
6
|
-
# @dependencies curl, piper binary
|
|
7
|
-
# @entrypoints Sourced by play-tts-piper.sh and provider management commands
|
|
8
|
-
# @patterns HuggingFace model repository integration, file-based caching
|
|
9
|
-
# @related play-tts-piper.sh, provider-manager.sh, GitHub Issue #25
|
|
10
|
-
#
|
|
11
|
-
|
|
12
|
-
# Base URL for Piper voice models on HuggingFace
|
|
13
|
-
PIPER_VOICES_BASE_URL="https://huggingface.co/rhasspy/piper-voices/resolve/main"
|
|
14
|
-
|
|
15
|
-
# @function get_voice_storage_dir
|
|
16
|
-
# @intent Determine directory for storing Piper voice models
|
|
17
|
-
# @why Voice models are large (~25MB each) and should be shared globally across all projects
|
|
18
|
-
# @returns Echoes path to voice storage directory (~/.claude/piper-voices)
|
|
19
|
-
# @sideeffects Creates directory if it doesn't exist
|
|
20
|
-
# @architecture Supports custom path via PIPER_VOICES_DIR env var, defaults to global storage
|
|
21
|
-
get_voice_storage_dir() {
|
|
22
|
-
local voice_dir
|
|
23
|
-
|
|
24
|
-
# Check for custom path in environment or config file
|
|
25
|
-
if [[ -n "$PIPER_VOICES_DIR" ]]; then
|
|
26
|
-
voice_dir="$PIPER_VOICES_DIR"
|
|
27
|
-
else
|
|
28
|
-
# Check for config file (project-local first, then global)
|
|
29
|
-
local config_file
|
|
30
|
-
if [[ -n "$CLAUDE_PROJECT_DIR" ]] && [[ -f "$CLAUDE_PROJECT_DIR/.claude/piper-voices-dir.txt" ]]; then
|
|
31
|
-
config_file="$CLAUDE_PROJECT_DIR/.claude/piper-voices-dir.txt"
|
|
32
|
-
else
|
|
33
|
-
# Search up directory tree for .claude/
|
|
34
|
-
local current_dir="$PWD"
|
|
35
|
-
while [[ "$current_dir" != "/" ]]; do
|
|
36
|
-
if [[ -f "$current_dir/.claude/piper-voices-dir.txt" ]]; then
|
|
37
|
-
config_file="$current_dir/.claude/piper-voices-dir.txt"
|
|
38
|
-
break
|
|
39
|
-
fi
|
|
40
|
-
current_dir=$(dirname "$current_dir")
|
|
41
|
-
done
|
|
42
|
-
|
|
43
|
-
# Check global config
|
|
44
|
-
if [[ -z "$config_file" ]] && [[ -f "$HOME/.claude/piper-voices-dir.txt" ]]; then
|
|
45
|
-
config_file="$HOME/.claude/piper-voices-dir.txt"
|
|
46
|
-
fi
|
|
47
|
-
fi
|
|
48
|
-
|
|
49
|
-
if [[ -n "$config_file" ]]; then
|
|
50
|
-
voice_dir=$(cat "$config_file" | tr -d '[:space:]')
|
|
51
|
-
fi
|
|
52
|
-
fi
|
|
53
|
-
|
|
54
|
-
# Fallback to default global storage
|
|
55
|
-
if [[ -z "$voice_dir" ]]; then
|
|
56
|
-
voice_dir="$HOME/.claude/piper-voices"
|
|
57
|
-
fi
|
|
58
|
-
|
|
59
|
-
mkdir -p "$voice_dir"
|
|
60
|
-
echo "$voice_dir"
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
# @function verify_voice
|
|
64
|
-
# @intent Check if voice model files exist locally
|
|
65
|
-
# @why Avoid redundant downloads, detect missing models
|
|
66
|
-
# @param $1 {string} voice_name - Voice model name (e.g., en_US-lessac-medium)
|
|
67
|
-
# @returns None
|
|
68
|
-
# @exitcode 0=voice exists, 1=voice missing
|
|
69
|
-
# @sideeffects None
|
|
70
|
-
verify_voice() {
|
|
71
|
-
local voice_name="$1"
|
|
72
|
-
local voice_dir
|
|
73
|
-
voice_dir=$(get_voice_storage_dir)
|
|
74
|
-
|
|
75
|
-
local onnx_file="$voice_dir/${voice_name}.onnx"
|
|
76
|
-
local json_file="$voice_dir/${voice_name}.onnx.json"
|
|
77
|
-
|
|
78
|
-
[[ -f "$onnx_file" ]] && [[ -f "$json_file" ]]
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
# @function get_voice_path
|
|
82
|
-
# @intent Get absolute path to voice model ONNX file
|
|
83
|
-
# @why Piper binary requires full path to model file
|
|
84
|
-
# @param $1 {string} voice_name - Voice model name
|
|
85
|
-
# @returns Echoes path to .onnx file
|
|
86
|
-
# @exitcode 0=success, 1=voice not found
|
|
87
|
-
# @sideeffects None
|
|
88
|
-
get_voice_path() {
|
|
89
|
-
local voice_name="$1"
|
|
90
|
-
local voice_dir
|
|
91
|
-
voice_dir=$(get_voice_storage_dir)
|
|
92
|
-
|
|
93
|
-
local onnx_file="$voice_dir/${voice_name}.onnx"
|
|
94
|
-
|
|
95
|
-
if [[ ! -f "$onnx_file" ]]; then
|
|
96
|
-
echo "❌ Voice model not found: $voice_name" >&2
|
|
97
|
-
return 1
|
|
98
|
-
fi
|
|
99
|
-
|
|
100
|
-
echo "$onnx_file"
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
# @function parse_voice_components
|
|
104
|
-
# @intent Extract language, locale, speaker, quality from voice name
|
|
105
|
-
# @why HuggingFace uses directory structure: lang/locale/speaker/quality
|
|
106
|
-
# @param $1 {string} voice_name - Voice name (e.g., en_US-lessac-medium)
|
|
107
|
-
# @returns Sets global variables: LANG, LOCALE, SPEAKER, QUALITY
|
|
108
|
-
# @sideeffects Sets global variables
|
|
109
|
-
# AI NOTE: Voice name format is: lang_LOCALE-speaker-quality
|
|
110
|
-
parse_voice_components() {
|
|
111
|
-
local voice_name="$1"
|
|
112
|
-
|
|
113
|
-
# Extract components from voice name
|
|
114
|
-
# Format: en_US-lessac-medium
|
|
115
|
-
# lang_LOCALE-speaker-quality
|
|
116
|
-
|
|
117
|
-
local lang_locale="${voice_name%%-*}" # en_US
|
|
118
|
-
local speaker_quality="${voice_name#*-}" # lessac-medium
|
|
119
|
-
|
|
120
|
-
LANG="${lang_locale%%_*}" # en
|
|
121
|
-
LOCALE="${lang_locale#*_}" # US
|
|
122
|
-
SPEAKER="${speaker_quality%%-*}" # lessac
|
|
123
|
-
QUALITY="${speaker_quality#*-}" # medium
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
# @function download_voice
|
|
127
|
-
# @intent Download Piper voice model from HuggingFace
|
|
128
|
-
# @why Provide free offline TTS voices
|
|
129
|
-
# @param $1 {string} voice_name - Voice model name
|
|
130
|
-
# @param $2 {string} lang_code - Language code (optional, inferred from voice_name)
|
|
131
|
-
# @returns None
|
|
132
|
-
# @exitcode 0=success, 1=download failed
|
|
133
|
-
# @sideeffects Downloads .onnx and .onnx.json files
|
|
134
|
-
# @edgecases Handles network failures, validates file integrity
|
|
135
|
-
download_voice() {
|
|
136
|
-
local voice_name="$1"
|
|
137
|
-
local lang_code="${2:-}"
|
|
138
|
-
|
|
139
|
-
local voice_dir
|
|
140
|
-
voice_dir=$(get_voice_storage_dir)
|
|
141
|
-
|
|
142
|
-
# Check if already downloaded
|
|
143
|
-
if verify_voice "$voice_name"; then
|
|
144
|
-
echo "✅ Voice already downloaded: $voice_name"
|
|
145
|
-
return 0
|
|
146
|
-
fi
|
|
147
|
-
|
|
148
|
-
# Parse voice components
|
|
149
|
-
parse_voice_components "$voice_name"
|
|
150
|
-
|
|
151
|
-
# Construct download URLs
|
|
152
|
-
# Path format: {language}/{language}_{locale}/{speaker}/{quality}/{speaker}-{quality}.onnx
|
|
153
|
-
local model_path="${LANG}/${LANG}_${LOCALE}/${SPEAKER}/${QUALITY}/${voice_name}"
|
|
154
|
-
local onnx_url="${PIPER_VOICES_BASE_URL}/${model_path}.onnx"
|
|
155
|
-
local json_url="${PIPER_VOICES_BASE_URL}/${model_path}.onnx.json"
|
|
156
|
-
|
|
157
|
-
echo "📥 Downloading Piper voice: $voice_name"
|
|
158
|
-
echo " Source: HuggingFace (rhasspy/piper-voices)"
|
|
159
|
-
echo " Size: ~25MB"
|
|
160
|
-
echo ""
|
|
161
|
-
|
|
162
|
-
# Download ONNX model
|
|
163
|
-
echo " Downloading model file..."
|
|
164
|
-
if ! curl -L --progress-bar -o "$voice_dir/${voice_name}.onnx" "$onnx_url"; then
|
|
165
|
-
echo "❌ Failed to download voice model"
|
|
166
|
-
rm -f "$voice_dir/${voice_name}.onnx"
|
|
167
|
-
return 1
|
|
168
|
-
fi
|
|
169
|
-
|
|
170
|
-
# Download JSON config
|
|
171
|
-
echo " Downloading config file..."
|
|
172
|
-
if ! curl -L -s -o "$voice_dir/${voice_name}.onnx.json" "$json_url"; then
|
|
173
|
-
echo "❌ Failed to download voice config"
|
|
174
|
-
rm -f "$voice_dir/${voice_name}.onnx" "$voice_dir/${voice_name}.onnx.json"
|
|
175
|
-
return 1
|
|
176
|
-
fi
|
|
177
|
-
|
|
178
|
-
# Verify file integrity (basic check - file size > 0)
|
|
179
|
-
if [[ ! -s "$voice_dir/${voice_name}.onnx" ]]; then
|
|
180
|
-
echo "❌ Downloaded file is empty or corrupt"
|
|
181
|
-
rm -f "$voice_dir/${voice_name}.onnx" "$voice_dir/${voice_name}.onnx.json"
|
|
182
|
-
return 1
|
|
183
|
-
fi
|
|
184
|
-
|
|
185
|
-
echo "✅ Voice downloaded successfully: $voice_name"
|
|
186
|
-
echo " Location: $voice_dir/${voice_name}.onnx"
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
# @function list_downloaded_voices
|
|
190
|
-
# @intent Show all locally cached voice models
|
|
191
|
-
# @why Help users see what voices they have available
|
|
192
|
-
# @returns Echoes voice names (one per line)
|
|
193
|
-
# @exitcode 0=success
|
|
194
|
-
# @sideeffects None
|
|
195
|
-
list_downloaded_voices() {
|
|
196
|
-
local voice_dir
|
|
197
|
-
voice_dir=$(get_voice_storage_dir)
|
|
198
|
-
|
|
199
|
-
echo "📦 Downloaded Piper Voices:"
|
|
200
|
-
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
201
|
-
|
|
202
|
-
local count=0
|
|
203
|
-
shopt -s nullglob
|
|
204
|
-
for onnx_file in "$voice_dir"/*.onnx; do
|
|
205
|
-
if [[ -f "$onnx_file" ]]; then
|
|
206
|
-
local voice_name
|
|
207
|
-
voice_name=$(basename "$onnx_file" .onnx)
|
|
208
|
-
local file_size
|
|
209
|
-
file_size=$(du -h "$onnx_file" | cut -f1)
|
|
210
|
-
echo " • $voice_name ($file_size)"
|
|
211
|
-
((count++))
|
|
212
|
-
fi
|
|
213
|
-
done
|
|
214
|
-
shopt -u nullglob
|
|
215
|
-
|
|
216
|
-
if [[ $count -eq 0 ]]; then
|
|
217
|
-
echo " (No voices downloaded yet)"
|
|
218
|
-
fi
|
|
219
|
-
|
|
220
|
-
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
221
|
-
echo "Total: $count voices"
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
# AI NOTE: This file manages the lifecycle of Piper voice models
|
|
225
|
-
# Voice models are ONNX files (~20-30MB each) downloaded from HuggingFace
|
|
226
|
-
# Files are cached locally to avoid repeated downloads
|
|
227
|
-
# Project-local storage preferred over global for isolation
|