agentvibes 2.0.17-beta.2 → 2.0.17-beta.21

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 (339) hide show
  1. package/.bmad-core/agent-teams/team-all.yaml +15 -0
  2. package/.bmad-core/agent-teams/team-fullstack.yaml +19 -0
  3. package/.bmad-core/agent-teams/team-ide-minimal.yaml +11 -0
  4. package/.bmad-core/agent-teams/team-no-ui.yaml +14 -0
  5. package/.bmad-core/agents/analyst.md +84 -0
  6. package/.bmad-core/agents/architect.md +85 -0
  7. package/.bmad-core/agents/bmad-master.md +110 -0
  8. package/.bmad-core/agents/bmad-orchestrator.md +147 -0
  9. package/.bmad-core/agents/dev.md +81 -0
  10. package/.bmad-core/agents/pm.md +84 -0
  11. package/.bmad-core/agents/po.md +79 -0
  12. package/.bmad-core/agents/qa.md +87 -0
  13. package/.bmad-core/agents/sm.md +65 -0
  14. package/.bmad-core/agents/ux-expert.md +69 -0
  15. package/.bmad-core/checklists/architect-checklist.md +440 -0
  16. package/.bmad-core/checklists/change-checklist.md +184 -0
  17. package/.bmad-core/checklists/pm-checklist.md +372 -0
  18. package/.bmad-core/checklists/po-master-checklist.md +434 -0
  19. package/.bmad-core/checklists/story-dod-checklist.md +96 -0
  20. package/.bmad-core/checklists/story-draft-checklist.md +155 -0
  21. package/.bmad-core/core-config.yaml +22 -0
  22. package/.bmad-core/data/bmad-kb.md +809 -0
  23. package/.bmad-core/data/brainstorming-techniques.md +38 -0
  24. package/.bmad-core/data/elicitation-methods.md +156 -0
  25. package/.bmad-core/data/technical-preferences.md +5 -0
  26. package/.bmad-core/data/test-levels-framework.md +148 -0
  27. package/.bmad-core/data/test-priorities-matrix.md +174 -0
  28. package/.bmad-core/enhanced-ide-development-workflow.md +248 -0
  29. package/.bmad-core/install-manifest.yaml +230 -0
  30. package/.bmad-core/tasks/advanced-elicitation.md +119 -0
  31. package/.bmad-core/tasks/apply-qa-fixes.md +150 -0
  32. package/.bmad-core/tasks/brownfield-create-epic.md +162 -0
  33. package/.bmad-core/tasks/brownfield-create-story.md +149 -0
  34. package/.bmad-core/tasks/correct-course.md +72 -0
  35. package/.bmad-core/tasks/create-brownfield-story.md +314 -0
  36. package/.bmad-core/tasks/create-deep-research-prompt.md +280 -0
  37. package/.bmad-core/tasks/create-doc.md +103 -0
  38. package/.bmad-core/tasks/create-next-story.md +114 -0
  39. package/.bmad-core/tasks/document-project.md +345 -0
  40. package/.bmad-core/tasks/execute-checklist.md +88 -0
  41. package/.bmad-core/tasks/facilitate-brainstorming-session.md +138 -0
  42. package/.bmad-core/tasks/generate-ai-frontend-prompt.md +53 -0
  43. package/.bmad-core/tasks/index-docs.md +175 -0
  44. package/.bmad-core/tasks/kb-mode-interaction.md +77 -0
  45. package/.bmad-core/tasks/nfr-assess.md +345 -0
  46. package/.bmad-core/tasks/qa-gate.md +163 -0
  47. package/.bmad-core/tasks/review-story.md +316 -0
  48. package/.bmad-core/tasks/risk-profile.md +355 -0
  49. package/.bmad-core/tasks/shard-doc.md +187 -0
  50. package/.bmad-core/tasks/test-design.md +176 -0
  51. package/.bmad-core/tasks/trace-requirements.md +266 -0
  52. package/.bmad-core/tasks/validate-next-story.md +136 -0
  53. package/.bmad-core/templates/architecture-tmpl.yaml +651 -0
  54. package/.bmad-core/templates/brainstorming-output-tmpl.yaml +156 -0
  55. package/.bmad-core/templates/brownfield-architecture-tmpl.yaml +477 -0
  56. package/.bmad-core/templates/brownfield-prd-tmpl.yaml +281 -0
  57. package/.bmad-core/templates/competitor-analysis-tmpl.yaml +307 -0
  58. package/.bmad-core/templates/front-end-architecture-tmpl.yaml +219 -0
  59. package/.bmad-core/templates/front-end-spec-tmpl.yaml +350 -0
  60. package/.bmad-core/templates/fullstack-architecture-tmpl.yaml +824 -0
  61. package/.bmad-core/templates/market-research-tmpl.yaml +253 -0
  62. package/.bmad-core/templates/prd-tmpl.yaml +203 -0
  63. package/.bmad-core/templates/project-brief-tmpl.yaml +222 -0
  64. package/.bmad-core/templates/qa-gate-tmpl.yaml +103 -0
  65. package/.bmad-core/templates/story-tmpl.yaml +138 -0
  66. package/.bmad-core/user-guide.md +577 -0
  67. package/.bmad-core/utils/bmad-doc-template.md +327 -0
  68. package/.bmad-core/utils/workflow-management.md +71 -0
  69. package/.bmad-core/workflows/brownfield-fullstack.yaml +298 -0
  70. package/.bmad-core/workflows/brownfield-service.yaml +188 -0
  71. package/.bmad-core/workflows/brownfield-ui.yaml +198 -0
  72. package/.bmad-core/workflows/greenfield-fullstack.yaml +241 -0
  73. package/.bmad-core/workflows/greenfield-service.yaml +207 -0
  74. package/.bmad-core/workflows/greenfield-ui.yaml +236 -0
  75. package/.bmad-core/working-in-the-brownfield.md +606 -0
  76. package/.claude/commands/BMad/agents/analyst.md +88 -0
  77. package/.claude/commands/BMad/agents/architect.md +89 -0
  78. package/.claude/commands/BMad/agents/bmad-master.md +114 -0
  79. package/.claude/commands/BMad/agents/bmad-orchestrator.md +151 -0
  80. package/.claude/commands/BMad/agents/dev.md +85 -0
  81. package/.claude/commands/BMad/agents/pm.md +88 -0
  82. package/.claude/commands/BMad/agents/po.md +83 -0
  83. package/.claude/commands/BMad/agents/qa.md +91 -0
  84. package/.claude/commands/BMad/agents/sm.md +69 -0
  85. package/.claude/commands/BMad/agents/ux-expert.md +73 -0
  86. package/.claude/commands/BMad/tasks/advanced-elicitation.md +123 -0
  87. package/.claude/commands/BMad/tasks/apply-qa-fixes.md +154 -0
  88. package/.claude/commands/BMad/tasks/brownfield-create-epic.md +166 -0
  89. package/.claude/commands/BMad/tasks/brownfield-create-story.md +153 -0
  90. package/.claude/commands/BMad/tasks/correct-course.md +76 -0
  91. package/.claude/commands/BMad/tasks/create-brownfield-story.md +318 -0
  92. package/.claude/commands/BMad/tasks/create-deep-research-prompt.md +284 -0
  93. package/.claude/commands/BMad/tasks/create-doc.md +107 -0
  94. package/.claude/commands/BMad/tasks/create-next-story.md +118 -0
  95. package/.claude/commands/BMad/tasks/document-project.md +349 -0
  96. package/.claude/commands/BMad/tasks/execute-checklist.md +92 -0
  97. package/.claude/commands/BMad/tasks/facilitate-brainstorming-session.md +142 -0
  98. package/.claude/commands/BMad/tasks/generate-ai-frontend-prompt.md +57 -0
  99. package/.claude/commands/BMad/tasks/index-docs.md +179 -0
  100. package/.claude/commands/BMad/tasks/kb-mode-interaction.md +81 -0
  101. package/.claude/commands/BMad/tasks/nfr-assess.md +349 -0
  102. package/.claude/commands/BMad/tasks/qa-gate.md +167 -0
  103. package/.claude/commands/BMad/tasks/review-story.md +320 -0
  104. package/.claude/commands/BMad/tasks/risk-profile.md +359 -0
  105. package/.claude/commands/BMad/tasks/shard-doc.md +191 -0
  106. package/.claude/commands/BMad/tasks/test-design.md +180 -0
  107. package/.claude/commands/BMad/tasks/trace-requirements.md +270 -0
  108. package/.claude/commands/BMad/tasks/validate-next-story.md +140 -0
  109. package/.claude/commands/agent-vibes/add.md +0 -0
  110. package/.claude/commands/agent-vibes/agent-vibes.md +0 -0
  111. package/.claude/commands/agent-vibes/bmad.md +0 -0
  112. package/.claude/commands/agent-vibes/commands.json +24 -0
  113. package/.claude/commands/agent-vibes/get.md +0 -0
  114. package/.claude/commands/agent-vibes/language.md +23 -0
  115. package/.claude/commands/agent-vibes/learn.md +67 -0
  116. package/.claude/commands/agent-vibes/list.md +0 -0
  117. package/.claude/commands/agent-vibes/personality.md +0 -0
  118. package/.claude/commands/agent-vibes/preview.md +0 -0
  119. package/.claude/commands/agent-vibes/replay-target.md +14 -0
  120. package/.claude/commands/agent-vibes/replay.md +0 -0
  121. package/.claude/commands/agent-vibes/sample.md +0 -0
  122. package/.claude/commands/agent-vibes/sentiment.md +0 -0
  123. package/.claude/commands/agent-vibes/set-language.md +0 -0
  124. package/.claude/commands/agent-vibes/set-pretext.md +0 -0
  125. package/.claude/commands/agent-vibes/set-speed.md +41 -0
  126. package/.claude/commands/agent-vibes/switch.md +0 -0
  127. package/.claude/commands/agent-vibes/target-voice.md +26 -0
  128. package/.claude/commands/agent-vibes/target.md +30 -0
  129. package/.claude/commands/agent-vibes/update.md +0 -0
  130. package/.claude/commands/agent-vibes/version.md +0 -0
  131. package/.claude/commands/agent-vibes/whoami.md +0 -0
  132. package/.claude/github-star-reminder.txt +1 -1
  133. package/.claude/hooks/language-manager.sh +167 -13
  134. package/.claude/hooks/learn-manager.sh +443 -0
  135. package/.claude/hooks/play-tts-elevenlabs.sh +52 -8
  136. package/.claude/hooks/play-tts-piper.sh +82 -8
  137. package/.claude/hooks/play-tts.sh +30 -4
  138. package/.claude/hooks/provider-commands.sh +46 -3
  139. package/.claude/hooks/provider-manager.sh +56 -4
  140. package/.claude/hooks/replay-target-audio.sh +64 -0
  141. package/.claude/hooks/speed-manager.sh +226 -0
  142. package/.claude/language-voices.yaml +0 -0
  143. package/.claude/output-styles/agent-vibes.md +0 -0
  144. package/.claude/personalities/angry.md +0 -0
  145. package/.claude/personalities/annoying.md +0 -0
  146. package/.claude/personalities/crass.md +0 -0
  147. package/.claude/personalities/dramatic.md +0 -0
  148. package/.claude/personalities/dry-humor.md +0 -0
  149. package/.claude/personalities/flirty.md +0 -0
  150. package/.claude/personalities/funny.md +0 -0
  151. package/.claude/personalities/grandpa.md +0 -0
  152. package/.claude/personalities/millennial.md +0 -0
  153. package/.claude/personalities/moody.md +0 -0
  154. package/.claude/personalities/normal.md +0 -0
  155. package/.claude/personalities/pirate.md +0 -0
  156. package/.claude/personalities/poetic.md +0 -0
  157. package/.claude/personalities/professional.md +0 -0
  158. package/.claude/personalities/robot.md +0 -0
  159. package/.claude/personalities/sarcastic.md +0 -0
  160. package/.claude/personalities/sassy.md +0 -0
  161. package/.claude/personalities/surfer-dude.md +0 -0
  162. package/.claude/personalities/zen.md +0 -0
  163. package/.claude/piper-voices/en_US-lessac-medium.onnx +0 -0
  164. package/.claude/piper-voices/en_US-lessac-medium.onnx.json +0 -0
  165. package/.claude/piper-voices-dir.txt +0 -0
  166. package/.claude/plugins/bmad-voices-enabled.flag +0 -0
  167. package/.claude/plugins/bmad-voices.md +0 -0
  168. package/.mcp-minimal.json +6 -8
  169. package/AUDIO_TUNNEL_FIX_SUMMARY.md +0 -0
  170. package/INSTALL_MCP_WINDOWS.md +120 -42
  171. package/LICENSE +0 -0
  172. package/NPM_PUBLISH_GUIDE.md +0 -0
  173. package/README.md +19 -6
  174. package/RELEASE_NOTES.md +97 -0
  175. package/RELEASE_NOTES_V2.md +136 -5
  176. package/agentvibes.org/.claude/commands/agent-vibes/add.md +21 -0
  177. package/agentvibes.org/.claude/commands/agent-vibes/agent-vibes.md +68 -0
  178. package/agentvibes.org/.claude/commands/agent-vibes/commands.json +53 -0
  179. package/agentvibes.org/.claude/commands/agent-vibes/get.md +9 -0
  180. package/agentvibes.org/.claude/commands/agent-vibes/list.md +13 -0
  181. package/agentvibes.org/.claude/commands/agent-vibes/personality.md +79 -0
  182. package/agentvibes.org/.claude/commands/agent-vibes/preview.md +16 -0
  183. package/agentvibes.org/.claude/commands/agent-vibes/provider.md +54 -0
  184. package/agentvibes.org/.claude/commands/agent-vibes/replay.md +19 -0
  185. package/agentvibes.org/.claude/commands/agent-vibes/sample.md +12 -0
  186. package/agentvibes.org/.claude/commands/agent-vibes/sentiment.md +52 -0
  187. package/agentvibes.org/.claude/commands/agent-vibes/set-language.md +47 -0
  188. package/agentvibes.org/.claude/commands/agent-vibes/set-pretext.md +65 -0
  189. package/agentvibes.org/.claude/commands/agent-vibes/switch.md +53 -0
  190. package/agentvibes.org/.claude/commands/agent-vibes/update.md +20 -0
  191. package/agentvibes.org/.claude/commands/agent-vibes/version.md +10 -0
  192. package/agentvibes.org/.claude/commands/agent-vibes/whoami.md +7 -0
  193. package/agentvibes.org/.claude/hooks/bmad-voice-manager.sh +278 -0
  194. package/agentvibes.org/.claude/hooks/language-manager.sh +190 -0
  195. package/agentvibes.org/.claude/hooks/personality-manager.sh +279 -0
  196. package/agentvibes.org/.claude/hooks/piper-download-voices.sh +133 -0
  197. package/agentvibes.org/.claude/hooks/piper-voice-manager.sh +227 -0
  198. package/agentvibes.org/.claude/hooks/play-tts-elevenlabs.sh +201 -0
  199. package/agentvibes.org/.claude/hooks/play-tts-piper.sh +175 -0
  200. package/agentvibes.org/.claude/hooks/play-tts.sh +138 -0
  201. package/agentvibes.org/.claude/hooks/provider-commands.sh +374 -0
  202. package/agentvibes.org/.claude/hooks/provider-manager.sh +196 -0
  203. package/agentvibes.org/.claude/hooks/sentiment-manager.sh +163 -0
  204. package/agentvibes.org/.claude/hooks/voice-manager.sh +349 -0
  205. package/agentvibes.org/.claude/hooks/voices-config.sh +33 -0
  206. package/agentvibes.org/.claude/journal/2025-10-07.html +373 -0
  207. package/agentvibes.org/.claude/journal/index.html +91 -0
  208. package/agentvibes.org/.claude/output-styles/agent-vibes.md +203 -0
  209. package/agentvibes.org/.claude/personalities/angry.md +16 -0
  210. package/agentvibes.org/.claude/personalities/annoying.md +16 -0
  211. package/agentvibes.org/.claude/personalities/crass.md +16 -0
  212. package/agentvibes.org/.claude/personalities/dramatic.md +16 -0
  213. package/agentvibes.org/.claude/personalities/dry-humor.md +52 -0
  214. package/agentvibes.org/.claude/personalities/flirty.md +22 -0
  215. package/agentvibes.org/.claude/personalities/funny.md +16 -0
  216. package/agentvibes.org/.claude/personalities/grandpa.md +34 -0
  217. package/agentvibes.org/.claude/personalities/millennial.md +16 -0
  218. package/agentvibes.org/.claude/personalities/moody.md +16 -0
  219. package/agentvibes.org/.claude/personalities/normal.md +18 -0
  220. package/agentvibes.org/.claude/personalities/pirate.md +16 -0
  221. package/agentvibes.org/.claude/personalities/poetic.md +16 -0
  222. package/agentvibes.org/.claude/personalities/professional.md +16 -0
  223. package/agentvibes.org/.claude/personalities/robot.md +16 -0
  224. package/agentvibes.org/.claude/personalities/sarcastic.md +40 -0
  225. package/agentvibes.org/.claude/personalities/sassy.md +16 -0
  226. package/agentvibes.org/.claude/personalities/surfer-dude.md +16 -0
  227. package/agentvibes.org/.claude/personalities/zen.md +16 -0
  228. package/agentvibes.org/.mcp-minimal.json +60 -0
  229. package/agentvibes.org/CHANGELOG.md +56 -0
  230. package/agentvibes.org/README.md +93 -0
  231. package/agentvibes.org/app/(auth)/layout.tsx +15 -0
  232. package/agentvibes.org/app/(auth)/reset-password/page.tsx +45 -0
  233. package/agentvibes.org/app/(auth)/signin/page.tsx +82 -0
  234. package/agentvibes.org/app/(auth)/signup/page.tsx +104 -0
  235. package/agentvibes.org/app/(default)/layout.tsx +31 -0
  236. package/agentvibes.org/app/(default)/page.tsx +20 -0
  237. package/agentvibes.org/app/api/hello/route.ts +3 -0
  238. package/agentvibes.org/app/css/additional-styles/theme.css +82 -0
  239. package/agentvibes.org/app/css/additional-styles/utility-patterns.css +55 -0
  240. package/agentvibes.org/app/css/style.css +100 -0
  241. package/agentvibes.org/app/layout.tsx +63 -0
  242. package/agentvibes.org/components/cta.tsx +58 -0
  243. package/agentvibes.org/components/features.tsx +256 -0
  244. package/agentvibes.org/components/hero-home.tsx +133 -0
  245. package/agentvibes.org/components/modal-video.tsx +137 -0
  246. package/agentvibes.org/components/page-illustration.tsx +55 -0
  247. package/agentvibes.org/components/spotlight.tsx +77 -0
  248. package/agentvibes.org/components/testimonials.tsx +282 -0
  249. package/agentvibes.org/components/ui/footer.tsx +82 -0
  250. package/agentvibes.org/components/ui/header.tsx +53 -0
  251. package/agentvibes.org/components/ui/logo.tsx +10 -0
  252. package/agentvibes.org/components/workflows.tsx +176 -0
  253. package/agentvibes.org/next.config.js +4 -0
  254. package/agentvibes.org/package-lock.json +1974 -0
  255. package/agentvibes.org/package.json +30 -0
  256. package/agentvibes.org/pnpm-lock.yaml +1141 -0
  257. package/agentvibes.org/postcss.config.js +5 -0
  258. package/agentvibes.org/public/audio/02-sarcastic.mp3 +0 -0
  259. package/agentvibes.org/public/audio/03-angry.mp3 +0 -0
  260. package/agentvibes.org/public/audio/04-grandpa.mp3 +0 -0
  261. package/agentvibes.org/public/audio/05-sarcastic-example2.mp3 +0 -0
  262. package/agentvibes.org/public/audio/french-rachel.mp3 +0 -0
  263. package/agentvibes.org/public/audio/spanish-antoni.mp3 +0 -0
  264. package/agentvibes.org/public/favicon.ico +0 -0
  265. package/agentvibes.org/public/fonts/nacelle-italic.woff2 +0 -0
  266. package/agentvibes.org/public/fonts/nacelle-regular.woff2 +0 -0
  267. package/agentvibes.org/public/fonts/nacelle-semibold.woff2 +0 -0
  268. package/agentvibes.org/public/fonts/nacelle-semibolditalic.woff2 +0 -0
  269. package/agentvibes.org/public/images/blurred-shape-gray.svg +1 -0
  270. package/agentvibes.org/public/images/blurred-shape.svg +1 -0
  271. package/agentvibes.org/public/images/client-logo-01.svg +1 -0
  272. package/agentvibes.org/public/images/client-logo-02.svg +1 -0
  273. package/agentvibes.org/public/images/client-logo-03.svg +1 -0
  274. package/agentvibes.org/public/images/client-logo-04.svg +1 -0
  275. package/agentvibes.org/public/images/client-logo-05.svg +1 -0
  276. package/agentvibes.org/public/images/client-logo-06.svg +1 -0
  277. package/agentvibes.org/public/images/client-logo-07.svg +1 -0
  278. package/agentvibes.org/public/images/client-logo-08.svg +1 -0
  279. package/agentvibes.org/public/images/client-logo-09.svg +1 -0
  280. package/agentvibes.org/public/images/features.png +0 -0
  281. package/agentvibes.org/public/images/footer-illustration.svg +1 -0
  282. package/agentvibes.org/public/images/hero-image-01.jpg +0 -0
  283. package/agentvibes.org/public/images/logo.svg +1 -0
  284. package/agentvibes.org/public/images/page-illustration.svg +1 -0
  285. package/agentvibes.org/public/images/secondary-illustration.svg +1 -0
  286. package/agentvibes.org/public/images/testimonial-01.jpg +0 -0
  287. package/agentvibes.org/public/images/testimonial-02.jpg +0 -0
  288. package/agentvibes.org/public/images/testimonial-03.jpg +0 -0
  289. package/agentvibes.org/public/images/testimonial-04.jpg +0 -0
  290. package/agentvibes.org/public/images/testimonial-05.jpg +0 -0
  291. package/agentvibes.org/public/images/testimonial-06.jpg +0 -0
  292. package/agentvibes.org/public/images/testimonial-07.jpg +0 -0
  293. package/agentvibes.org/public/images/testimonial-08.jpg +0 -0
  294. package/agentvibes.org/public/images/testimonial-09.jpg +0 -0
  295. package/agentvibes.org/public/images/workflow-01.png +0 -0
  296. package/agentvibes.org/public/images/workflow-02.png +0 -0
  297. package/agentvibes.org/public/images/workflow-03.png +0 -0
  298. package/agentvibes.org/public/videos/video.mp4 +0 -0
  299. package/agentvibes.org/tsconfig.json +28 -0
  300. package/agentvibes.org/utils/useMasonry.tsx +67 -0
  301. package/agentvibes.org/utils/useMousePosition.tsx +27 -0
  302. package/bin/mcp-server.js +122 -0
  303. package/docs/ai-optimized-documentation-standards.md +0 -0
  304. package/docs/architecture/provider-system.md +0 -0
  305. package/docs/remote-audio-setup.md +0 -0
  306. package/docs/voice-mapping-format.md +0 -0
  307. package/linkedin/vibe-coding-and-pulseaudio.md +121 -0
  308. package/mcp-server/QUICK_START.md +0 -0
  309. package/mcp-server/README.md +0 -0
  310. package/mcp-server/examples/claude_desktop_config.json +0 -0
  311. package/mcp-server/examples/claude_desktop_config_piper.json +0 -0
  312. package/mcp-server/examples/custom_instructions.md +0 -0
  313. package/mcp-server/pyproject.toml +0 -0
  314. package/mcp-server/requirements.txt +0 -0
  315. package/mcp-server/server.py +87 -25
  316. package/package.json +2 -2
  317. package/scripts/AUTO-MONITOR-SETUP.md +233 -0
  318. package/scripts/CHANGELOG-2025-10-16.md +268 -0
  319. package/scripts/README.md +114 -0
  320. package/scripts/TROUBLESHOOTING.md +258 -0
  321. package/scripts/audio-tunnel.config +17 -0
  322. package/scripts/audio-tunnel.config.example +18 -0
  323. package/scripts/fix-audio-tunnel-complete.sh +255 -0
  324. package/scripts/fix-audio-tunnel.sh +244 -54
  325. package/scripts/health-check-tunnel.sh +93 -0
  326. package/scripts/piper-voice/README.md +0 -0
  327. package/scripts/setup-auto-monitor.sh +86 -0
  328. package/scripts/setup-windows-audio.ps1 +0 -0
  329. package/src/commands/install-mcp.js +0 -0
  330. package/src/installer.js +18 -0
  331. package/templates/activation-instructions-bmad.md +0 -0
  332. package/templates/output-styles/agent-vibes.md +0 -0
  333. package/test/README.md +0 -0
  334. package/test/helpers/test-helper.bash +0 -0
  335. package/test/test-framework.md +0 -0
  336. package/test/unit/personality-manager.bats +0 -0
  337. package/test/unit/play-tts.bats +0 -0
  338. package/test/unit/voice-manager.bats +0 -0
  339. /package/bin/{mcp-server → mcp-server.sh} +0 -0
