agentvibes 3.5.9 → 4.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.
Files changed (71) hide show
  1. package/.agentvibes/bmad/bmad-voices-enabled.flag +0 -0
  2. package/.agentvibes/bmad/bmad-voices.md +69 -0
  3. package/.claude/config/audio-effects.cfg +1 -1
  4. package/.claude/config/background-music-position.txt +1 -27
  5. package/.claude/github-star-reminder.txt +1 -1
  6. package/.claude/hooks/audio-processor.sh +32 -17
  7. package/.claude/hooks/bmad-speak-enhanced.sh +5 -5
  8. package/.claude/hooks/bmad-speak.sh +4 -4
  9. package/.claude/hooks/bmad-voice-manager.sh +8 -8
  10. package/.claude/hooks/clawdbot-receiver-SECURE.sh +23 -25
  11. package/.claude/hooks/clawdbot-receiver.sh +28 -4
  12. package/.claude/hooks/language-manager.sh +1 -1
  13. package/.claude/hooks/path-resolver.sh +60 -0
  14. package/.claude/hooks/play-tts-agentvibes-receiver-for-voiceless-connections.sh +90 -0
  15. package/.claude/hooks/play-tts-piper.sh +82 -24
  16. package/.claude/hooks/play-tts-ssh-remote.sh +13 -15
  17. package/.claude/hooks/play-tts.sh +16 -5
  18. package/.claude/hooks/session-start-tts.sh +26 -56
  19. package/.claude/hooks/soprano-gradio-synth.py +1 -1
  20. package/.claude/hooks/verbosity-manager.sh +10 -4
  21. package/.claude/settings.json +1 -1
  22. package/CLAUDE.md +129 -104
  23. package/README.md +418 -10
  24. package/RELEASE_NOTES.md +60 -1036
  25. package/bin/agentvibes-voice-browser.js +1827 -0
  26. package/bin/agentvibes.js +100 -0
  27. package/mcp-server/server.py +67 -3
  28. package/package.json +11 -2
  29. package/src/console/app.js +806 -0
  30. package/src/console/audio-env.js +123 -0
  31. package/src/console/brand-colors.js +13 -0
  32. package/src/console/footer-config.js +42 -0
  33. package/src/console/modals/.gitkeep +0 -0
  34. package/src/console/modals/modal-overlay.js +247 -0
  35. package/src/console/navigation.js +60 -0
  36. package/src/console/tabs/.gitkeep +0 -0
  37. package/src/console/tabs/agents-tab.js +369 -0
  38. package/src/console/tabs/help-tab.js +261 -0
  39. package/src/console/tabs/install-tab.js +990 -0
  40. package/src/console/tabs/music-tab.js +997 -0
  41. package/src/console/tabs/placeholder-tab.js +45 -0
  42. package/src/console/tabs/readme-tab.js +267 -0
  43. package/src/console/tabs/settings-tab.js +3949 -0
  44. package/src/console/tabs/voices-tab.js +1574 -0
  45. package/src/installer/music-file-input.js +304 -0
  46. package/src/installer.js +1353 -676
  47. package/src/services/.gitkeep +0 -0
  48. package/src/services/agent-voice-store.js +163 -0
  49. package/src/services/config-service.js +240 -0
  50. package/src/services/navigation-service.js +123 -0
  51. package/src/services/provider-service.js +132 -0
  52. package/src/services/verbosity-service.js +157 -0
  53. package/src/utils/audio-duration-validator.js +298 -0
  54. package/src/utils/audio-format-validator.js +277 -0
  55. package/src/utils/dependency-checker.js +3 -3
  56. package/src/utils/file-ownership-verifier.js +358 -0
  57. package/src/utils/music-file-validator.js +275 -0
  58. package/src/utils/preview-list-prompt.js +136 -0
  59. package/src/utils/provider-validator.js +144 -132
  60. package/src/utils/secure-music-storage.js +412 -0
  61. package/templates/agentvibes-receiver.sh +11 -7
  62. package/voice-assignments.json +8245 -0
  63. package/.claude/config/background-music-volume.txt +0 -1
  64. package/.claude/config/background-music.cfg +0 -1
  65. package/.claude/config/background-music.txt +0 -1
  66. package/.claude/config/tts-speech-rate.txt +0 -1
  67. package/.claude/config/tts-verbosity.txt +0 -1
  68. package/.claude/hooks/bmad-party-manager.sh +0 -225
  69. package/.claude/hooks/stop.sh +0 -38
  70. package/.claude/piper-voices-dir.txt +0 -1
  71. package/.mcp.json +0 -34
