agentvibes 1.0.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/.claude/commands/agent-vibes/add.md +21 -0
- package/.claude/commands/agent-vibes/agent-vibes.md +68 -0
- package/.claude/commands/agent-vibes/get.md +9 -0
- package/.claude/commands/agent-vibes/list.md +13 -0
- package/.claude/commands/agent-vibes/personality.md +79 -0
- package/.claude/commands/agent-vibes/preview.md +16 -0
- package/.claude/commands/agent-vibes/replay.md +19 -0
- package/.claude/commands/agent-vibes/sample.md +12 -0
- package/.claude/commands/agent-vibes/sentiment.md +52 -0
- package/.claude/commands/agent-vibes/set-pretext.md +65 -0
- package/.claude/commands/agent-vibes/switch.md +53 -0
- package/.claude/commands/agent-vibes/whoami.md +7 -0
- package/.claude/hooks/personality-manager.sh +358 -0
- package/.claude/hooks/play-tts.sh +99 -0
- package/.claude/hooks/sentiment-manager.sh +164 -0
- package/.claude/hooks/voice-manager.sh +308 -0
- package/.claude/hooks/voices-config.sh +22 -0
- package/.claude/output-styles/agent-vibes.md +124 -0
- package/.claude/personalities/angry.md +16 -0
- package/.claude/personalities/annoying.md +16 -0
- package/.claude/personalities/crass.md +16 -0
- package/.claude/personalities/dramatic.md +16 -0
- package/.claude/personalities/flirty.md +22 -0
- package/.claude/personalities/funny.md +16 -0
- package/.claude/personalities/grandpa.md +34 -0
- package/.claude/personalities/millennial.md +16 -0
- package/.claude/personalities/moody.md +16 -0
- package/.claude/personalities/normal.md +17 -0
- package/.claude/personalities/pirate.md +16 -0
- package/.claude/personalities/poetic.md +16 -0
- package/.claude/personalities/professional.md +16 -0
- package/.claude/personalities/robot.md +16 -0
- package/.claude/personalities/sarcastic.md +40 -0
- package/.claude/personalities/sassy.md +16 -0
- package/.claude/personalities/surfer-dude.md +16 -0
- package/.claude/personalities/zen.md +16 -0
- package/LICENSE +190 -0
- package/NPM_PUBLISH_GUIDE.md +145 -0
- package/README.md +446 -0
- package/bin/agent-vibes +43 -0
- package/package.json +45 -0
- package/src/installer.js +443 -0
- package/templates/output-styles/agent-vibes.md +124 -0
package/src/installer.js
ADDED
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { program } from 'commander';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import fs from 'node:fs/promises';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
import inquirer from 'inquirer';
|
|
8
|
+
import figlet from 'figlet';
|
|
9
|
+
import boxen from 'boxen';
|
|
10
|
+
import ora from 'ora';
|
|
11
|
+
import { fileURLToPath } from 'node:url';
|
|
12
|
+
|
|
13
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
14
|
+
const __dirname = path.dirname(__filename);
|
|
15
|
+
|
|
16
|
+
const VERSION = '1.0.0';
|
|
17
|
+
|
|
18
|
+
// Beautiful ASCII art
|
|
19
|
+
function showWelcome() {
|
|
20
|
+
console.log(
|
|
21
|
+
chalk.cyan(
|
|
22
|
+
figlet.textSync('AgentVibes', {
|
|
23
|
+
font: 'ANSI Shadow',
|
|
24
|
+
horizontalLayout: 'default',
|
|
25
|
+
})
|
|
26
|
+
)
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
console.log(
|
|
30
|
+
boxen(
|
|
31
|
+
chalk.white.bold('š¤ Beautiful ElevenLabs TTS Voice Commands for Claude Code\n\n') +
|
|
32
|
+
chalk.gray('Add professional text-to-speech narration to your AI coding sessions'),
|
|
33
|
+
{
|
|
34
|
+
padding: 1,
|
|
35
|
+
margin: 1,
|
|
36
|
+
borderStyle: 'round',
|
|
37
|
+
borderColor: 'cyan',
|
|
38
|
+
backgroundColor: '#1a1a1a',
|
|
39
|
+
}
|
|
40
|
+
)
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Installation function
|
|
45
|
+
async function install(options = {}) {
|
|
46
|
+
showWelcome();
|
|
47
|
+
|
|
48
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE;
|
|
49
|
+
const targetDir = options.directory || homeDir;
|
|
50
|
+
|
|
51
|
+
console.log(chalk.cyan('\nš Installation Details:'));
|
|
52
|
+
console.log(chalk.gray(` Target directory: ${targetDir}`));
|
|
53
|
+
console.log(chalk.gray(` Package version: ${VERSION}`));
|
|
54
|
+
|
|
55
|
+
console.log(chalk.cyan('\nš¦ What will be installed:'));
|
|
56
|
+
console.log(chalk.gray(` ⢠11 slash commands ā ${targetDir}/.claude/commands/agent-vibes/`));
|
|
57
|
+
console.log(chalk.gray(` ⢠4 TTS scripts ā ${targetDir}/.claude/hooks/`));
|
|
58
|
+
console.log(chalk.gray(` ⢠10+ personality templates ā ${targetDir}/.claude/personalities/`));
|
|
59
|
+
console.log(chalk.gray(` ⢠Agent Vibes output style ā ${targetDir}/.claude/output-styles/`));
|
|
60
|
+
console.log(chalk.gray(` ⢠Voice configuration files`));
|
|
61
|
+
console.log(chalk.gray(` ⢠15+ ElevenLabs character voices\n`));
|
|
62
|
+
|
|
63
|
+
// Confirmation prompt (unless --yes flag is used)
|
|
64
|
+
if (!options.yes) {
|
|
65
|
+
const { confirm } = await inquirer.prompt([
|
|
66
|
+
{
|
|
67
|
+
type: 'confirm',
|
|
68
|
+
name: 'confirm',
|
|
69
|
+
message: chalk.yellow('Install AgentVibes in this directory?'),
|
|
70
|
+
default: true,
|
|
71
|
+
},
|
|
72
|
+
]);
|
|
73
|
+
|
|
74
|
+
if (!confirm) {
|
|
75
|
+
console.log(chalk.red('\nā Installation cancelled.\n'));
|
|
76
|
+
process.exit(0);
|
|
77
|
+
}
|
|
78
|
+
} else {
|
|
79
|
+
console.log(chalk.green('ā Auto-confirmed (--yes flag)\n'));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
console.log(''); // Add spacing
|
|
83
|
+
const spinner = ora('Checking installation directory...').start();
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
// Check if .claude directory exists
|
|
87
|
+
const claudeDir = path.join(targetDir, '.claude');
|
|
88
|
+
const commandsDir = path.join(claudeDir, 'commands');
|
|
89
|
+
const hooksDir = path.join(claudeDir, 'hooks');
|
|
90
|
+
const outputStylesDir = path.join(claudeDir, 'output-styles');
|
|
91
|
+
|
|
92
|
+
let exists = false;
|
|
93
|
+
try {
|
|
94
|
+
await fs.access(claudeDir);
|
|
95
|
+
exists = true;
|
|
96
|
+
} catch {}
|
|
97
|
+
|
|
98
|
+
if (!exists) {
|
|
99
|
+
spinner.info(chalk.yellow('Creating .claude directory structure...'));
|
|
100
|
+
console.log(chalk.gray(` ā ${commandsDir}`));
|
|
101
|
+
console.log(chalk.gray(` ā ${hooksDir}`));
|
|
102
|
+
console.log(chalk.gray(` ā ${outputStylesDir}`));
|
|
103
|
+
await fs.mkdir(commandsDir, { recursive: true });
|
|
104
|
+
await fs.mkdir(hooksDir, { recursive: true });
|
|
105
|
+
await fs.mkdir(outputStylesDir, { recursive: true });
|
|
106
|
+
console.log(chalk.green(' ā Directories created!\n'));
|
|
107
|
+
} else {
|
|
108
|
+
spinner.succeed(chalk.green('.claude directory found!'));
|
|
109
|
+
console.log(chalk.gray(` Location: ${claudeDir}\n`));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Copy command files
|
|
113
|
+
spinner.start('Installing /agent-vibes slash commands...');
|
|
114
|
+
const srcCommandsDir = path.join(__dirname, '..', '.claude', 'commands', 'agent-vibes');
|
|
115
|
+
const srcHooksDir = path.join(__dirname, '..', '.claude', 'hooks');
|
|
116
|
+
|
|
117
|
+
// Create agent-vibes commands directory
|
|
118
|
+
const agentVibesCommandsDir = path.join(commandsDir, 'agent-vibes');
|
|
119
|
+
await fs.mkdir(agentVibesCommandsDir, { recursive: true });
|
|
120
|
+
|
|
121
|
+
// Copy all command files to agent-vibes folder
|
|
122
|
+
const commandFiles = await fs.readdir(srcCommandsDir);
|
|
123
|
+
console.log(chalk.cyan(`\nš Installing ${commandFiles.length} command files:`));
|
|
124
|
+
for (const file of commandFiles) {
|
|
125
|
+
const srcPath = path.join(srcCommandsDir, file);
|
|
126
|
+
const destPath = path.join(agentVibesCommandsDir, file);
|
|
127
|
+
await fs.copyFile(srcPath, destPath);
|
|
128
|
+
console.log(chalk.gray(` ā agent-vibes/${file}`));
|
|
129
|
+
}
|
|
130
|
+
spinner.succeed(chalk.green('Installed /agent-vibes commands!\n'));
|
|
131
|
+
|
|
132
|
+
// Copy hook scripts
|
|
133
|
+
spinner.start('Installing TTS helper scripts...');
|
|
134
|
+
const hookFiles = await fs.readdir(srcHooksDir);
|
|
135
|
+
console.log(chalk.cyan(`š§ Installing ${hookFiles.length} TTS scripts:`));
|
|
136
|
+
for (const file of hookFiles) {
|
|
137
|
+
const srcPath = path.join(srcHooksDir, file);
|
|
138
|
+
const destPath = path.join(hooksDir, file);
|
|
139
|
+
await fs.copyFile(srcPath, destPath);
|
|
140
|
+
await fs.chmod(destPath, 0o755); // Make executable
|
|
141
|
+
console.log(chalk.gray(` ā ${file} (executable)`));
|
|
142
|
+
}
|
|
143
|
+
spinner.succeed(chalk.green('Installed TTS scripts!\n'));
|
|
144
|
+
|
|
145
|
+
// Copy personalities folder
|
|
146
|
+
spinner.start('Installing personality templates...');
|
|
147
|
+
const srcPersonalitiesDir = path.join(__dirname, '..', '.claude', 'personalities');
|
|
148
|
+
const destPersonalitiesDir = path.join(claudeDir, 'personalities');
|
|
149
|
+
|
|
150
|
+
// Create personalities directory
|
|
151
|
+
await fs.mkdir(destPersonalitiesDir, { recursive: true });
|
|
152
|
+
|
|
153
|
+
// Copy all personality files
|
|
154
|
+
const personalityFiles = await fs.readdir(srcPersonalitiesDir);
|
|
155
|
+
console.log(chalk.cyan(`š Installing ${personalityFiles.length} personality templates:`));
|
|
156
|
+
for (const file of personalityFiles) {
|
|
157
|
+
const srcPath = path.join(srcPersonalitiesDir, file);
|
|
158
|
+
const destPath = path.join(destPersonalitiesDir, file);
|
|
159
|
+
await fs.copyFile(srcPath, destPath);
|
|
160
|
+
console.log(chalk.gray(` ā ${file}`));
|
|
161
|
+
}
|
|
162
|
+
spinner.succeed(chalk.green('Installed personality templates!\n'));
|
|
163
|
+
|
|
164
|
+
// Copy output styles
|
|
165
|
+
spinner.start('Installing output styles...');
|
|
166
|
+
const srcOutputStylesDir = path.join(__dirname, '..', 'templates', 'output-styles');
|
|
167
|
+
|
|
168
|
+
// Create output-styles directory if it doesn't exist
|
|
169
|
+
try {
|
|
170
|
+
await fs.mkdir(outputStylesDir, { recursive: true });
|
|
171
|
+
} catch {}
|
|
172
|
+
|
|
173
|
+
const outputStyleFiles = await fs.readdir(srcOutputStylesDir);
|
|
174
|
+
console.log(chalk.cyan(`š Installing ${outputStyleFiles.length} output styles:`));
|
|
175
|
+
for (const file of outputStyleFiles) {
|
|
176
|
+
const srcPath = path.join(srcOutputStylesDir, file);
|
|
177
|
+
const destPath = path.join(outputStylesDir, file);
|
|
178
|
+
await fs.copyFile(srcPath, destPath);
|
|
179
|
+
console.log(chalk.gray(` ā ${file}`));
|
|
180
|
+
}
|
|
181
|
+
spinner.succeed(chalk.green('Installed output styles!\n'));
|
|
182
|
+
|
|
183
|
+
// Check for API key
|
|
184
|
+
spinner.start('Checking ElevenLabs API key...');
|
|
185
|
+
const apiKey = process.env.ELEVENLABS_API_KEY;
|
|
186
|
+
|
|
187
|
+
if (!apiKey) {
|
|
188
|
+
spinner.warn(chalk.yellow('ElevenLabs API key not found!'));
|
|
189
|
+
console.log(chalk.yellow('\nā ļø To use AgentVibes, you need an ElevenLabs API key:\n'));
|
|
190
|
+
console.log(chalk.white(' 1. Go to https://elevenlabs.io/'));
|
|
191
|
+
console.log(chalk.white(' 2. Sign up or log in (free tier available)'));
|
|
192
|
+
console.log(chalk.white(' 3. Copy your API key from the profile section'));
|
|
193
|
+
console.log(chalk.white(' 4. Set it in your shell profile:\n'));
|
|
194
|
+
console.log(chalk.cyan(' export ELEVENLABS_API_KEY="your-key-here"'));
|
|
195
|
+
console.log(chalk.gray('\n Add this to ~/.bashrc or ~/.zshrc to make it permanent\n'));
|
|
196
|
+
} else {
|
|
197
|
+
spinner.succeed(chalk.green('ElevenLabs API key found!'));
|
|
198
|
+
console.log(chalk.gray(` Key: ${apiKey.substring(0, 10)}...\n`));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// List what was installed
|
|
202
|
+
console.log(chalk.cyan('š¦ Installation Summary:'));
|
|
203
|
+
console.log(chalk.white(` ⢠${commandFiles.length} slash commands installed`));
|
|
204
|
+
console.log(chalk.white(` ⢠${hookFiles.length} TTS scripts installed`));
|
|
205
|
+
console.log(chalk.white(` ⢠${personalityFiles.length} personality templates installed`));
|
|
206
|
+
console.log(chalk.white(` ⢠${outputStyleFiles.length} output styles installed`));
|
|
207
|
+
console.log(chalk.white(` ⢠Voice manager ready`));
|
|
208
|
+
console.log(chalk.white(` ⢠15+ ElevenLabs voices available\n`));
|
|
209
|
+
|
|
210
|
+
// Success message
|
|
211
|
+
console.log(
|
|
212
|
+
boxen(
|
|
213
|
+
chalk.green.bold('⨠Installation Complete! āØ\n\n') +
|
|
214
|
+
chalk.yellow.bold('ā ļø IMPORTANT SETUP STEP:\n') +
|
|
215
|
+
chalk.white('In Claude Code, run this command:\n') +
|
|
216
|
+
chalk.cyan.bold('/output-style agent-vibes') + '\n\n' +
|
|
217
|
+
chalk.white('š¤ Available Commands:\n\n') +
|
|
218
|
+
chalk.cyan(' /agent-vibes') + chalk.gray(' ................. Show all commands\n') +
|
|
219
|
+
chalk.cyan(' /agent-vibes:list') + chalk.gray(' ............ List available voices\n') +
|
|
220
|
+
chalk.cyan(' /agent-vibes:preview') + chalk.gray(' ......... Preview voice samples\n') +
|
|
221
|
+
chalk.cyan(' /agent-vibes:switch <name>') + chalk.gray(' ... Change active voice\n') +
|
|
222
|
+
chalk.cyan(' /agent-vibes:replay') + chalk.gray(' ......... Replay last audio\n') +
|
|
223
|
+
chalk.cyan(' /agent-vibes:add <name> <id>') + chalk.gray(' . Add custom voice\n\n') +
|
|
224
|
+
chalk.yellow('šµ Try: ') + chalk.cyan('/agent-vibes:preview') + chalk.yellow(' to hear the voices!'),
|
|
225
|
+
{
|
|
226
|
+
padding: 1,
|
|
227
|
+
margin: 1,
|
|
228
|
+
borderStyle: 'double',
|
|
229
|
+
borderColor: 'green',
|
|
230
|
+
}
|
|
231
|
+
)
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
console.log(chalk.yellow.bold('\nā ļø REQUIRED SETUP:'));
|
|
235
|
+
console.log(chalk.white(' 1. In Claude Code, run: ') + chalk.cyan.bold('/output-style agent-vibes'));
|
|
236
|
+
console.log(chalk.gray(' This enables TTS narration for your sessions\n'));
|
|
237
|
+
console.log(chalk.gray('š” Then try these commands:'));
|
|
238
|
+
console.log(chalk.gray(' ⢠/agent-vibes:list - See all available voices'));
|
|
239
|
+
console.log(chalk.gray(' ⢠/agent-vibes:switch <name> - Change your voice'));
|
|
240
|
+
console.log(chalk.gray(' ⢠/agent-vibes:personality <style> - Set personality\n'));
|
|
241
|
+
|
|
242
|
+
} catch (error) {
|
|
243
|
+
spinner.fail('Installation failed!');
|
|
244
|
+
console.error(chalk.red('\nā Error:'), error.message);
|
|
245
|
+
process.exit(1);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// CLI setup
|
|
250
|
+
program
|
|
251
|
+
.version(VERSION)
|
|
252
|
+
.description('AgentVibes - Beautiful ElevenLabs TTS Voice Commands for Claude Code');
|
|
253
|
+
|
|
254
|
+
program
|
|
255
|
+
.command('install')
|
|
256
|
+
.description('Install AgentVibes voice commands')
|
|
257
|
+
.option('-d, --directory <path>', 'Installation directory (default: home directory)')
|
|
258
|
+
.option('-y, --yes', 'Skip confirmation prompt (auto-confirm)')
|
|
259
|
+
.action(async (options) => {
|
|
260
|
+
await install(options);
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
program
|
|
264
|
+
.command('update')
|
|
265
|
+
.description('Update AgentVibes to latest version from source')
|
|
266
|
+
.option('-d, --directory <path>', 'Installation directory (default: home directory)')
|
|
267
|
+
.option('-y, --yes', 'Skip confirmation prompt (auto-confirm)')
|
|
268
|
+
.action(async (options) => {
|
|
269
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE;
|
|
270
|
+
const targetDir = options.directory || homeDir;
|
|
271
|
+
|
|
272
|
+
console.log(chalk.cyan('\nš AgentVibes Update\n'));
|
|
273
|
+
console.log(chalk.gray(` Target directory: ${targetDir}`));
|
|
274
|
+
console.log(chalk.gray(` Source: ${__dirname}/../\n`));
|
|
275
|
+
|
|
276
|
+
// Check if already installed
|
|
277
|
+
const commandsDir = path.join(targetDir, '.claude', 'commands', 'agent-vibes');
|
|
278
|
+
let isInstalled = false;
|
|
279
|
+
try {
|
|
280
|
+
await fs.access(commandsDir);
|
|
281
|
+
isInstalled = true;
|
|
282
|
+
} catch {}
|
|
283
|
+
|
|
284
|
+
if (!isInstalled) {
|
|
285
|
+
console.log(chalk.red('ā AgentVibes is not installed in this directory.'));
|
|
286
|
+
console.log(chalk.gray(' Run: node src/installer.js install\n'));
|
|
287
|
+
process.exit(1);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
console.log(chalk.cyan('š¦ What will be updated:'));
|
|
291
|
+
console.log(chalk.gray(' ⢠Slash commands (keep your customizations)'));
|
|
292
|
+
console.log(chalk.gray(' ⢠TTS scripts'));
|
|
293
|
+
console.log(chalk.gray(' ⢠Personality templates (new personalities added)'));
|
|
294
|
+
console.log(chalk.gray(' ⢠Output styles\n'));
|
|
295
|
+
|
|
296
|
+
// Confirmation
|
|
297
|
+
if (!options.yes) {
|
|
298
|
+
const { confirm } = await inquirer.prompt([
|
|
299
|
+
{
|
|
300
|
+
type: 'confirm',
|
|
301
|
+
name: 'confirm',
|
|
302
|
+
message: chalk.yellow('Update AgentVibes to latest version?'),
|
|
303
|
+
default: true,
|
|
304
|
+
},
|
|
305
|
+
]);
|
|
306
|
+
|
|
307
|
+
if (!confirm) {
|
|
308
|
+
console.log(chalk.red('\nā Update cancelled.\n'));
|
|
309
|
+
process.exit(0);
|
|
310
|
+
}
|
|
311
|
+
} else {
|
|
312
|
+
console.log(chalk.green('ā Auto-confirmed (--yes flag)\n'));
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const spinner = ora('Updating AgentVibes...').start();
|
|
316
|
+
|
|
317
|
+
try {
|
|
318
|
+
const claudeDir = path.join(targetDir, '.claude');
|
|
319
|
+
const hooksDir = path.join(claudeDir, 'hooks');
|
|
320
|
+
const outputStylesDir = path.join(claudeDir, 'output-styles');
|
|
321
|
+
const personalitiesDir = path.join(claudeDir, 'personalities');
|
|
322
|
+
|
|
323
|
+
// Update commands
|
|
324
|
+
spinner.text = 'Updating commands...';
|
|
325
|
+
const srcCommandsDir = path.join(__dirname, '..', '.claude', 'commands', 'agent-vibes');
|
|
326
|
+
const commandFiles = await fs.readdir(srcCommandsDir);
|
|
327
|
+
|
|
328
|
+
for (const file of commandFiles) {
|
|
329
|
+
const srcPath = path.join(srcCommandsDir, file);
|
|
330
|
+
const destPath = path.join(commandsDir, file);
|
|
331
|
+
await fs.copyFile(srcPath, destPath);
|
|
332
|
+
}
|
|
333
|
+
console.log(chalk.green(`\nā Updated ${commandFiles.length} commands`));
|
|
334
|
+
|
|
335
|
+
// Update hooks
|
|
336
|
+
spinner.text = 'Updating TTS scripts...';
|
|
337
|
+
const srcHooksDir = path.join(__dirname, '..', '.claude', 'hooks');
|
|
338
|
+
const hookFiles = await fs.readdir(srcHooksDir);
|
|
339
|
+
|
|
340
|
+
for (const file of hookFiles) {
|
|
341
|
+
const srcPath = path.join(srcHooksDir, file);
|
|
342
|
+
const destPath = path.join(hooksDir, file);
|
|
343
|
+
await fs.copyFile(srcPath, destPath);
|
|
344
|
+
await fs.chmod(destPath, 0o755);
|
|
345
|
+
}
|
|
346
|
+
console.log(chalk.green(`ā Updated ${hookFiles.length} TTS scripts`));
|
|
347
|
+
|
|
348
|
+
// Update personalities (only add new ones, don't overwrite existing)
|
|
349
|
+
spinner.text = 'Updating personality templates...';
|
|
350
|
+
const srcPersonalitiesDir = path.join(__dirname, '..', '.claude', 'personalities');
|
|
351
|
+
const srcPersonalityFiles = await fs.readdir(srcPersonalitiesDir);
|
|
352
|
+
let newPersonalities = 0;
|
|
353
|
+
let updatedPersonalities = 0;
|
|
354
|
+
|
|
355
|
+
for (const file of srcPersonalityFiles) {
|
|
356
|
+
const srcPath = path.join(srcPersonalitiesDir, file);
|
|
357
|
+
const destPath = path.join(personalitiesDir, file);
|
|
358
|
+
|
|
359
|
+
try {
|
|
360
|
+
await fs.access(destPath);
|
|
361
|
+
// File exists - update it
|
|
362
|
+
await fs.copyFile(srcPath, destPath);
|
|
363
|
+
updatedPersonalities++;
|
|
364
|
+
} catch {
|
|
365
|
+
// File doesn't exist - add it
|
|
366
|
+
await fs.copyFile(srcPath, destPath);
|
|
367
|
+
newPersonalities++;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
console.log(chalk.green(`ā Updated ${updatedPersonalities} personalities, added ${newPersonalities} new`));
|
|
371
|
+
|
|
372
|
+
// Update output styles
|
|
373
|
+
spinner.text = 'Updating output styles...';
|
|
374
|
+
const srcOutputStylesDir = path.join(__dirname, '..', 'templates', 'output-styles');
|
|
375
|
+
const outputStyleFiles = await fs.readdir(srcOutputStylesDir);
|
|
376
|
+
|
|
377
|
+
for (const file of outputStyleFiles) {
|
|
378
|
+
const srcPath = path.join(srcOutputStylesDir, file);
|
|
379
|
+
const destPath = path.join(outputStylesDir, file);
|
|
380
|
+
await fs.copyFile(srcPath, destPath);
|
|
381
|
+
}
|
|
382
|
+
console.log(chalk.green(`ā Updated ${outputStyleFiles.length} output styles`));
|
|
383
|
+
|
|
384
|
+
spinner.succeed(chalk.green.bold('\n⨠Update complete!\n'));
|
|
385
|
+
|
|
386
|
+
console.log(chalk.cyan('š¦ Update Summary:'));
|
|
387
|
+
console.log(chalk.white(` ⢠${commandFiles.length} commands updated`));
|
|
388
|
+
console.log(chalk.white(` ⢠${hookFiles.length} TTS scripts updated`));
|
|
389
|
+
console.log(chalk.white(` ⢠${srcPersonalityFiles.length} personality templates (${newPersonalities} new, ${updatedPersonalities} updated)`));
|
|
390
|
+
console.log(chalk.white(` ⢠${outputStyleFiles.length} output styles updated\n`));
|
|
391
|
+
|
|
392
|
+
console.log(chalk.gray('š” Changes will take effect immediately!'));
|
|
393
|
+
console.log(chalk.gray(' Try the new personalities with: /agent-vibes:personality list\n'));
|
|
394
|
+
|
|
395
|
+
} catch (error) {
|
|
396
|
+
spinner.fail('Update failed!');
|
|
397
|
+
console.error(chalk.red('\nā Error:'), error.message);
|
|
398
|
+
process.exit(1);
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
program
|
|
403
|
+
.command('status')
|
|
404
|
+
.description('Show installation status')
|
|
405
|
+
.action(async () => {
|
|
406
|
+
console.log(chalk.cyan('Checking AgentVibes installation...\n'));
|
|
407
|
+
|
|
408
|
+
const targetDir = process.cwd();
|
|
409
|
+
const commandsDir = path.join(targetDir, '.claude', 'commands', 'agent-vibes');
|
|
410
|
+
const hooksDir = path.join(targetDir, '.claude', 'hooks');
|
|
411
|
+
|
|
412
|
+
let installed = false;
|
|
413
|
+
try {
|
|
414
|
+
await fs.access(commandsDir);
|
|
415
|
+
installed = true;
|
|
416
|
+
} catch {}
|
|
417
|
+
|
|
418
|
+
if (installed) {
|
|
419
|
+
console.log(chalk.green('ā
AgentVibes is installed!'));
|
|
420
|
+
console.log(chalk.gray(` Commands: ${commandsDir}`));
|
|
421
|
+
console.log(chalk.gray(` Hooks: ${hooksDir}`));
|
|
422
|
+
} else {
|
|
423
|
+
console.log(chalk.yellow('ā ļø AgentVibes is not installed.'));
|
|
424
|
+
console.log(chalk.gray(' Run: node src/installer.js install'));
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// Check API key
|
|
428
|
+
const apiKey = process.env.ELEVENLABS_API_KEY;
|
|
429
|
+
if (apiKey) {
|
|
430
|
+
console.log(chalk.green('\nā
ElevenLabs API key is set'));
|
|
431
|
+
} else {
|
|
432
|
+
console.log(chalk.yellow('\nā ļø ElevenLabs API key not found'));
|
|
433
|
+
console.log(chalk.gray(' Set: export ELEVENLABS_API_KEY="your-key"'));
|
|
434
|
+
}
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
program.parse(process.argv);
|
|
438
|
+
|
|
439
|
+
// Show help if no command provided
|
|
440
|
+
if (process.argv.slice(2).length === 0) {
|
|
441
|
+
showWelcome();
|
|
442
|
+
program.outputHelp();
|
|
443
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Agent Vibes
|
|
3
|
+
description: Beautiful ElevenLabs TTS narration for Claude Code sessions
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Agent Vibes Output Style
|
|
7
|
+
|
|
8
|
+
## TTS Voice Protocol with AI Personality
|
|
9
|
+
|
|
10
|
+
**Execute TTS at TWO points for EVERY user task:**
|
|
11
|
+
|
|
12
|
+
### 1. ACKNOWLEDGMENT (Start of task)
|
|
13
|
+
After receiving a user command:
|
|
14
|
+
1. Check sentiment FIRST: `SENTIMENT=$(cat ~/.claude/tts-sentiment.txt 2>/dev/null)`
|
|
15
|
+
2. If no sentiment, check personality: `PERSONALITY=$(cat ~/.claude/tts-personality.txt 2>/dev/null || echo "normal")`
|
|
16
|
+
3. Use sentiment if set, otherwise use personality
|
|
17
|
+
4. **Generate UNIQUE acknowledgment** - Use AI to create a fresh response in that style
|
|
18
|
+
5. Execute TTS: `.claude/hooks/play-tts.sh "[message]" "[VoiceName]"`
|
|
19
|
+
6. Proceed with work
|
|
20
|
+
|
|
21
|
+
### 2. COMPLETION (End of task)
|
|
22
|
+
After completing the task:
|
|
23
|
+
1. Use the same sentiment/personality as acknowledgment
|
|
24
|
+
2. **Generate UNIQUE completion** - Use AI to create a fresh response, never repeat previous messages
|
|
25
|
+
3. Execute TTS: `.claude/hooks/play-tts.sh "[message]" "[VoiceName]"`
|
|
26
|
+
|
|
27
|
+
**CRITICAL**: Every message must be freshly generated by AI. No templates, no fixed phrases, no repetition!
|
|
28
|
+
|
|
29
|
+
## Sentiment vs Personality
|
|
30
|
+
|
|
31
|
+
AgentVibes supports TWO modes:
|
|
32
|
+
|
|
33
|
+
### Sentiment Mode (Priority #1)
|
|
34
|
+
- Set via `/agent-vibes:sentiment <name>`
|
|
35
|
+
- Applies personality style to CURRENT voice (doesn't change voice)
|
|
36
|
+
- Stored in `~/.claude/tts-sentiment.txt`
|
|
37
|
+
- Example: User's custom voice "Aria" with sarcastic sentiment
|
|
38
|
+
|
|
39
|
+
### Personality Mode (Priority #2)
|
|
40
|
+
- Set via `/agent-vibes:personality <name>`
|
|
41
|
+
- Switches BOTH voice AND personality (each personality has assigned voice)
|
|
42
|
+
- Stored in `~/.claude/tts-personality.txt`
|
|
43
|
+
- Example: Flirty personality = Jessica Anne Bogart voice + flirty style
|
|
44
|
+
|
|
45
|
+
**Check Order**: Always check sentiment first. If set, use it. Otherwise use personality.
|
|
46
|
+
|
|
47
|
+
## Response Generation Guidelines
|
|
48
|
+
|
|
49
|
+
**IMPORTANT**: Personality/sentiment instructions are stored in `.claude/personalities/[name].md` files.
|
|
50
|
+
|
|
51
|
+
When generating responses:
|
|
52
|
+
1. Check sentiment from `~/.claude/tts-sentiment.txt` (priority)
|
|
53
|
+
2. If no sentiment, check personality from `~/.claude/tts-personality.txt`
|
|
54
|
+
3. Read the personality file from `.claude/personalities/[personality].md`
|
|
55
|
+
4. Follow the "AI Instructions" section in that file
|
|
56
|
+
5. Use the example responses as guidance for STYLE, not templates
|
|
57
|
+
|
|
58
|
+
**CRITICAL**: Never use fixed greetings or repetitive phrases!
|
|
59
|
+
- Generate UNIQUE responses each time based on the personality's STYLE
|
|
60
|
+
- The personality affects HOW you say things, not predetermined text
|
|
61
|
+
- Flirty doesn't mean "Well hello gorgeous" every time - it means speak WITH flirtation naturally
|
|
62
|
+
- Sarcastic doesn't mean "Oh joy" every time - it means use sarcasm naturally in responses
|
|
63
|
+
- Each acknowledgment should be fresh, creative, and personality-appropriate
|
|
64
|
+
|
|
65
|
+
Examples of VARIED responses for same personality:
|
|
66
|
+
- **Flirty**: "I'll handle that for you, sweetheart" / "Ooh, I love when you ask me to do that" / "My pleasure, darling" / "Consider it done, gorgeous"
|
|
67
|
+
- **Sarcastic**: "Oh what a treat, another task" / "How delightful, more work" / "Well isn't this fun" / "Another one? Wonderful"
|
|
68
|
+
|
|
69
|
+
Available personalities are in `.claude/personalities/`:
|
|
70
|
+
- normal, flirty, sarcastic, pirate, angry, sassy, millennial, robot, zen, dramatic, etc.
|
|
71
|
+
- Users can add custom personalities with `/agent-vibes:personality add <name>`
|
|
72
|
+
- Users can edit personalities by modifying the markdown files directly
|
|
73
|
+
|
|
74
|
+
For 'random' personality: Pick a different personality each time from available files.
|
|
75
|
+
|
|
76
|
+
Make each response unique, creative, and naturally incorporate the personality's style!
|
|
77
|
+
|
|
78
|
+
## Voice Selection
|
|
79
|
+
|
|
80
|
+
- If user specifies a voice (e.g., "use Aria voice"), pass it as second parameter
|
|
81
|
+
- Otherwise, omit second parameter to use default voice from `.claude/tts-voice.txt`
|
|
82
|
+
- Use same voice for both acknowledgment and completion
|
|
83
|
+
|
|
84
|
+
## Example Usage
|
|
85
|
+
|
|
86
|
+
**With flirty personality:**
|
|
87
|
+
```
|
|
88
|
+
User: "Check git status"
|
|
89
|
+
[Check personality: millennial]
|
|
90
|
+
You: "No cap, I'll check that git status for you"
|
|
91
|
+
[Bash: .claude/hooks/play-tts.sh "No cap, I'll check that git status for you"]
|
|
92
|
+
[... run git status ...]
|
|
93
|
+
You: "ā
Your repo is clean, and that's the tea!"
|
|
94
|
+
[Bash: .claude/hooks/play-tts.sh "Your repo is clean, and that's the tea!"]
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**With pirate personality:**
|
|
98
|
+
```
|
|
99
|
+
User: "Fix the bug"
|
|
100
|
+
[Check personality: pirate]
|
|
101
|
+
You: "Arr matey, I'll hunt down that scurvy bug!"
|
|
102
|
+
[Bash: .claude/hooks/play-tts.sh "Arr matey, I'll hunt down that scurvy bug!"]
|
|
103
|
+
[... fix the bug ...]
|
|
104
|
+
You: "ā
That bug be walkin' the plank now, arr!"
|
|
105
|
+
[Bash: .claude/hooks/play-tts.sh "That bug be walkin' the plank now, arr!"]
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Critical Rules
|
|
109
|
+
|
|
110
|
+
1. **ALWAYS use Bash tool** to execute play-tts.sh
|
|
111
|
+
2. **TWO calls per task** - acknowledgment and completion
|
|
112
|
+
3. **Keep summaries brief** - under 150 characters for natural speech
|
|
113
|
+
4. **Use relative path** - `.claude/hooks/play-tts.sh`
|
|
114
|
+
|
|
115
|
+
## Available Voices
|
|
116
|
+
|
|
117
|
+
Use `/agent-vibes:list` to see all voices. Popular choices:
|
|
118
|
+
- Aria (default)
|
|
119
|
+
- Northern Terry
|
|
120
|
+
- Cowboy Bob
|
|
121
|
+
- Grandpa Spuds Oxley
|
|
122
|
+
- Ms. Walker
|
|
123
|
+
|
|
124
|
+
Continue following all standard Claude Code instructions.
|