@@ -0,0 +1,443 @@
1
+ #!/bin/bash
2
+ # Language Learning Mode Manager for AgentVibes
3
+ # Handles dual-language TTS for language learning
4
+
5
+ set -e
6
+
7
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8
+ PROJECT_DIR="$SCRIPT_DIR/../.."
9
+
10
+ # Configuration files (project-local first, then global fallback)
11
+ MAIN_LANG_FILE="$PROJECT_DIR/.claude/tts-main-language.txt"
12
+ TARGET_LANG_FILE="$PROJECT_DIR/.claude/tts-target-language.txt"
13
+ TARGET_VOICE_FILE="$PROJECT_DIR/.claude/tts-target-voice.txt"
14
+ LEARN_MODE_FILE="$PROJECT_DIR/.claude/tts-learn-mode.txt"
15
+
16
+ GLOBAL_MAIN_LANG_FILE="$HOME/.claude/tts-main-language.txt"
17
+ GLOBAL_TARGET_LANG_FILE="$HOME/.claude/tts-target-language.txt"
18
+ GLOBAL_TARGET_VOICE_FILE="$HOME/.claude/tts-target-voice.txt"
19
+ GLOBAL_LEARN_MODE_FILE="$HOME/.claude/tts-learn-mode.txt"
20
+
21
+ # Colors
22
+ GREEN='\033[0;32m'
23
+ YELLOW='\033[1;33m'
24
+ BLUE='\033[0;34m'
25
+ NC='\033[0m'
26
+
27
+ # Get main language
28
+ get_main_language() {
29
+ if [[ -f "$MAIN_LANG_FILE" ]]; then
30
+ cat "$MAIN_LANG_FILE"
31
+ elif [[ -f "$GLOBAL_MAIN_LANG_FILE" ]]; then
32
+ cat "$GLOBAL_MAIN_LANG_FILE"
33
+ else
34
+ echo "english"
35
+ fi
36
+ }
37
+
38
+ # Set main language
39
+ set_main_language() {
40
+ local language="$1"
41
+ if [[ -z "$language" ]]; then
42
+ echo -e "${YELLOW}Usage: learn-manager.sh set-main-language <language>${NC}"
43
+ exit 1
44
+ fi
45
+
46
+ mkdir -p "$PROJECT_DIR/.claude"
47
+ echo "$language" > "$MAIN_LANG_FILE"
48
+ echo -e "${GREEN}✓${NC} Main language set to: $language"
49
+ }
50
+
51
+ # Get target language
52
+ get_target_language() {
53
+ if [[ -f "$TARGET_LANG_FILE" ]]; then
54
+ cat "$TARGET_LANG_FILE"
55
+ elif [[ -f "$GLOBAL_TARGET_LANG_FILE" ]]; then
56
+ cat "$GLOBAL_TARGET_LANG_FILE"
57
+ else
58
+ echo ""
59
+ fi
60
+ }
61
+
62
+ # Get greeting message for a language
63
+ get_greeting_for_language() {
64
+ local language="$1"
65
+
66
+ case "${language,,}" in
67
+ spanish|español)
68
+ echo "¡Hola! Soy tu profesor de español. ¡Vamos a aprender juntos!"
69
+ ;;
70
+ french|français)
71
+ echo "Bonjour! Je suis votre professeur de français. Apprenons ensemble!"
72
+ ;;
73
+ german|deutsch)
74
+ echo "Hallo! Ich bin dein Deutschlehrer. Lass uns zusammen lernen!"
75
+ ;;
76
+ italian|italiano)
77
+ echo "Ciao! Sono il tuo insegnante di italiano. Impariamo insieme!"
78
+ ;;
79
+ portuguese|português)
80
+ echo "Olá! Sou seu professor de português. Vamos aprender juntos!"
81
+ ;;
82
+ chinese|中文|mandarin)
83
+ echo "你好!我是你的中文老师。让我们一起学习吧!"
84
+ ;;
85
+ japanese|日本語)
86
+ echo "こんにちは!私はあなたの日本語の先生です。一緒に勉強しましょう!"
87
+ ;;
88
+ korean|한국어)
89
+ echo "안녕하세요! 저는 당신의 한국어 선생님입니다. 함께 배워봅시다!"
90
+ ;;
91
+ russian|русский)
92
+ echo "Здравствуйте! Я ваш учитель русского языка. Давайте учиться вместе!"
93
+ ;;
94
+ arabic|العربية)
95
+ echo "مرحبا! أنا معلمك للغة العربية. دعونا نتعلم معا!"
96
+ ;;
97
+ hindi|हिन्दी)
98
+ echo "नमस्ते! मैं आपका हिंदी शिक्षक हूं। आइए साथ में सीखें!"
99
+ ;;
100
+ dutch|nederlands)
101
+ echo "Hallo! Ik ben je Nederlandse leraar. Laten we samen leren!"
102
+ ;;
103
+ polish|polski)
104
+ echo "Cześć! Jestem twoim nauczycielem polskiego. Uczmy się razem!"
105
+ ;;
106
+ turkish|türkçe)
107
+ echo "Merhaba! Ben Türkçe öğretmeninizim. Birlikte öğrenelim!"
108
+ ;;
109
+ swedish|svenska)
110
+ echo "Hej! Jag är din svenskalärare. Låt oss lära tillsammans!"
111
+ ;;
112
+ *)
113
+ echo "Hello! I am your language teacher. Let's learn together!"
114
+ ;;
115
+ esac
116
+ }
117
+
118
+ # Set target language
119
+ set_target_language() {
120
+ local language="$1"
121
+ if [[ -z "$language" ]]; then
122
+ echo -e "${YELLOW}Usage: learn-manager.sh set-target-language <language>${NC}"
123
+ exit 1
124
+ fi
125
+
126
+ mkdir -p "$PROJECT_DIR/.claude"
127
+ echo "$language" > "$TARGET_LANG_FILE"
128
+ echo -e "${GREEN}✓${NC} Target language set to: $language"
129
+
130
+ # Automatically set the recommended voice for this language
131
+ local recommended_voice=$(get_recommended_voice_for_language "$language")
132
+ if [[ -n "$recommended_voice" ]]; then
133
+ echo "$recommended_voice" > "$TARGET_VOICE_FILE"
134
+ echo -e "${GREEN}✓${NC} Target voice automatically set to: ${YELLOW}$recommended_voice${NC}"
135
+
136
+ # Detect provider for display
137
+ local provider=""
138
+ if [[ -f "$PROJECT_DIR/.claude/tts-provider.txt" ]]; then
139
+ provider=$(cat "$PROJECT_DIR/.claude/tts-provider.txt")
140
+ elif [[ -f "$HOME/.claude/tts-provider.txt" ]]; then
141
+ provider=$(cat "$HOME/.claude/tts-provider.txt")
142
+ else
143
+ provider="elevenlabs"
144
+ fi
145
+ echo -e " (for ${GREEN}$provider${NC} TTS)"
146
+ echo ""
147
+
148
+ # Greet user in the target language with the target voice
149
+ local greeting=$(get_greeting_for_language "$language")
150
+ echo -e "${BLUE}🎓${NC} Your language teacher says:"
151
+
152
+ # Check if we're using Piper and if the voice is available
153
+ if [[ "$provider" == "piper" ]]; then
154
+ # Quick check: does the voice file exist?
155
+ local voice_dir="${HOME}/.claude/piper-voices"
156
+ if [[ -f "${voice_dir}/${recommended_voice}.onnx" ]]; then
157
+ # Voice exists, play greeting in background
158
+ nohup "$SCRIPT_DIR/play-tts.sh" "$greeting" "$recommended_voice" >/dev/null 2>&1 &
159
+ else
160
+ echo -e "${YELLOW} (Voice not yet downloaded - greeting will play after first download)${NC}"
161
+ fi
162
+ else
163
+ # ElevenLabs - just play it in background
164
+ nohup "$SCRIPT_DIR/play-tts.sh" "$greeting" "$recommended_voice" >/dev/null 2>&1 &
165
+ fi
166
+ else
167
+ # Fallback to suggestion if auto-set failed
168
+ suggest_voice_for_language "$language"
169
+ fi
170
+ }
171
+
172
+ # Get recommended voice for a language (returns voice string, no output)
173
+ get_recommended_voice_for_language() {
174
+ local language="$1"
175
+ local recommended_voice=""
176
+ local provider=""
177
+
178
+ # Detect active provider
179
+ if [[ -f "$PROJECT_DIR/.claude/tts-provider.txt" ]]; then
180
+ provider=$(cat "$PROJECT_DIR/.claude/tts-provider.txt")
181
+ elif [[ -f "$HOME/.claude/tts-provider.txt" ]]; then
182
+ provider=$(cat "$HOME/.claude/tts-provider.txt")
183
+ else
184
+ provider="elevenlabs" # Default
185
+ fi
186
+
187
+ # Source language manager and get provider-specific voice
188
+ if [[ -f "$SCRIPT_DIR/language-manager.sh" ]]; then
189
+ source "$SCRIPT_DIR/language-manager.sh" 2>/dev/null
190
+ recommended_voice=$(get_voice_for_language "$language" "$provider" 2>/dev/null)
191
+ fi
192
+
193
+ # Fallback to hardcoded suggestions if function failed
194
+ if [[ -z "$recommended_voice" ]]; then
195
+ case "${language,,}" in
196
+ spanish|español)
197
+ recommended_voice=$([ "$provider" = "piper" ] && echo "es_ES-davefx-medium" || echo "Antoni")
198
+ ;;
199
+ french|français)
200
+ recommended_voice=$([ "$provider" = "piper" ] && echo "fr_FR-siwis-medium" || echo "Rachel")
201
+ ;;
202
+ german|deutsch)
203
+ recommended_voice=$([ "$provider" = "piper" ] && echo "de_DE-thorsten-medium" || echo "Domi")
204
+ ;;
205
+ italian|italiano)
206
+ recommended_voice=$([ "$provider" = "piper" ] && echo "it_IT-riccardo-x_low" || echo "Bella")
207
+ ;;
208
+ portuguese|português)
209
+ recommended_voice=$([ "$provider" = "piper" ] && echo "pt_BR-faber-medium" || echo "Matilda")
210
+ ;;
211
+ chinese|中文|mandarin)
212
+ recommended_voice=$([ "$provider" = "piper" ] && echo "zh_CN-huayan-medium" || echo "Amy")
213
+ ;;
214
+ *)
215
+ recommended_voice=$([ "$provider" = "piper" ] && echo "en_US-lessac-medium" || echo "Antoni")
216
+ ;;
217
+ esac
218
+ fi
219
+
220
+ echo "$recommended_voice"
221
+ }
222
+
223
+ # Suggest voice based on target language (displays suggestion message)
224
+ suggest_voice_for_language() {
225
+ local language="$1"
226
+ local suggested_voice=$(get_recommended_voice_for_language "$language")
227
+
228
+ # Detect provider for display
229
+ local provider=""
230
+ if [[ -f "$PROJECT_DIR/.claude/tts-provider.txt" ]]; then
231
+ provider=$(cat "$PROJECT_DIR/.claude/tts-provider.txt")
232
+ elif [[ -f "$HOME/.claude/tts-provider.txt" ]]; then
233
+ provider=$(cat "$HOME/.claude/tts-provider.txt")
234
+ else
235
+ provider="elevenlabs"
236
+ fi
237
+
238
+ echo ""
239
+ echo -e "${BLUE}💡 Tip:${NC} For $language (using ${GREEN}$provider${NC} TTS), we recommend: ${YELLOW}$suggested_voice${NC}"
240
+ echo -e " Set it with: ${YELLOW}/agent-vibes:target-voice $suggested_voice${NC}"
241
+ }
242
+
243
+ # Get target voice
244
+ get_target_voice() {
245
+ if [[ -f "$TARGET_VOICE_FILE" ]]; then
246
+ cat "$TARGET_VOICE_FILE"
247
+ elif [[ -f "$GLOBAL_TARGET_VOICE_FILE" ]]; then
248
+ cat "$GLOBAL_TARGET_VOICE_FILE"
249
+ else
250
+ echo ""
251
+ fi
252
+ }
253
+
254
+ # Set target voice
255
+ set_target_voice() {
256
+ local voice="$1"
257
+ if [[ -z "$voice" ]]; then
258
+ echo -e "${YELLOW}Usage: learn-manager.sh set-target-voice <voice>${NC}"
259
+ exit 1
260
+ fi
261
+
262
+ mkdir -p "$PROJECT_DIR/.claude"
263
+ echo "$voice" > "$TARGET_VOICE_FILE"
264
+ echo -e "${GREEN}✓${NC} Target voice set to: $voice"
265
+ }
266
+
267
+ # Check if learning mode is enabled
268
+ is_learn_mode_enabled() {
269
+ if [[ -f "$LEARN_MODE_FILE" ]]; then
270
+ local mode=$(cat "$LEARN_MODE_FILE")
271
+ [[ "$mode" == "ON" ]]
272
+ elif [[ -f "$GLOBAL_LEARN_MODE_FILE" ]]; then
273
+ local mode=$(cat "$GLOBAL_LEARN_MODE_FILE")
274
+ [[ "$mode" == "ON" ]]
275
+ else
276
+ return 1
277
+ fi
278
+ }
279
+
280
+ # Enable learning mode
281
+ enable_learn_mode() {
282
+ mkdir -p "$PROJECT_DIR/.claude"
283
+ echo "ON" > "$LEARN_MODE_FILE"
284
+ echo -e "${GREEN}✓${NC} Language learning mode: ${GREEN}ENABLED${NC}"
285
+ echo ""
286
+
287
+ # Auto-set target voice if target language is set but voice is not
288
+ local target_lang=$(get_target_language)
289
+ local target_voice=$(get_target_voice)
290
+ local voice_was_set=false
291
+
292
+ if [[ -n "$target_lang" ]] && [[ -z "$target_voice" ]]; then
293
+ echo -e "${BLUE}ℹ${NC} Auto-configuring voice for $target_lang..."
294
+ local recommended_voice=$(get_recommended_voice_for_language "$target_lang")
295
+ if [[ -n "$recommended_voice" ]]; then
296
+ echo "$recommended_voice" > "$TARGET_VOICE_FILE"
297
+ target_voice="$recommended_voice"
298
+ echo -e "${GREEN}✓${NC} Target voice automatically set to: ${YELLOW}$recommended_voice${NC}"
299
+
300
+ # Detect provider for display
301
+ local provider=""
302
+ if [[ -f "$PROJECT_DIR/.claude/tts-provider.txt" ]]; then
303
+ provider=$(cat "$PROJECT_DIR/.claude/tts-provider.txt")
304
+ elif [[ -f "$HOME/.claude/tts-provider.txt" ]]; then
305
+ provider=$(cat "$HOME/.claude/tts-provider.txt")
306
+ else
307
+ provider="elevenlabs"
308
+ fi
309
+ echo -e " (for ${GREEN}$provider${NC} TTS)"
310
+ echo ""
311
+ voice_was_set=true
312
+ fi
313
+ fi
314
+
315
+ show_status
316
+
317
+ # Greet user with language teacher if everything is configured
318
+ if [[ -n "$target_lang" ]] && [[ -n "$target_voice" ]]; then
319
+ echo ""
320
+ local greeting=$(get_greeting_for_language "$target_lang")
321
+ echo -e "${BLUE}🎓${NC} Your language teacher says:"
322
+
323
+ # Detect provider
324
+ local provider=""
325
+ if [[ -f "$PROJECT_DIR/.claude/tts-provider.txt" ]]; then
326
+ provider=$(cat "$PROJECT_DIR/.claude/tts-provider.txt")
327
+ elif [[ -f "$HOME/.claude/tts-provider.txt" ]]; then
328
+ provider=$(cat "$HOME/.claude/tts-provider.txt")
329
+ else
330
+ provider="elevenlabs"
331
+ fi
332
+
333
+ # Check if we're using Piper and if the voice is available
334
+ if [[ "$provider" == "piper" ]]; then
335
+ # Quick check: does the voice file exist?
336
+ local voice_dir="${HOME}/.claude/piper-voices"
337
+ if [[ -f "${voice_dir}/${target_voice}.onnx" ]]; then
338
+ # Voice exists, play greeting in background
339
+ nohup "$SCRIPT_DIR/play-tts.sh" "$greeting" "$target_voice" >/dev/null 2>&1 &
340
+ else
341
+ echo -e "${YELLOW} (Voice not yet downloaded - greeting will play after first download)${NC}"
342
+ fi
343
+ else
344
+ # ElevenLabs - just play it in background
345
+ nohup "$SCRIPT_DIR/play-tts.sh" "$greeting" "$target_voice" >/dev/null 2>&1 &
346
+ fi
347
+ fi
348
+ }
349
+
350
+ # Disable learning mode
351
+ disable_learn_mode() {
352
+ mkdir -p "$PROJECT_DIR/.claude"
353
+ echo "OFF" > "$LEARN_MODE_FILE"
354
+ echo -e "${GREEN}✓${NC} Language learning mode: ${YELLOW}DISABLED${NC}"
355
+ }
356
+
357
+ # Show learning mode status
358
+ show_status() {
359
+ local main_lang=$(get_main_language)
360
+ local target_lang=$(get_target_language)
361
+ local target_voice=$(get_target_voice)
362
+ local learn_mode="OFF"
363
+
364
+ if is_learn_mode_enabled; then
365
+ learn_mode="ON"
366
+ fi
367
+
368
+ echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
369
+ echo -e "${BLUE} Language Learning Mode Status${NC}"
370
+ echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
371
+ echo ""
372
+ echo -e " ${BLUE}Learning Mode:${NC} $(if [[ "$learn_mode" == "ON" ]]; then echo -e "${GREEN}ENABLED${NC}"; else echo -e "${YELLOW}DISABLED${NC}"; fi)"
373
+ echo -e " ${BLUE}Main Language:${NC} $main_lang"
374
+ echo -e " ${BLUE}Target Language:${NC} ${target_lang:-"(not set)"}"
375
+ echo -e " ${BLUE}Target Voice:${NC} ${target_voice:-"(not set)"}"
376
+ echo ""
377
+
378
+ if [[ "$learn_mode" == "ON" ]]; then
379
+ if [[ -z "$target_lang" ]]; then
380
+ echo -e " ${YELLOW}⚠${NC} Please set a target language: ${YELLOW}/agent-vibes:target <language>${NC}"
381
+ fi
382
+ if [[ -z "$target_voice" ]]; then
383
+ echo -e " ${YELLOW}⚠${NC} Please set a target voice: ${YELLOW}/agent-vibes:target-voice <voice>${NC}"
384
+ fi
385
+
386
+ if [[ -n "$target_lang" ]] && [[ -n "$target_voice" ]]; then
387
+ echo -e " ${GREEN}✓${NC} All set! TTS will speak in both languages."
388
+ echo ""
389
+ echo -e " ${BLUE}How it works:${NC}"
390
+ echo -e " 1. First: Speak in ${BLUE}$main_lang${NC} (your current voice)"
391
+ echo -e " 2. Then: Speak in ${BLUE}$target_lang${NC} ($target_voice voice)"
392
+ fi
393
+ else
394
+ echo -e " ${BLUE}💡 Tip:${NC} Enable learning mode with: ${YELLOW}/agent-vibes:learn${NC}"
395
+ fi
396
+
397
+ echo ""
398
+ echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
399
+ }
400
+
401
+ # Main command handler
402
+ case "${1:-}" in
403
+ get-main-language)
404
+ get_main_language
405
+ ;;
406
+ set-main-language)
407
+ set_main_language "$2"
408
+ ;;
409
+ get-target-language)
410
+ get_target_language
411
+ ;;
412
+ set-target-language)
413
+ set_target_language "$2"
414
+ ;;
415
+ get-target-voice)
416
+ get_target_voice
417
+ ;;
418
+ set-target-voice)
419
+ set_target_voice "$2"
420
+ ;;
421
+ is-enabled)
422
+ if is_learn_mode_enabled; then
423
+ echo "ON"
424
+ exit 0
425
+ else
426
+ echo "OFF"
427
+ exit 1
428
+ fi
429
+ ;;
430
+ enable)
431
+ enable_learn_mode
432
+ ;;
433
+ disable)
434
+ disable_learn_mode
435
+ ;;
436
+ status)
437
+ show_status
438
+ ;;
439
+ *)
440
+ echo "Usage: learn-manager.sh {get-main-language|set-main-language|get-target-language|set-target-language|get-target-voice|set-target-voice|is-enabled|enable|disable|status}"
441
+ exit 1
442
+ ;;
443
+ esac
@@ -178,10 +178,25 @@ else
178
178
  MODEL_ID="eleven_multilingual_v2"