@@ -0,0 +1,100 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * AgentVibes TUI Console — Command Entry Point
4
+ * Story 6.5: Command Routing & Entry Points
5
+ *
6
+ * Routes CLI subcommands to the correct TUI console tab:
7
+ * npx agentvibes → smart detection (Settings if installed, Install if not)
8
+ * npx agentvibes install → Install tab
9
+ * npx agentvibes config → Settings tab
10
+ * npx agentvibes configure → Settings tab
11
+ * npx agentvibes <unknown> → help text + exit(1)
12
+ */
13
+
14
+ import { fileURLToPath } from 'node:url';
15
+ import fs from 'node:fs';
16
+ import { ConfigService } from '../src/services/config-service.js';
17
+ import { launchConsole } from '../src/console/app.js';
18
+
19
+ /**
20
+ * Resolve CLI args to a TUI start tab or an error.
21
+ * Exported as named export for unit testing without child-process spawning.
22
+ *
23
+ * @param {string[]} args - CLI arguments (process.argv.slice(2))
24
+ * @param {{ isInstalled: () => boolean }} configService
25
+ * @returns {{ startTab: string } | { help: string } | { error: string }}
26
+ */
27
+ export function resolveStartTab(args, configService) {
28
+ const cmd = args[0];
29
+
30
+ if (cmd === 'install') {
31
+ return { startTab: 'install' };
32
+ }
33
+
34
+ if (cmd === 'config' || cmd === 'configure') {
35
+ return { startTab: 'settings' };
36
+ }
37
+
38
+ if (cmd === '--help' || cmd === '-h') {
39
+ return {
40
+ help: [
41
+ 'AgentVibes — TTS for AI assistants with personality',
42
+ '',
43
+ 'Usage:',
44
+ ' npx agentvibes # Open console (auto-detects install state)',
45
+ ' npx agentvibes install # Open Install tab',
46
+ ' npx agentvibes config # Open Settings tab',
47
+ ' npx agentvibes --help # Show this help',
48
+ '',
49
+ 'Visit https://agentvibes.org for documentation.',
50
+ ].join('\n'),
51
+ };
52
+ }
53
+
54
+ if (!cmd) {
55
+ // Smart detection: show Install tab if not installed, Settings if installed
56
+ return { startTab: configService.isInstalled() ? 'settings' : 'install' };
57
+ }
58
+
59
+ // Unknown command → help + error
60
+ return {
61
+ error: [
62
+ `Unknown command: '${cmd}'`,
63
+ '',
64
+ 'Usage:',
65
+ ' npx agentvibes # Open console (auto-detects install state)',
66
+ ' npx agentvibes install # Open Install tab',
67
+ ' npx agentvibes config # Open Settings tab',
68
+ '',
69
+ "Run 'npx agentvibes' to get started.",
70
+ ].join('\n'),
71
+ };
72
+ }
73
+
74
+ // ---------------------------------------------------------------------------
75
+ // Main: run only when executed directly (not imported by tests)
76
+ // ---------------------------------------------------------------------------
77
+
78
+ // Resolve symlinks before comparing so the guard works when run via npm link / npx
79
+ const _thisFile = fileURLToPath(import.meta.url);
80
+ const _argv1 = (() => { try { return fs.realpathSync(process.argv[1]); } catch { return process.argv[1]; } })();
81
+
82
+ if (_argv1 === _thisFile) {
83
+ const configService = new ConfigService();
84
+ const result = resolveStartTab(process.argv.slice(2), configService);
85
+
86
+ if (result.help) {
87
+ process.stdout.write(result.help + '\n');
88
+ process.exit(0);
89
+ }
90
+
91
+ if (result.error) {
92
+ process.stderr.write(result.error + '\n');
93
+ process.exit(1);
94
+ }
95
+
96
+ launchConsole({ startTab: result.startTab }).catch(err => {
97
+ process.stderr.write(`Failed to launch AgentVibes console: ${err.message}\n`);
98
+ process.exit(1);
99
+ });
100
+ }
@@ -41,6 +41,7 @@ use or other dealings in the software.
41
41
  """
42
42
 
43
43
  import asyncio
44
+ import json
44
45
  import os
45
46
  import platform
46
47
  import subprocess
@@ -101,6 +102,62 @@ class AgentVibesServer:
101
102
  # Fallback to global ~/.claude (should never happen in properly installed package)
102
103
  return Path.home() / self.CLAUDE_DIR_NAME
103
104
 
105
+ def _resolve_friendly_name(self, voice_name: str) -> str:
106
+ """
107
+ Resolve friendly name to Piper voice ID using voice-metadata.json.
108
+
109
+ Args:
110
+ voice_name: Friendly name (e.g., "ryan") or Piper ID
111
+
112
+ Returns:
113
+ Resolved Piper voice ID, or original voice_name if not found
114
+ """
115
+ import re
116
+
117
+ metadata_path = self.agentvibes_root / ".agentvibes" / "config" / "voice-metadata.json"
118
+
119
+ # SECURITY: Verify file exists and is not a symlink
120
+ if not metadata_path.exists() or metadata_path.is_symlink():
121
+ return voice_name
122
+
123
+ # SECURITY: Verify file ownership matches current user (Unix only)
124
+ try:
125
+ if hasattr(os, 'getuid'):
126
+ stat_info = metadata_path.stat()
127
+ if stat_info.st_uid != os.getuid():
128
+ return voice_name
129
+ except (OSError, AttributeError):
130
+ pass
131
+
132
+ try:
133
+ with open(metadata_path, 'r') as f:
134
+ metadata = json.load(f)
135
+
136
+ voices = metadata.get('voices', {})
137
+ voice_lower = voice_name.lower()
138
+
139
+ resolved_id = None
140
+
141
+ # Check if it's a friendly name key
142
+ if voice_lower in voices:
143
+ resolved_id = voices[voice_lower].get('id')
144
+
145
+ # Check if it matches a displayName
146
+ if not resolved_id:
147
+ for friendly_name, voice_data in voices.items():
148
+ if voice_data.get('displayName', '').lower() == voice_lower:
149
+ resolved_id = voice_data.get('id')
150
+ break
151
+
152
+ # SECURITY: Validate resolved ID matches safe pattern
153
+ if resolved_id and re.match(r'^[a-zA-Z0-9_-]+$', resolved_id):
154
+ return resolved_id
155
+
156
+ except (json.JSONDecodeError, KeyError, IOError, TypeError):
157
+ pass
158
+
159
+ return voice_name
160
+
104
161
  async def text_to_speech(
105
162
  self,
106
163
  text: str,
@@ -249,18 +306,25 @@ class AgentVibesServer:
249
306
 
250
307
  async def set_voice(self, voice_name: str) -> str:
251
308
  """
