agentvibes 4.2.0 → 4.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +152 -79
- 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 +5882 -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 +132 -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,449 +1,449 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
#
|
|
3
|
-
# File: .claude/hooks/personality-manager.sh
|
|
4
|
-
#
|
|
5
|
-
# AgentVibes - Finally, your AI Agents can Talk Back! Text-to-Speech WITH personality for AI Assistants!
|
|
6
|
-
# Website: https://agentvibes.org
|
|
7
|
-
# Repository: https://github.com/paulpreibisch/AgentVibes
|
|
8
|
-
#
|
|
9
|
-
# Co-created by Paul Preibisch with Claude AI
|
|
10
|
-
# Copyright (c) 2025 Paul Preibisch
|
|
11
|
-
#
|
|
12
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
13
|
-
# you may not use this file except in compliance with the License.
|
|
14
|
-
# You may obtain a copy of the License at
|
|
15
|
-
#
|
|
16
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
17
|
-
#
|
|
18
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
19
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
20
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
21
|
-
# See the License for the specific language governing permissions and
|
|
22
|
-
# limitations under the License.
|
|
23
|
-
#
|
|
24
|
-
# DISCLAIMER: This software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
25
|
-
# express or implied. Use at your own risk. See the Apache License for details.
|
|
26
|
-
#
|
|
27
|
-
# ---
|
|
28
|
-
#
|
|
29
|
-
# @fileoverview Personality Manager - Adds character and emotional style to TTS voices
|
|
30
|
-
# @context Enables voices to have distinct personalities (flirty, sarcastic, pirate, etc.) with provider-aware voice assignment
|
|
31
|
-
# @architecture Markdown-based personality templates with provider-specific voice mappings (Piper vs macOS)
|
|
32
|
-
# @dependencies .claude/personalities/*.md files, voice-manager.sh, play-tts.sh, provider-manager.sh
|
|
33
|
-
# @entrypoints Called by /agent-vibes:personality slash commands
|
|
34
|
-
# @patterns Template-based configuration, provider abstraction, random personality support
|
|
35
|
-
# @related .claude/personalities/*.md, voice-manager.sh, .claude/tts-personality.txt
|
|
36
|
-
|
|
37
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
38
|
-
PERSONALITIES_DIR="$SCRIPT_DIR/../personalities"
|
|
39
|
-
|
|
40
|
-
# Determine target .claude directory based on context
|
|
41
|
-
# Priority:
|
|
42
|
-
# 1. CLAUDE_PROJECT_DIR env var (set by MCP for project-specific settings)
|
|
43
|
-
# 2. Script location (for direct slash command usage)
|
|
44
|
-
# 3. Global ~/.claude (fallback)
|
|
45
|
-
|
|
46
|
-
if [[ -n "$CLAUDE_PROJECT_DIR" ]] && [[ -d "$CLAUDE_PROJECT_DIR/.claude" ]]; then
|
|
47
|
-
# MCP context: Use the project directory where MCP was invoked
|
|
48
|
-
CLAUDE_DIR="$CLAUDE_PROJECT_DIR/.claude"
|
|
49
|
-
else
|
|
50
|
-
# Direct usage context: Use script location
|
|
51
|
-
# Script is at .claude/hooks/personality-manager.sh, so .claude is ..
|
|
52
|
-
CLAUDE_DIR="$(cd "$SCRIPT_DIR/.." 2>/dev/null && pwd)"
|
|
53
|
-
|
|
54
|
-
# If script is in global ~/.claude, use that
|
|
55
|
-
if [[ "$CLAUDE_DIR" == "$HOME/.claude" ]]; then
|
|
56
|
-
CLAUDE_DIR="$HOME/.claude"
|
|
57
|
-
elif [[ ! -d "$CLAUDE_DIR" ]]; then
|
|
58
|
-
# Fallback to global if directory doesn't exist
|
|
59
|
-
CLAUDE_DIR="$HOME/.claude"
|
|
60
|
-
fi
|
|
61
|
-
fi
|
|
62
|
-
|
|
63
|
-
PERSONALITY_FILE="$CLAUDE_DIR/tts-personality.txt"
|
|
64
|
-
|
|
65
|
-
# Function to get personality data from markdown file
|
|
66
|
-
get_personality_data() {
|
|
67
|
-
local personality="$1"
|
|
68
|
-
local field="$2"
|
|
69
|
-
local file="$PERSONALITIES_DIR/${personality}.md"
|
|
70
|
-
|
|
71
|
-
if [[ ! -f "$file" ]]; then
|
|
72
|
-
return 1
|
|
73
|
-
fi
|
|
74
|
-
|
|
75
|
-
case "$field" in
|
|
76
|
-
prefix)
|
|
77
|
-
sed -n '/^## Prefix/,/^##/p' "$file" | sed '1d;$d' | tr -d '\n' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'
|
|
78
|
-
;;
|
|
79
|
-
suffix)
|
|
80
|
-
sed -n '/^## Suffix/,/^##/p' "$file" | sed '1d;$d' | tr -d '\n' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'
|
|
81
|
-
;;
|
|
82
|
-
description)
|
|
83
|
-
grep "^description:" "$file" | cut -d: -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'
|
|
84
|
-
;;
|
|
85
|
-
voice)
|
|
86
|
-
grep "^piper_voice:" "$file" | cut -d: -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'
|
|
87
|
-
;;
|
|
88
|
-
piper_voice)
|
|
89
|
-
grep "^piper_voice:" "$file" | cut -d: -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'
|
|
90
|
-
;;
|
|
91
|
-
instructions)
|
|
92
|
-
sed -n '/^## AI Instructions/,/^##/p' "$file" | sed '1d;$d'
|
|
93
|
-
;;
|
|
94
|
-
esac
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
# Function to list all available personalities
|
|
98
|
-
list_personalities() {
|
|
99
|
-
local personalities=()
|
|
100
|
-
|
|
101
|
-
# Find all .md files in personalities directory
|
|
102
|
-
if [[ -d "$PERSONALITIES_DIR" ]]; then
|
|
103
|
-
for file in "$PERSONALITIES_DIR"/*.md; do
|
|
104
|
-
if [[ -f "$file" ]]; then
|
|
105
|
-
basename "$file" .md
|
|
106
|
-
fi
|
|
107
|
-
done
|
|
108
|
-
fi
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
case "$1" in
|
|
112
|
-
list)
|
|
113
|
-
# Get current personality
|
|
114
|
-
CURRENT="normal"
|
|
115
|
-
if [ -f "$PERSONALITY_FILE" ]; then
|
|
116
|
-
CURRENT=$(cat "$PERSONALITY_FILE")
|
|
117
|
-
fi
|
|
118
|
-
|
|
119
|
-
# Use Node.js formatter for beautiful boxen display
|
|
120
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
121
|
-
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
122
|
-
FORMATTER="$PROJECT_ROOT/src/cli/list-personalities.js"
|
|
123
|
-
|
|
124
|
-
# Use Node.js formatter if available
|
|
125
|
-
if [[ -f "$FORMATTER" ]] && command -v node &> /dev/null; then
|
|
126
|
-
node "$FORMATTER" "$PERSONALITIES_DIR" "$CURRENT"
|
|
127
|
-
else
|
|
128
|
-
# Fallback to plain text display
|
|
129
|
-
echo "🎭 Available Personalities:"
|
|
130
|
-
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
131
|
-
|
|
132
|
-
echo "Built-in personalities:"
|
|
133
|
-
for personality in $(list_personalities | sort); do
|
|
134
|
-
desc=$(get_personality_data "$personality" "description")
|
|
135
|
-
if [[ "$personality" == "$CURRENT" ]]; then
|
|
136
|
-
echo " ✓ $personality - $desc (current)"
|
|
137
|
-
else
|
|
138
|
-
echo " - $personality - $desc"
|
|
139
|
-
fi
|
|
140
|
-
done
|
|
141
|
-
|
|
142
|
-
# Add random option
|
|
143
|
-
if [[ "$CURRENT" == "random" ]]; then
|
|
144
|
-
echo " ✓ random - Picks randomly each time (current)"
|
|
145
|
-
else
|
|
146
|
-
echo " - random - Picks randomly each time"
|
|
147
|
-
fi
|
|
148
|
-
|
|
149
|
-
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
150
|
-
echo ""
|
|
151
|
-
echo "Usage: /agent-vibes:personality <name>"
|
|
152
|
-
echo " /agent-vibes:personality add <name>"
|
|
153
|
-
echo " /agent-vibes:personality edit <name>"
|
|
154
|
-
fi
|
|
155
|
-
;;
|
|
156
|
-
|
|
157
|
-
set|switch)
|
|
158
|
-
PERSONALITY="$2"
|
|
159
|
-
|
|
160
|
-
if [[ -z "$PERSONALITY" ]]; then
|
|
161
|
-
echo "❌ Please specify a personality name"
|
|
162
|
-
echo "Usage: $0 set <personality>"
|
|
163
|
-
exit 1
|
|
164
|
-
fi
|
|
165
|
-
|
|
166
|
-
# Check if personality file exists (unless it's random)
|
|
167
|
-
if [[ "$PERSONALITY" != "random" ]]; then
|
|
168
|
-
if [[ ! -f "$PERSONALITIES_DIR/${PERSONALITY}.md" ]]; then
|
|
169
|
-
echo "❌ Personality not found: $PERSONALITY"
|
|
170
|
-
echo ""
|
|
171
|
-
echo "Available personalities:"
|
|
172
|
-
for p in $(list_personalities | sort); do
|
|
173
|
-
echo " • $p"
|
|
174
|
-
done
|
|
175
|
-
exit 1
|
|
176
|
-
fi
|
|
177
|
-
fi
|
|
178
|
-
|
|
179
|
-
# Save the personality
|
|
180
|
-
echo "$PERSONALITY" > "$PERSONALITY_FILE"
|
|
181
|
-
echo "🎭 Personality set to: $PERSONALITY"
|
|
182
|
-
|
|
183
|
-
# Check if personality has an assigned voice
|
|
184
|
-
# Detect active TTS provider
|
|
185
|
-
PROVIDER_FILE=""
|
|
186
|
-
if [[ -f "$CLAUDE_DIR/tts-provider.txt" ]]; then
|
|
187
|
-
PROVIDER_FILE="$CLAUDE_DIR/tts-provider.txt"
|
|
188
|
-
elif [[ -f "$HOME/.claude/tts-provider.txt" ]]; then
|
|
189
|
-
PROVIDER_FILE="$HOME/.claude/tts-provider.txt"
|
|
190
|
-
fi
|
|
191
|
-
|
|
192
|
-
ACTIVE_PROVIDER="piper" # default
|
|
193
|
-
if [[ -n "$PROVIDER_FILE" ]]; then
|
|
194
|
-
ACTIVE_PROVIDER=$(cat "$PROVIDER_FILE")
|
|
195
|
-
fi
|
|
196
|
-
|
|
197
|
-
# Get the appropriate voice based on provider
|
|
198
|
-
ASSIGNED_VOICE=""
|
|
199
|
-
if [[ "$ACTIVE_PROVIDER" == "piper" ]]; then
|
|
200
|
-
# Try to get Piper-specific voice first
|
|
201
|
-
ASSIGNED_VOICE=$(get_personality_data "$PERSONALITY" "piper_voice")
|
|
202
|
-
if [[ -z "$ASSIGNED_VOICE" ]]; then
|
|
203
|
-
# Fallback to default Piper voice
|
|
204
|
-
ASSIGNED_VOICE="en_US-lessac-medium"
|
|
205
|
-
fi
|
|
206
|
-
else
|
|
207
|
-
# Use Piper voice (reads from piper_voice: field)
|
|
208
|
-
ASSIGNED_VOICE=$(get_personality_data "$PERSONALITY" "voice")
|
|
209
|
-
fi
|
|
210
|
-
|
|
211
|
-
if [[ -n "$ASSIGNED_VOICE" ]]; then
|
|
212
|
-
# Switch to the assigned voice (silently - personality will do the talking)
|
|
213
|
-
VOICE_MANAGER="$SCRIPT_DIR/voice-manager.sh"
|
|
214
|
-
if [[ -x "$VOICE_MANAGER" ]]; then
|
|
215
|
-
echo "🎤 Switching to assigned voice: $ASSIGNED_VOICE"
|
|
216
|
-
"$VOICE_MANAGER" switch "$ASSIGNED_VOICE" --silent >/dev/null 2>&1
|
|
217
|
-
fi
|
|
218
|
-
fi
|
|
219
|
-
|
|
220
|
-
# Make a personality-appropriate remark with TTS
|
|
221
|
-
if [[ "$PERSONALITY" != "random" ]]; then
|
|
222
|
-
echo ""
|
|
223
|
-
|
|
224
|
-
# Get TTS script path
|
|
225
|
-
TTS_SCRIPT="$SCRIPT_DIR/play-tts.sh"
|
|
226
|
-
|
|
227
|
-
# Try to get acknowledgment from personality file
|
|
228
|
-
PERSONALITY_FILE_PATH="$PERSONALITIES_DIR/${PERSONALITY}.md"
|
|
229
|
-
REMARK=""
|
|
230
|
-
|
|
231
|
-
if [[ -f "$PERSONALITY_FILE_PATH" ]]; then
|
|
232
|
-
# Extract example responses from personality file (lines starting with "- ")
|
|
233
|
-
mapfile -t EXAMPLES < <(grep '^- "' "$PERSONALITY_FILE_PATH" | sed 's/^- "//; s/"$//')
|
|
234
|
-
|
|
235
|
-
if [[ ${#EXAMPLES[@]} -gt 0 ]]; then
|
|
236
|
-
# Pick a random example
|
|
237
|
-
REMARK="${EXAMPLES[$RANDOM % ${#EXAMPLES[@]}]}"
|
|
238
|
-
fi
|
|
239
|
-
fi
|
|
240
|
-
|
|
241
|
-
# Fallback if no examples found
|
|
242
|
-
if [[ -z "$REMARK" ]]; then
|
|
243
|
-
REMARK="Personality set to ${PERSONALITY}!"
|
|
244
|
-
fi
|
|
245
|
-
|
|
246
|
-
echo "💬 $REMARK"
|
|
247
|
-
"$TTS_SCRIPT" "$REMARK"
|
|
248
|
-
|
|
249
|
-
echo ""
|
|
250
|
-
echo "Note: AI will generate unique ${PERSONALITY} responses - no fixed templates!"
|
|
251
|
-
echo ""
|
|
252
|
-
echo "💡 Tip: To hear automatic TTS narration, enable the Agent Vibes output style:"
|
|
253
|
-
echo " /output-style Agent Vibes"
|
|
254
|
-
fi
|
|
255
|
-
;;
|
|
256
|
-
|
|
257
|
-
get)
|
|
258
|
-
if [ -f "$PERSONALITY_FILE" ]; then
|
|
259
|
-
CURRENT=$(cat "$PERSONALITY_FILE")
|
|
260
|
-
echo "Current personality: $CURRENT"
|
|
261
|
-
|
|
262
|
-
if [[ "$CURRENT" != "random" ]]; then
|
|
263
|
-
desc=$(get_personality_data "$CURRENT" "description")
|
|
264
|
-
[[ -n "$desc" ]] && echo "Description: $desc"
|
|
265
|
-
fi
|
|
266
|
-
else
|
|
267
|
-
echo "Current personality: normal (default)"
|
|
268
|
-
fi
|
|
269
|
-
;;
|
|
270
|
-
|
|
271
|
-
add)
|
|
272
|
-
NAME="$2"
|
|
273
|
-
if [[ -z "$NAME" ]]; then
|
|
274
|
-
echo "❌ Please specify a personality name"
|
|
275
|
-
echo "Usage: $0 add <name>"
|
|
276
|
-
exit 1
|
|
277
|
-
fi
|
|
278
|
-
|
|
279
|
-
FILE="$PERSONALITIES_DIR/${NAME}.md"
|
|
280
|
-
if [[ -f "$FILE" ]]; then
|
|
281
|
-
echo "❌ Personality '$NAME' already exists"
|
|
282
|
-
echo "Use 'edit' to modify it"
|
|
283
|
-
exit 1
|
|
284
|
-
fi
|
|
285
|
-
|
|
286
|
-
# Create new personality file
|
|
287
|
-
cat > "$FILE" << 'EOF'
|
|
288
|
-
---
|
|
289
|
-
name: NAME
|
|
290
|
-
description: Custom personality
|
|
291
|
-
---
|
|
292
|
-
|
|
293
|
-
# NAME Personality
|
|
294
|
-
|
|
295
|
-
## Prefix
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
## Suffix
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
## AI Instructions
|
|
302
|
-
Describe how the AI should generate messages for this personality.
|
|
303
|
-
|
|
304
|
-
## Example Responses
|
|
305
|
-
- "Example response 1"
|
|
306
|
-
- "Example response 2"
|
|
307
|
-
EOF
|
|
308
|
-
|
|
309
|
-
# Replace NAME with actual name
|
|
310
|
-
sed -i "s/NAME/$NAME/g" "$FILE"
|
|
311
|
-
|
|
312
|
-
echo "✅ Created new personality: $NAME"
|
|
313
|
-
echo "📝 Edit the file: $FILE"
|
|
314
|
-
echo ""
|
|
315
|
-
echo "You can now customize:"
|
|
316
|
-
echo " • Prefix: Text before messages"
|
|
317
|
-
echo " • Suffix: Text after messages"
|
|
318
|
-
echo " • AI Instructions: How AI should speak"
|
|
319
|
-
echo " • Example Responses: Sample messages"
|
|
320
|
-
;;
|
|
321
|
-
|
|
322
|
-
edit)
|
|
323
|
-
NAME="$2"
|
|
324
|
-
if [[ -z "$NAME" ]]; then
|
|
325
|
-
echo "❌ Please specify a personality name"
|
|
326
|
-
echo "Usage: $0 edit <name>"
|
|
327
|
-
exit 1
|
|
328
|
-
fi
|
|
329
|
-
|
|
330
|
-
FILE="$PERSONALITIES_DIR/${NAME}.md"
|
|
331
|
-
if [[ ! -f "$FILE" ]]; then
|
|
332
|
-
echo "❌ Personality '$NAME' not found"
|
|
333
|
-
echo "Use 'add' to create it first"
|
|
334
|
-
exit 1
|
|
335
|
-
fi
|
|
336
|
-
|
|
337
|
-
echo "📝 Edit this file to customize the personality:"
|
|
338
|
-
echo "$FILE"
|
|
339
|
-
;;
|
|
340
|
-
|
|
341
|
-
reset)
|
|
342
|
-
echo "normal" > "$PERSONALITY_FILE"
|
|
343
|
-
echo "🎭 Personality reset to: normal"
|
|
344
|
-
;;
|
|
345
|
-
|
|
346
|
-
set-favorite-voice)
|
|
347
|
-
PERSONALITY="$2"
|
|
348
|
-
NEW_VOICE="$3"
|
|
349
|
-
|
|
350
|
-
if [[ -z "$PERSONALITY" ]] || [[ -z "$NEW_VOICE" ]]; then
|
|
351
|
-
echo "❌ Please specify both personality name and voice name"
|
|
352
|
-
echo "Usage: $0 set-favorite-voice <personality> <voice>"
|
|
353
|
-
exit 1
|
|
354
|
-
fi
|
|
355
|
-
|
|
356
|
-
FILE="$PERSONALITIES_DIR/${PERSONALITY}.md"
|
|
357
|
-
if [[ ! -f "$FILE" ]]; then
|
|
358
|
-
echo "❌ Personality '$PERSONALITY' not found"
|
|
359
|
-
exit 1
|
|
360
|
-
fi
|
|
361
|
-
|
|
362
|
-
# Detect active TTS provider
|
|
363
|
-
PROVIDER_FILE=""
|
|
364
|
-
if [[ -f "$CLAUDE_DIR/tts-provider.txt" ]]; then
|
|
365
|
-
PROVIDER_FILE="$CLAUDE_DIR/tts-provider.txt"
|
|
366
|
-
elif [[ -f "$HOME/.claude/tts-provider.txt" ]]; then
|
|
367
|
-
PROVIDER_FILE="$HOME/.claude/tts-provider.txt"
|
|
368
|
-
fi
|
|
369
|
-
|
|
370
|
-
ACTIVE_PROVIDER="piper" # default
|
|
371
|
-
if [[ -n "$PROVIDER_FILE" ]]; then
|
|
372
|
-
ACTIVE_PROVIDER=$(cat "$PROVIDER_FILE")
|
|
373
|
-
fi
|
|
374
|
-
|
|
375
|
-
# Determine which field to update based on provider
|
|
376
|
-
if [[ "$ACTIVE_PROVIDER" == "piper" ]]; then
|
|
377
|
-
VOICE_FIELD="piper_voice"
|
|
378
|
-
CURRENT_VOICE=$(get_personality_data "$PERSONALITY" "piper_voice")
|
|
379
|
-
else
|
|
380
|
-
# macOS or other provider
|
|
381
|
-
VOICE_FIELD="macos_voice"
|
|
382
|
-
CURRENT_VOICE=$(get_personality_data "$PERSONALITY" "macos_voice")
|
|
383
|
-
fi
|
|
384
|
-
|
|
385
|
-
# Check if personality already has a favorite voice assigned
|
|
386
|
-
if [[ -n "$CURRENT_VOICE" ]] && [[ "$CURRENT_VOICE" != "$NEW_VOICE" ]]; then
|
|
387
|
-
echo "⚠️ WARNING: Personality '$PERSONALITY' already has a favorite voice assigned!"
|
|
388
|
-
echo ""
|
|
389
|
-
echo " Current favorite ($ACTIVE_PROVIDER): $CURRENT_VOICE"
|
|
390
|
-
echo " New voice: $NEW_VOICE"
|
|
391
|
-
echo ""
|
|
392
|
-
echo "Do you want to replace the favorite voice?"
|
|
393
|
-
echo ""
|
|
394
|
-
read -p "Enter your choice (yes/no): " CHOICE
|
|
395
|
-
|
|
396
|
-
case "$CHOICE" in
|
|
397
|
-
yes|y|YES|Y)
|
|
398
|
-
echo "✅ Replacing favorite voice..."
|
|
399
|
-
;;
|
|
400
|
-
no|n|NO|N)
|
|
401
|
-
echo "❌ Keeping current favorite voice: $CURRENT_VOICE"
|
|
402
|
-
exit 0
|
|
403
|
-
;;
|
|
404
|
-
*)
|
|
405
|
-
echo "❌ Invalid choice. Keeping current favorite voice: $CURRENT_VOICE"
|
|
406
|
-
exit 1
|
|
407
|
-
;;
|
|
408
|
-
esac
|
|
409
|
-
fi
|
|
410
|
-
|
|
411
|
-
# Update the voice in the personality file
|
|
412
|
-
if grep -q "^${VOICE_FIELD}:" "$FILE"; then
|
|
413
|
-
# Field exists, replace it
|
|
414
|
-
sed -i "s/^${VOICE_FIELD}:.*/${VOICE_FIELD}: ${NEW_VOICE}/" "$FILE"
|
|
415
|
-
else
|
|
416
|
-
# Field doesn't exist, add it after the frontmatter
|
|
417
|
-
sed -i "/^---$/,/^---$/ { /^---$/a\\
|
|
418
|
-
${VOICE_FIELD}: ${NEW_VOICE}
|
|
419
|
-
}" "$FILE"
|
|
420
|
-
fi
|
|
421
|
-
|
|
422
|
-
echo "✅ Favorite voice for '$PERSONALITY' personality set to: $NEW_VOICE ($ACTIVE_PROVIDER)"
|
|
423
|
-
echo "📝 Updated file: $FILE"
|
|
424
|
-
;;
|
|
425
|
-
|
|
426
|
-
*)
|
|
427
|
-
# If a single argument is provided and it's not a command, treat it as "set <personality>"
|
|
428
|
-
if [[ -n "$1" ]] && [[ -f "$PERSONALITIES_DIR/${1}.md" || "$1" == "random" ]]; then
|
|
429
|
-
# Call set with the personality name
|
|
430
|
-
exec "$0" set "$1"
|
|
431
|
-
else
|
|
432
|
-
echo "AgentVibes Personality Manager"
|
|
433
|
-
echo ""
|
|
434
|
-
echo "Commands:"
|
|
435
|
-
echo " list - List all personalities"
|
|
436
|
-
echo " set/switch <name> - Set personality"
|
|
437
|
-
echo " add <name> - Create new personality"
|
|
438
|
-
echo " edit <name> - Show path to edit personality"
|
|
439
|
-
echo " get - Show current personality"
|
|
440
|
-
echo " set-favorite-voice <name> <voice> - Set favorite voice for a personality"
|
|
441
|
-
echo " reset - Reset to normal"
|
|
442
|
-
echo ""
|
|
443
|
-
echo "Examples:"
|
|
444
|
-
echo " /agent-vibes:personality flirty"
|
|
445
|
-
echo " /agent-vibes:personality add cowboy"
|
|
446
|
-
echo " /agent-vibes:personality set-favorite-voice flirty \"Aria\""
|
|
447
|
-
fi
|
|
448
|
-
;;
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# File: .claude/hooks/personality-manager.sh
|
|
4
|
+
#
|
|
5
|
+
# AgentVibes - Finally, your AI Agents can Talk Back! Text-to-Speech WITH personality for AI Assistants!
|
|
6
|
+
# Website: https://agentvibes.org
|
|
7
|
+
# Repository: https://github.com/paulpreibisch/AgentVibes
|
|
8
|
+
#
|
|
9
|
+
# Co-created by Paul Preibisch with Claude AI
|
|
10
|
+
# Copyright (c) 2025 Paul Preibisch
|
|
11
|
+
#
|
|
12
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
13
|
+
# you may not use this file except in compliance with the License.
|
|
14
|
+
# You may obtain a copy of the License at
|
|
15
|
+
#
|
|
16
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
17
|
+
#
|
|
18
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
19
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
20
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
21
|
+
# See the License for the specific language governing permissions and
|
|
22
|
+
# limitations under the License.
|
|
23
|
+
#
|
|
24
|
+
# DISCLAIMER: This software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
25
|
+
# express or implied. Use at your own risk. See the Apache License for details.
|
|
26
|
+
#
|
|
27
|
+
# ---
|
|
28
|
+
#
|
|
29
|
+
# @fileoverview Personality Manager - Adds character and emotional style to TTS voices
|
|
30
|
+
# @context Enables voices to have distinct personalities (flirty, sarcastic, pirate, etc.) with provider-aware voice assignment
|
|
31
|
+
# @architecture Markdown-based personality templates with provider-specific voice mappings (Piper vs macOS)
|
|
32
|
+
# @dependencies .claude/personalities/*.md files, voice-manager.sh, play-tts.sh, provider-manager.sh
|
|
33
|
+
# @entrypoints Called by /agent-vibes:personality slash commands
|
|
34
|
+
# @patterns Template-based configuration, provider abstraction, random personality support
|
|
35
|
+
# @related .claude/personalities/*.md, voice-manager.sh, .claude/tts-personality.txt
|
|
36
|
+
|
|
37
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
38
|
+
PERSONALITIES_DIR="$SCRIPT_DIR/../personalities"
|
|
39
|
+
|
|
40
|
+
# Determine target .claude directory based on context
|
|
41
|
+
# Priority:
|
|
42
|
+
# 1. CLAUDE_PROJECT_DIR env var (set by MCP for project-specific settings)
|
|
43
|
+
# 2. Script location (for direct slash command usage)
|
|
44
|
+
# 3. Global ~/.claude (fallback)
|
|
45
|
+
|
|
46
|
+
if [[ -n "$CLAUDE_PROJECT_DIR" ]] && [[ -d "$CLAUDE_PROJECT_DIR/.claude" ]]; then
|
|
47
|
+
# MCP context: Use the project directory where MCP was invoked
|
|
48
|
+
CLAUDE_DIR="$CLAUDE_PROJECT_DIR/.claude"
|
|
49
|
+
else
|
|
50
|
+
# Direct usage context: Use script location
|
|
51
|
+
# Script is at .claude/hooks/personality-manager.sh, so .claude is ..
|
|
52
|
+
CLAUDE_DIR="$(cd "$SCRIPT_DIR/.." 2>/dev/null && pwd)"
|
|
53
|
+
|
|
54
|
+
# If script is in global ~/.claude, use that
|
|
55
|
+
if [[ "$CLAUDE_DIR" == "$HOME/.claude" ]]; then
|
|
56
|
+
CLAUDE_DIR="$HOME/.claude"
|
|
57
|
+
elif [[ ! -d "$CLAUDE_DIR" ]]; then
|
|
58
|
+
# Fallback to global if directory doesn't exist
|
|
59
|
+
CLAUDE_DIR="$HOME/.claude"
|
|
60
|
+
fi
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
PERSONALITY_FILE="$CLAUDE_DIR/tts-personality.txt"
|
|
64
|
+
|
|
65
|
+
# Function to get personality data from markdown file
|
|
66
|
+
get_personality_data() {
|
|
67
|
+
local personality="$1"
|
|
68
|
+
local field="$2"
|
|
69
|
+
local file="$PERSONALITIES_DIR/${personality}.md"
|
|
70
|
+
|
|
71
|
+
if [[ ! -f "$file" ]]; then
|
|
72
|
+
return 1
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
case "$field" in
|
|
76
|
+
prefix)
|
|
77
|
+
sed -n '/^## Prefix/,/^##/p' "$file" | sed '1d;$d' | tr -d '\n' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'
|
|
78
|
+
;;
|
|
79
|
+
suffix)
|
|
80
|
+
sed -n '/^## Suffix/,/^##/p' "$file" | sed '1d;$d' | tr -d '\n' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'
|
|
81
|
+
;;
|
|
82
|
+
description)
|
|
83
|
+
grep "^description:" "$file" | cut -d: -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'
|
|
84
|
+
;;
|
|
85
|
+
voice)
|
|
86
|
+
grep "^piper_voice:" "$file" | cut -d: -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'
|
|
87
|
+
;;
|
|
88
|
+
piper_voice)
|
|
89
|
+
grep "^piper_voice:" "$file" | cut -d: -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'
|
|
90
|
+
;;
|
|
91
|
+
instructions)
|
|
92
|
+
sed -n '/^## AI Instructions/,/^##/p' "$file" | sed '1d;$d'
|
|
93
|
+
;;
|
|
94
|
+
esac
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
# Function to list all available personalities
|
|
98
|
+
list_personalities() {
|
|
99
|
+
local personalities=()
|
|
100
|
+
|
|
101
|
+
# Find all .md files in personalities directory
|
|
102
|
+
if [[ -d "$PERSONALITIES_DIR" ]]; then
|
|
103
|
+
for file in "$PERSONALITIES_DIR"/*.md; do
|
|
104
|
+
if [[ -f "$file" ]]; then
|
|
105
|
+
basename "$file" .md
|
|
106
|
+
fi
|
|
107
|
+
done
|
|
108
|
+
fi
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
case "$1" in
|
|
112
|
+
list)
|
|
113
|
+
# Get current personality
|
|
114
|
+
CURRENT="normal"
|
|
115
|
+
if [ -f "$PERSONALITY_FILE" ]; then
|
|
116
|
+
CURRENT=$(cat "$PERSONALITY_FILE")
|
|
117
|
+
fi
|
|
118
|
+
|
|
119
|
+
# Use Node.js formatter for beautiful boxen display
|
|
120
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
121
|
+
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
122
|
+
FORMATTER="$PROJECT_ROOT/src/cli/list-personalities.js"
|
|
123
|
+
|
|
124
|
+
# Use Node.js formatter if available
|
|
125
|
+
if [[ -f "$FORMATTER" ]] && command -v node &> /dev/null; then
|
|
126
|
+
node "$FORMATTER" "$PERSONALITIES_DIR" "$CURRENT"
|
|
127
|
+
else
|
|
128
|
+
# Fallback to plain text display
|
|
129
|
+
echo "🎭 Available Personalities:"
|
|
130
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
131
|
+
|
|
132
|
+
echo "Built-in personalities:"
|
|
133
|
+
for personality in $(list_personalities | sort); do
|
|
134
|
+
desc=$(get_personality_data "$personality" "description")
|
|
135
|
+
if [[ "$personality" == "$CURRENT" ]]; then
|
|
136
|
+
echo " ✓ $personality - $desc (current)"
|
|
137
|
+
else
|
|
138
|
+
echo " - $personality - $desc"
|
|
139
|
+
fi
|
|
140
|
+
done
|
|
141
|
+
|
|
142
|
+
# Add random option
|
|
143
|
+
if [[ "$CURRENT" == "random" ]]; then
|
|
144
|
+
echo " ✓ random - Picks randomly each time (current)"
|
|
145
|
+
else
|
|
146
|
+
echo " - random - Picks randomly each time"
|
|
147
|
+
fi
|
|
148
|
+
|
|
149
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
150
|
+
echo ""
|
|
151
|
+
echo "Usage: /agent-vibes:personality <name>"
|
|
152
|
+
echo " /agent-vibes:personality add <name>"
|
|
153
|
+
echo " /agent-vibes:personality edit <name>"
|
|
154
|
+
fi
|
|
155
|
+
;;
|
|
156
|
+
|
|
157
|
+
set|switch)
|
|
158
|
+
PERSONALITY="$2"
|
|
159
|
+
|
|
160
|
+
if [[ -z "$PERSONALITY" ]]; then
|
|
161
|
+
echo "❌ Please specify a personality name"
|
|
162
|
+
echo "Usage: $0 set <personality>"
|
|
163
|
+
exit 1
|
|
164
|
+
fi
|
|
165
|
+
|
|
166
|
+
# Check if personality file exists (unless it's random)
|
|
167
|
+
if [[ "$PERSONALITY" != "random" ]]; then
|
|
168
|
+
if [[ ! -f "$PERSONALITIES_DIR/${PERSONALITY}.md" ]]; then
|
|
169
|
+
echo "❌ Personality not found: $PERSONALITY"
|
|
170
|
+
echo ""
|
|
171
|
+
echo "Available personalities:"
|
|
172
|
+
for p in $(list_personalities | sort); do
|
|
173
|
+
echo " • $p"
|
|
174
|
+
done
|
|
175
|
+
exit 1
|
|
176
|
+
fi
|
|
177
|
+
fi
|
|
178
|
+
|
|
179
|
+
# Save the personality
|
|
180
|
+
echo "$PERSONALITY" > "$PERSONALITY_FILE"
|
|
181
|
+
echo "🎭 Personality set to: $PERSONALITY"
|
|
182
|
+
|
|
183
|
+
# Check if personality has an assigned voice
|
|
184
|
+
# Detect active TTS provider
|
|
185
|
+
PROVIDER_FILE=""
|
|
186
|
+
if [[ -f "$CLAUDE_DIR/tts-provider.txt" ]]; then
|
|
187
|
+
PROVIDER_FILE="$CLAUDE_DIR/tts-provider.txt"
|
|
188
|
+
elif [[ -f "$HOME/.claude/tts-provider.txt" ]]; then
|
|
189
|
+
PROVIDER_FILE="$HOME/.claude/tts-provider.txt"
|
|
190
|
+
fi
|
|
191
|
+
|
|
192
|
+
ACTIVE_PROVIDER="piper" # default
|
|
193
|
+
if [[ -n "$PROVIDER_FILE" ]]; then
|
|
194
|
+
ACTIVE_PROVIDER=$(cat "$PROVIDER_FILE")
|
|
195
|
+
fi
|
|
196
|
+
|
|
197
|
+
# Get the appropriate voice based on provider
|
|
198
|
+
ASSIGNED_VOICE=""
|
|
199
|
+
if [[ "$ACTIVE_PROVIDER" == "piper" ]]; then
|
|
200
|
+
# Try to get Piper-specific voice first
|
|
201
|
+
ASSIGNED_VOICE=$(get_personality_data "$PERSONALITY" "piper_voice")
|
|
202
|
+
if [[ -z "$ASSIGNED_VOICE" ]]; then
|
|
203
|
+
# Fallback to default Piper voice
|
|
204
|
+
ASSIGNED_VOICE="en_US-lessac-medium"
|
|
205
|
+
fi
|
|
206
|
+
else
|
|
207
|
+
# Use Piper voice (reads from piper_voice: field)
|
|
208
|
+
ASSIGNED_VOICE=$(get_personality_data "$PERSONALITY" "voice")
|
|
209
|
+
fi
|
|
210
|
+
|
|
211
|
+
if [[ -n "$ASSIGNED_VOICE" ]]; then
|
|
212
|
+
# Switch to the assigned voice (silently - personality will do the talking)
|
|
213
|
+
VOICE_MANAGER="$SCRIPT_DIR/voice-manager.sh"
|
|
214
|
+
if [[ -x "$VOICE_MANAGER" ]]; then
|
|
215
|
+
echo "🎤 Switching to assigned voice: $ASSIGNED_VOICE"
|
|
216
|
+
"$VOICE_MANAGER" switch "$ASSIGNED_VOICE" --silent >/dev/null 2>&1
|
|
217
|
+
fi
|
|
218
|
+
fi
|
|
219
|
+
|
|
220
|
+
# Make a personality-appropriate remark with TTS
|
|
221
|
+
if [[ "$PERSONALITY" != "random" ]]; then
|
|
222
|
+
echo ""
|
|
223
|
+
|
|
224
|
+
# Get TTS script path
|
|
225
|
+
TTS_SCRIPT="$SCRIPT_DIR/play-tts.sh"
|
|
226
|
+
|
|
227
|
+
# Try to get acknowledgment from personality file
|
|
228
|
+
PERSONALITY_FILE_PATH="$PERSONALITIES_DIR/${PERSONALITY}.md"
|
|
229
|
+
REMARK=""
|
|
230
|
+
|
|
231
|
+
if [[ -f "$PERSONALITY_FILE_PATH" ]]; then
|
|
232
|
+
# Extract example responses from personality file (lines starting with "- ")
|
|
233
|
+
mapfile -t EXAMPLES < <(grep '^- "' "$PERSONALITY_FILE_PATH" | sed 's/^- "//; s/"$//')
|
|
234
|
+
|
|
235
|
+
if [[ ${#EXAMPLES[@]} -gt 0 ]]; then
|
|
236
|
+
# Pick a random example
|
|
237
|
+
REMARK="${EXAMPLES[$RANDOM % ${#EXAMPLES[@]}]}"
|
|
238
|
+
fi
|
|
239
|
+
fi
|
|
240
|
+
|
|
241
|
+
# Fallback if no examples found
|
|
242
|
+
if [[ -z "$REMARK" ]]; then
|
|
243
|
+
REMARK="Personality set to ${PERSONALITY}!"
|
|
244
|
+
fi
|
|
245
|
+
|
|
246
|
+
echo "💬 $REMARK"
|
|
247
|
+
"$TTS_SCRIPT" "$REMARK"
|
|
248
|
+
|
|
249
|
+
echo ""
|
|
250
|
+
echo "Note: AI will generate unique ${PERSONALITY} responses - no fixed templates!"
|
|
251
|
+
echo ""
|
|
252
|
+
echo "💡 Tip: To hear automatic TTS narration, enable the Agent Vibes output style:"
|
|
253
|
+
echo " /output-style Agent Vibes"
|
|
254
|
+
fi
|
|
255
|
+
;;
|
|
256
|
+
|
|
257
|
+
get)
|
|
258
|
+
if [ -f "$PERSONALITY_FILE" ]; then
|
|
259
|
+
CURRENT=$(cat "$PERSONALITY_FILE")
|
|
260
|
+
echo "Current personality: $CURRENT"
|
|
261
|
+
|
|
262
|
+
if [[ "$CURRENT" != "random" ]]; then
|
|
263
|
+
desc=$(get_personality_data "$CURRENT" "description")
|
|
264
|
+
[[ -n "$desc" ]] && echo "Description: $desc"
|
|
265
|
+
fi
|
|
266
|
+
else
|
|
267
|
+
echo "Current personality: normal (default)"
|
|
268
|
+
fi
|
|
269
|
+
;;
|
|
270
|
+
|
|
271
|
+
add)
|
|
272
|
+
NAME="$2"
|
|
273
|
+
if [[ -z "$NAME" ]]; then
|
|
274
|
+
echo "❌ Please specify a personality name"
|
|
275
|
+
echo "Usage: $0 add <name>"
|
|
276
|
+
exit 1
|
|
277
|
+
fi
|
|
278
|
+
|
|
279
|
+
FILE="$PERSONALITIES_DIR/${NAME}.md"
|
|
280
|
+
if [[ -f "$FILE" ]]; then
|
|
281
|
+
echo "❌ Personality '$NAME' already exists"
|
|
282
|
+
echo "Use 'edit' to modify it"
|
|
283
|
+
exit 1
|
|
284
|
+
fi
|
|
285
|
+
|
|
286
|
+
# Create new personality file
|
|
287
|
+
cat > "$FILE" << 'EOF'
|
|
288
|
+
---
|
|
289
|
+
name: NAME
|
|
290
|
+
description: Custom personality
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
# NAME Personality
|
|
294
|
+
|
|
295
|
+
## Prefix
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
## Suffix
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
## AI Instructions
|
|
302
|
+
Describe how the AI should generate messages for this personality.
|
|
303
|
+
|
|
304
|
+
## Example Responses
|
|
305
|
+
- "Example response 1"
|
|
306
|
+
- "Example response 2"
|
|
307
|
+
EOF
|
|
308
|
+
|
|
309
|
+
# Replace NAME with actual name
|
|
310
|
+
sed -i "s/NAME/$NAME/g" "$FILE"
|
|
311
|
+
|
|
312
|
+
echo "✅ Created new personality: $NAME"
|
|
313
|
+
echo "📝 Edit the file: $FILE"
|
|
314
|
+
echo ""
|
|
315
|
+
echo "You can now customize:"
|
|
316
|
+
echo " • Prefix: Text before messages"
|
|
317
|
+
echo " • Suffix: Text after messages"
|
|
318
|
+
echo " • AI Instructions: How AI should speak"
|
|
319
|
+
echo " • Example Responses: Sample messages"
|
|
320
|
+
;;
|
|
321
|
+
|
|
322
|
+
edit)
|
|
323
|
+
NAME="$2"
|
|
324
|
+
if [[ -z "$NAME" ]]; then
|
|
325
|
+
echo "❌ Please specify a personality name"
|
|
326
|
+
echo "Usage: $0 edit <name>"
|
|
327
|
+
exit 1
|
|
328
|
+
fi
|
|
329
|
+
|
|
330
|
+
FILE="$PERSONALITIES_DIR/${NAME}.md"
|
|
331
|
+
if [[ ! -f "$FILE" ]]; then
|
|
332
|
+
echo "❌ Personality '$NAME' not found"
|
|
333
|
+
echo "Use 'add' to create it first"
|
|
334
|
+
exit 1
|
|
335
|
+
fi
|
|
336
|
+
|
|
337
|
+
echo "📝 Edit this file to customize the personality:"
|
|
338
|
+
echo "$FILE"
|
|
339
|
+
;;
|
|
340
|
+
|
|
341
|
+
reset)
|
|
342
|
+
echo "normal" > "$PERSONALITY_FILE"
|
|
343
|
+
echo "🎭 Personality reset to: normal"
|
|
344
|
+
;;
|
|
345
|
+
|
|
346
|
+
set-favorite-voice)
|
|
347
|
+
PERSONALITY="$2"
|
|
348
|
+
NEW_VOICE="$3"
|
|
349
|
+
|
|
350
|
+
if [[ -z "$PERSONALITY" ]] || [[ -z "$NEW_VOICE" ]]; then
|
|
351
|
+
echo "❌ Please specify both personality name and voice name"
|
|
352
|
+
echo "Usage: $0 set-favorite-voice <personality> <voice>"
|
|
353
|
+
exit 1
|
|
354
|
+
fi
|
|
355
|
+
|
|
356
|
+
FILE="$PERSONALITIES_DIR/${PERSONALITY}.md"
|
|
357
|
+
if [[ ! -f "$FILE" ]]; then
|
|
358
|
+
echo "❌ Personality '$PERSONALITY' not found"
|
|
359
|
+
exit 1
|
|
360
|
+
fi
|
|
361
|
+
|
|
362
|
+
# Detect active TTS provider
|
|
363
|
+
PROVIDER_FILE=""
|
|
364
|
+
if [[ -f "$CLAUDE_DIR/tts-provider.txt" ]]; then
|
|
365
|
+
PROVIDER_FILE="$CLAUDE_DIR/tts-provider.txt"
|
|
366
|
+
elif [[ -f "$HOME/.claude/tts-provider.txt" ]]; then
|
|
367
|
+
PROVIDER_FILE="$HOME/.claude/tts-provider.txt"
|
|
368
|
+
fi
|
|
369
|
+
|
|
370
|
+
ACTIVE_PROVIDER="piper" # default
|
|
371
|
+
if [[ -n "$PROVIDER_FILE" ]]; then
|
|
372
|
+
ACTIVE_PROVIDER=$(cat "$PROVIDER_FILE")
|
|
373
|
+
fi
|
|
374
|
+
|
|
375
|
+
# Determine which field to update based on provider
|
|
376
|
+
if [[ "$ACTIVE_PROVIDER" == "piper" ]]; then
|
|
377
|
+
VOICE_FIELD="piper_voice"
|
|
378
|
+
CURRENT_VOICE=$(get_personality_data "$PERSONALITY" "piper_voice")
|
|
379
|
+
else
|
|
380
|
+
# macOS or other provider
|
|
381
|
+
VOICE_FIELD="macos_voice"
|
|
382
|
+
CURRENT_VOICE=$(get_personality_data "$PERSONALITY" "macos_voice")
|
|
383
|
+
fi
|
|
384
|
+
|
|
385
|
+
# Check if personality already has a favorite voice assigned
|
|
386
|
+
if [[ -n "$CURRENT_VOICE" ]] && [[ "$CURRENT_VOICE" != "$NEW_VOICE" ]]; then
|
|
387
|
+
echo "⚠️ WARNING: Personality '$PERSONALITY' already has a favorite voice assigned!"
|
|
388
|
+
echo ""
|
|
389
|
+
echo " Current favorite ($ACTIVE_PROVIDER): $CURRENT_VOICE"
|
|
390
|
+
echo " New voice: $NEW_VOICE"
|
|
391
|
+
echo ""
|
|
392
|
+
echo "Do you want to replace the favorite voice?"
|
|
393
|
+
echo ""
|
|
394
|
+
read -p "Enter your choice (yes/no): " CHOICE
|
|
395
|
+
|
|
396
|
+
case "$CHOICE" in
|
|
397
|
+
yes|y|YES|Y)
|
|
398
|
+
echo "✅ Replacing favorite voice..."
|
|
399
|
+
;;
|
|
400
|
+
no|n|NO|N)
|
|
401
|
+
echo "❌ Keeping current favorite voice: $CURRENT_VOICE"
|
|
402
|
+
exit 0
|
|
403
|
+
;;
|
|
404
|
+
*)
|
|
405
|
+
echo "❌ Invalid choice. Keeping current favorite voice: $CURRENT_VOICE"
|
|
406
|
+
exit 1
|
|
407
|
+
;;
|
|
408
|
+
esac
|
|
409
|
+
fi
|
|
410
|
+
|
|
411
|
+
# Update the voice in the personality file
|
|
412
|
+
if grep -q "^${VOICE_FIELD}:" "$FILE"; then
|
|
413
|
+
# Field exists, replace it
|
|
414
|
+
sed -i "s/^${VOICE_FIELD}:.*/${VOICE_FIELD}: ${NEW_VOICE}/" "$FILE"
|
|
415
|
+
else
|
|
416
|
+
# Field doesn't exist, add it after the frontmatter
|
|
417
|
+
sed -i "/^---$/,/^---$/ { /^---$/a\\
|
|
418
|
+
${VOICE_FIELD}: ${NEW_VOICE}
|
|
419
|
+
}" "$FILE"
|
|
420
|
+
fi
|
|
421
|
+
|
|
422
|
+
echo "✅ Favorite voice for '$PERSONALITY' personality set to: $NEW_VOICE ($ACTIVE_PROVIDER)"
|
|
423
|
+
echo "📝 Updated file: $FILE"
|
|
424
|
+
;;
|
|
425
|
+
|
|
426
|
+
*)
|
|
427
|
+
# If a single argument is provided and it's not a command, treat it as "set <personality>"
|
|
428
|
+
if [[ -n "$1" ]] && [[ -f "$PERSONALITIES_DIR/${1}.md" || "$1" == "random" ]]; then
|
|
429
|
+
# Call set with the personality name
|
|
430
|
+
exec "$0" set "$1"
|
|
431
|
+
else
|
|
432
|
+
echo "AgentVibes Personality Manager"
|
|
433
|
+
echo ""
|
|
434
|
+
echo "Commands:"
|
|
435
|
+
echo " list - List all personalities"
|
|
436
|
+
echo " set/switch <name> - Set personality"
|
|
437
|
+
echo " add <name> - Create new personality"
|
|
438
|
+
echo " edit <name> - Show path to edit personality"
|
|
439
|
+
echo " get - Show current personality"
|
|
440
|
+
echo " set-favorite-voice <name> <voice> - Set favorite voice for a personality"
|
|
441
|
+
echo " reset - Reset to normal"
|
|
442
|
+
echo ""
|
|
443
|
+
echo "Examples:"
|
|
444
|
+
echo " /agent-vibes:personality flirty"
|
|
445
|
+
echo " /agent-vibes:personality add cowboy"
|
|
446
|
+
echo " /agent-vibes:personality set-favorite-voice flirty \"Aria\""
|
|
447
|
+
fi
|
|
448
|
+
;;
|
|
449
449
|
esac
|