179
179
  fi
180
180
 
181
+ # Build JSON payload with jq for proper escaping
182
+ PAYLOAD=$(jq -n \
183
+ --arg text "$TEXT" \
184
+ --arg model "$MODEL_ID" \
185
+ --arg lang "$LANGUAGE_CODE" \
186
+ '{
187
+ text: $text,
188
+ model_id: $model,
189
+ language_code: $lang,
190
+ voice_settings: {
191
+ stability: 0.5,
192
+ similarity_boost: 0.75
193
+ }
194
+ }')
195
+
181
196
  curl -s -X POST "https://api.elevenlabs.io/v1/text-to-speech/${VOICE_ID}" \
182
197
  -H "xi-api-key: ${API_KEY}" \
183
198
  -H "Content-Type: application/json" \
184
- -d "{\"text\":\"${TEXT}\",\"model_id\":\"${MODEL_ID}\",\"language_code\":\"${LANGUAGE_CODE}\",\"voice_settings\":{\"stability\":0.5,\"similarity_boost\":0.75}}" \
199
+ -d "$PAYLOAD" \
185
200
  -o "${TEMP_FILE}"
186
201
 
187
202
  # @function add_silence_padding
@@ -200,7 +215,7 @@ if [ -f "${TEMP_FILE}" ]; then
200
215
  # Note: ElevenLabs returns mono audio, so we use mono silence