252
- Switch to a different voice.
309
+ Switch to a different voice (supports friendly names like "ryan" or "katherine").
253
310
 
254
311
  Args:
255
- voice_name: Name of the voice to switch to
312
+ voice_name: Friendly name (e.g., "ryan") or Piper voice ID
256
313
 
257
314
  Returns:
258
315
  Success or error message
259
316
  """
317
+ # Resolve friendly name to Piper ID
318
+ original_name = voice_name
319
+ resolved_name = self._resolve_friendly_name(voice_name)
320
+
260
321
  result = await self._run_script(
261
- self.VOICE_MANAGER_SCRIPT, ["switch", voice_name, "--silent"]
322
+ self.VOICE_MANAGER_SCRIPT, ["switch", resolved_name, "--silent"]
262
323
  )
324
+
263
325
  if result and "✅" in result:
326
+ if original_name.lower() != resolved_name.lower():
327
+ return f"✅ Voice switched to: {original_name} ({resolved_name})"
264
328
  return f"✅ Voice switched to: {voice_name}"
265
329
  return f"❌ Failed to switch voice: {result}"
266
330
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "agentvibes",
4
- "version": "3.5.9",
4
+ "version": "4.0.0",
5
5
  "description": "Now your AI Agents can finally talk back! Professional TTS voice for Claude Code, Claude Desktop (via MCP), and Clawdbot with multi-provider support.",
6
6
  "homepage": "https://agentvibes.org",
7
7
  "keywords": [
@@ -27,9 +27,10 @@
27
27
  "type": "module",
28
28
  "main": "src/installer.js",
29
29
  "bin": {
30
- "agentvibes": "bin/agent-vibes",
30
+ "agentvibes": "bin/agentvibes.js",
31
31
  "agent-vibes": "bin/agent-vibes",
32
32
  "agentvibes-mcp-server": "bin/mcp-server.js",
33
+ "agentvibes-voice-browser": "bin/agentvibes-voice-browser.js",
33
34
  "test-bmad-pr": "bin/test-bmad-pr"
34
35
  },
35
36
  "files": [
@@ -62,6 +63,9 @@
62
63
  ".claude/piper-voices-dir.txt",
63
64
  ".claude/verbosity.txt",
64
65
  ".claude/github-star-reminder.txt",
66
+ ".claude/audio/voice-samples/",
67
+ "voice-assignments.json",
68
+ ".agentvibes/",
65
69
  ".clawdbot/",
66
70
  ".mcp.json",
67
71
  "setup-windows.ps1",
@@ -75,6 +79,7 @@
75
79
  "install-local": "node src/installer.js install",
76
80
  "postinstall": "node mcp-server/install-deps.js",
77
81
  "install-mcp-deps": "node mcp-server/install-deps.js",
82
+ "voice-browser": "node bin/agentvibes-voice-browser.js",
78
83
  "test": "npm run test:syntax && AGENTVIBES_TEST_MODE=true bats test/unit/*.bats && npm run test:coverage",
79
84
  "test:syntax": "node -c src/installer.js && node -c mcp-server/install-deps.js",
80
85
  "test:bats": "AGENTVIBES_TEST_MODE=true bats test/unit/*.bats",
@@ -83,6 +88,9 @@
83
88
  "test:verbose": "AGENTVIBES_TEST_MODE=true bats -t test/unit/*.bats"
84
89
  },
85
90
  "dependencies": {
91
+ "@inquirer/search": "^3.1.3",
92
+ "agentvibes": "^3.5.9",
93
+ "blessed": "^0.1.81",
86
94
  "boxen": "^7.0.0",
87
95
  "chalk": "^5.0.0",
88
96
  "commander": "^10.0.0",
@@ -98,6 +106,7 @@
98
106
  "access": "public"
99
107
  },
100
108
  "devDependencies": {
109
+ "bats": "^1.13.0",
101
110
  "c8": "^10.1.3"
102
111
  }
103
112
  }