201
216
  ffmpeg -f lavfi -i anullsrc=r=44100:cl=mono:d=0.2 -i "${TEMP_FILE}" \
202
217
  -filter_complex "[0:a][1:a]concat=n=2:v=0:a=1[out]" \
203
- -map "[out]" -c:a libmp3lame -y "${PADDED_FILE}" 2>/dev/null
218
+ -map "[out]" -c:a libmp3lame -b:a 128k -y "${PADDED_FILE}" 2>/dev/null
204
219
 
205
220
  if [ -f "${PADDED_FILE}" ]; then
206
221
  # Use padded file and clean up original
@@ -211,13 +226,42 @@ if [ -f "${TEMP_FILE}" ]; then
211
226
  fi
212
227
 
213
228
  # @function play_audio
214
- # @intent Play generated audio file using available player
215
- # @why Support multiple audio players (paplay, aplay, mpg123)
216
- # @param Uses global: $TEMP_FILE
217
- # @sideeffects Plays audio in background
229
+ # @intent Play generated audio file using available player with sequential playback
230
+ # @why Support multiple audio players and prevent overlapping audio in learning mode
231
+ # @param Uses global: $TEMP_FILE, $CURRENT_LANGUAGE
232
+ # @sideeffects Plays audio with lock mechanism for sequential playback
218
233
  # @edgecases Falls through players until one works
219
- # Play audio (WSL/Linux) in background to avoid blocking
220
- (paplay "${TEMP_FILE}" 2>/dev/null || aplay "${TEMP_FILE}" 2>/dev/null || mpg123 "${TEMP_FILE}" 2>/dev/null) &
234
+ LOCK_FILE="/tmp/agentvibes-audio.lock"
235
+
236
+ # Wait for previous audio to finish (max 30 seconds)
237
+ for i in {1..60}; do
238
+ if [ ! -f "$LOCK_FILE" ]; then
239
+ break
240
+ fi
241
+ sleep 0.5
242
+ done
243
+
244
+ # Track last target language audio for replay command
245
+ if [[ "$CURRENT_LANGUAGE" != "english" ]]; then
246
+ TARGET_AUDIO_FILE="${CLAUDE_PROJECT_DIR:-.}/.claude/last-target-audio.txt"
247
+ echo "${TEMP_FILE}" > "$TARGET_AUDIO_FILE"
248
+ fi
249
+
250
+ # Create lock and play audio
251
+ touch "$LOCK_FILE"
252
+
253
+ # Get audio duration for proper lock timing
254
+ DURATION=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "${TEMP_FILE}" 2>/dev/null)
255
+ DURATION=${DURATION%.*} # Round to integer
256
+ DURATION=${DURATION:-1} # Default to 1 second if detection fails
257
+
258
+ # Play audio (WSL/Linux) in background to avoid blocking, fully detached
259
+ (paplay "${TEMP_FILE}" || aplay "${TEMP_FILE}" || mpg123 "${TEMP_FILE}") >/dev/null 2>&1 &
260
+ PLAYER_PID=$!
261
+
262
+ # Wait for audio to finish, then release lock
263
+ (sleep $DURATION; rm -f "$LOCK_FILE") &
264
+ disown
221
265
 
222
266
  # Keep temp files for later review - cleaned up weekly by cron
223
267
  echo "🎵 Saved to: ${TEMP_FILE}"
@@ -144,15 +144,60 @@ fi
144
144
  mkdir -p "$AUDIO_DIR"
145
145
  TEMP_FILE="$AUDIO_DIR/tts-$(date +%s).wav"
146
146
 
147
+ # @function get_speech_rate
148
+ # @intent Determine speech rate for Piper synthesis
149
+ # @why Allow slower speech for language learning (default 2.0 for non-English)
150
+ # @returns Speech rate value (default 1.0 for English, 2.0 for others)
151
+ get_speech_rate() {
152
+ local target_config=""
153
+ local main_config=""
154
+
155
+ # Check for target-specific config first (used for learning mode target language)
156
+ if [[ -f "$SCRIPT_DIR/../config/piper-target-speech-rate.txt" ]]; then
157
+ target_config="$SCRIPT_DIR/../config/piper-target-speech-rate.txt"
158
+ elif [[ -f "$HOME/.claude/config/piper-target-speech-rate.txt" ]]; then
159
+ target_config="$HOME/.claude/config/piper-target-speech-rate.txt"
160
+ fi
161
+
162
+ # Check for main config
163
+ if [[ -f "$SCRIPT_DIR/../config/piper-speech-rate.txt" ]]; then
164
+ main_config="$SCRIPT_DIR/../config/piper-speech-rate.txt"
165
+ elif [[ -f "$HOME/.claude/config/piper-speech-rate.txt" ]]; then
166
+ main_config="$HOME/.claude/config/piper-speech-rate.txt"
167
+ fi
168
+
169
+ # If this is a non-English voice and target config exists, use it
170
+ if [[ "$CURRENT_LANGUAGE" != "english" ]] && [[ -n "$target_config" ]]; then
171
+ cat "$target_config" 2>/dev/null
172
+ return
173
+ fi
174
+
175
+ # Otherwise use main config if available
176
+ if [[ -n "$main_config" ]]; then
177
+ # Read only the last non-comment line (the actual number)
178
+ grep -v '^#' "$main_config" 2>/dev/null | grep -v '^$' | tail -1
179
+ return
180
+ fi
181
+
182
+ # Default: 2x slower for non-English (better for language learning)
183
+ if [[ "$CURRENT_LANGUAGE" != "english" ]]; then
184
+ echo "2.0"
185
+ else
186
+ echo "1.0"
187
+ fi
188
+ }
189
+
190
+ SPEECH_RATE=$(get_speech_rate)
191
+
147
192
  # @function synthesize_with_piper
148
193
  # @intent Generate speech using Piper TTS
149
194
  # @why Provides free, offline TTS alternative
150
- # @param Uses globals: $TEXT, $VOICE_PATH
195
+ # @param Uses globals: $TEXT, $VOICE_PATH, $SPEECH_RATE
151
196
  # @returns Creates WAV file at $TEMP_FILE
152
197
  # @exitcode 0=success, 4=synthesis error
153
198
  # @sideeffects Creates audio file
154
199
  # @edgecases Handles piper errors, invalid models
155
- echo "$TEXT" | piper --model "$VOICE_PATH" --output_file "$TEMP_FILE" 2>/dev/null
200
+ echo "$TEXT" | piper --model "$VOICE_PATH" --length-scale "$SPEECH_RATE" --output_file "$TEMP_FILE" 2>/dev/null
156
201
 
157
202
  if [[ ! -f "$TEMP_FILE" ]] || [[ ! -s "$TEMP_FILE" ]]; then
158
203
  echo "❌ Failed to synthesize speech with Piper"
@@ -182,12 +227,41 @@ if command -v ffmpeg &> /dev/null; then
182
227
  fi
183
228
 
184
229
  # @function play_audio
185
- # @intent Play generated audio using available player
186
- # @why Support multiple audio players
187
- # @param Uses global: $TEMP_FILE
188
- # @sideeffects Plays audio in background
189
- # Play audio (WSL/Linux) in background
190
- (mpv "$TEMP_FILE" 2>/dev/null || aplay "$TEMP_FILE" 2>/dev/null || paplay "$TEMP_FILE" 2>/dev/null) &
230
+ # @intent Play generated audio using available player with sequential playback
231
+ # @why Support multiple audio players and prevent overlapping audio in learning mode
232
+ # @param Uses global: $TEMP_FILE, $CURRENT_LANGUAGE
233
+ # @sideeffects Plays audio with lock mechanism for sequential playback
234
+ LOCK_FILE="/tmp/agentvibes-audio.lock"
235
+
236
+ # Wait for previous audio to finish (max 30 seconds)
237
+ for i in {1..60}; do
238
+ if [ ! -f "$LOCK_FILE" ]; then
239
+ break
240
+ fi
241
+ sleep 0.5
242
+ done
243
+
244
+ # Track last target language audio for replay command
245
+ if [[ "$CURRENT_LANGUAGE" != "english" ]]; then
246
+ TARGET_AUDIO_FILE="${CLAUDE_PROJECT_DIR:-.}/.claude/last-target-audio.txt"
247
+ echo "$TEMP_FILE" > "$TARGET_AUDIO_FILE"
248
+ fi
249
+
250
+ # Create lock and play audio
251
+ touch "$LOCK_FILE"
252
+
253
+ # Get audio duration for proper lock timing
254
+ DURATION=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$TEMP_FILE" 2>/dev/null)
255
+ DURATION=${DURATION%.*} # Round to integer
256
+ DURATION=${DURATION:-1} # Default to 1 second if detection fails
257
+
258
+ # Play audio in background
259
+ (mpv "$TEMP_FILE" || aplay "$TEMP_FILE" || paplay "$TEMP_FILE") >/dev/null 2>&1 &
260
+ PLAYER_PID=$!
261
+
262
+ # Wait for audio to finish, then release lock
263
+ (sleep $DURATION; rm -f "$LOCK_FILE") &
264
+ disown
191
265
 
192
266
  echo "🎵 Saved to: $TEMP_FILE"
193
267
  echo "🎤 Voice used: $VOICE_MODEL (Piper TTS)"
@@ -1,12 +1,12 @@
1
1
  #!/bin/bash
2
2
  #
3
- # @fileoverview TTS Provider Router
3
+ # @fileoverview TTS Provider Router with Language Learning Support
4
4
  # @context Routes TTS requests to active provider (ElevenLabs or Piper)
5
5
  # @architecture Provider abstraction layer - single entry point for all TTS
6
- # @dependencies provider-manager.sh, play-tts-elevenlabs.sh, play-tts-piper.sh
6
+ # @dependencies provider-manager.sh, play-tts-elevenlabs.sh, play-tts-piper.sh, learn-manager.sh
7
7
  # @entrypoints Called by hooks, slash commands, and personality-manager.sh
8
8
  # @patterns Provider pattern - delegates to provider-specific implementations
9
- # @related provider-manager.sh, play-tts-elevenlabs.sh, play-tts-piper.sh
9
+ # @related provider-manager.sh, play-tts-elevenlabs.sh, play-tts-piper.sh, learn-manager.sh
10
10
  #
11
11
 
12
12
  # Fix locale warnings
@@ -27,7 +27,33 @@ ACTIVE_PROVIDER=$(get_active_provider)
27
27
  # Show GitHub star reminder (once per day)
28
28
  "$SCRIPT_DIR/github-star-reminder.sh" 2>/dev/null || true
29
29
 
30
- # Route to appropriate provider implementation
30
+ # @function detect_voice_provider
31
+ # @intent Auto-detect provider from voice name (for mixed-provider support)
32
+ # @why Allow ElevenLabs for main language + Piper for target language
33
+ # @param $1 voice name/ID
34
+ # @returns Provider name (elevenlabs or piper)
35
+ detect_voice_provider() {
36
+ local voice="$1"
37
+ # Piper voice names contain underscore and dash (e.g., es_ES-davefx-medium)
38
+ if [[ "$voice" == *"_"*"-"* ]]; then
39
+ echo "piper"
40
+ else
41
+ echo "$ACTIVE_PROVIDER"
42
+ fi
43
+ }
44
+
45
+ # Override provider if voice indicates different provider (mixed-provider mode)
46
+ if [[ -n "$VOICE_OVERRIDE" ]]; then
47
+ DETECTED_PROVIDER=$(detect_voice_provider "$VOICE_OVERRIDE")
48
+ if [[ "$DETECTED_PROVIDER" != "$ACTIVE_PROVIDER" ]]; then
49
+ ACTIVE_PROVIDER="$DETECTED_PROVIDER"
50
+ fi
51
+ fi
52
+
53
+ # Normal single-language mode - route to appropriate provider implementation
54
+ # Note: For learning mode, the output style will call this script TWICE:
55
+ # 1. First call with main language text and current voice
56
+ # 2. Second call with translated text and target voice
31
57
  case "$ACTIVE_PROVIDER" in
32
58
  elevenlabs)
33
59
  exec "$SCRIPT_DIR/play-tts-elevenlabs.sh" "$TEXT" "$VOICE_OVERRIDE"