agentvibes 5.11.2 → 5.12.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 (54) hide show
  1. package/.claude/config/audio-effects.cfg +1 -1
  2. package/.claude/config/audio-effects.cfg.bak-kokoro +7 -0
  3. package/.claude/github-star-reminder.txt +1 -1
  4. package/.claude/hooks/audio-processor.sh +1 -1
  5. package/.claude/hooks/background-music-manager.sh +2 -1
  6. package/.claude/hooks/bmad-speak-enhanced.sh +37 -22
  7. package/.claude/hooks/bmad-speak.sh +26 -8
  8. package/.claude/hooks/play-tts-agentvibes-receiver-for-voiceless-connections.sh +1 -1
  9. package/.claude/hooks/play-tts-kokoro.sh +9 -0
  10. package/.claude/hooks/play-tts-piper.sh +13 -1
  11. package/.claude/hooks/play-tts-ssh-remote.sh +117 -7
  12. package/.claude/hooks/play-tts-termux-ssh.sh +1 -1
  13. package/.claude/hooks/play-tts.sh +106 -13
  14. package/.claude/hooks-windows/background-music-manager.ps1 +2 -1
  15. package/.claude/hooks-windows/play-tts-kokoro.ps1 +14 -0
  16. package/.claude/hooks-windows/play-tts.ps1 +163 -30
  17. package/.claude/hooks-windows/tts-watcher.ps1 +55 -0
  18. package/.claude/hooks-windows/voice-manager-windows.ps1 +101 -1
  19. package/README.md +11 -6
  20. package/RELEASE_NOTES.md +67 -0
  21. package/bin/mcp-server.sh +6 -19
  22. package/bin/resolve-utterance.js +137 -0
  23. package/mcp-server/server.py +280 -99
  24. package/mcp-server/test_mcp_correctness.py +486 -0
  25. package/mcp-server/test_windows_script_parity.py +341 -336
  26. package/package.json +3 -2
  27. package/setup-windows.ps1 +867 -815
  28. package/src/console/app.js +14 -11
  29. package/src/console/footer-config.js +0 -4
  30. package/src/console/navigation.js +0 -1
  31. package/src/console/tabs/agents-tab.js +96 -11
  32. package/src/console/tabs/music-tab.js +108 -3
  33. package/src/console/tabs/placeholder-tab.js +0 -2
  34. package/src/console/tabs/settings-tab.js +41 -2
  35. package/src/console/tabs/setup-tab.js +34 -6
  36. package/src/console/tabs/voices-tab.js +19 -9
  37. package/src/console/widgets/track-picker.js +3 -3
  38. package/src/i18n/de.js +0 -1
  39. package/src/i18n/en.js +0 -1
  40. package/src/i18n/es.js +0 -1
  41. package/src/i18n/fr.js +0 -1
  42. package/src/i18n/hi.js +0 -1
  43. package/src/i18n/ja.js +0 -1
  44. package/src/i18n/ko.js +0 -1
  45. package/src/i18n/pt.js +0 -1
  46. package/src/i18n/zh-CN.js +0 -1
  47. package/src/installer.js +205 -15
  48. package/src/services/config-service.js +264 -264
  49. package/src/services/llm-provider-service.js +7 -7
  50. package/src/services/navigation-service.js +1 -1
  51. package/src/services/utterance-loader.js +280 -0
  52. package/src/services/utterance-resolver.js +526 -0
  53. package/templates/agentvibes-receiver.sh +74 -12
  54. package/voice-assignments.json +8245 -0
@@ -0,0 +1,137 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * File: bin/resolve-utterance.js
4
+ *
5
+ * CLI bridge between the pure Node utterance resolver and the bash/PowerShell/
6
+ * Python player scripts (Story AVI-S8.5, Stage 2). Reads all config once via the
7
+ * loader, resolves the plan, and prints it as one line of JSON on stdout.
8
+ *
9
+ * Players call this ONCE and execute the returned plan verbatim — they no longer
10
+ * read config or make precedence decisions themselves.
11
+ *
12
+ * Usage:
13
+ * resolve-utterance.js --text "hello" [--llm claude-code] [--voice af_bella]
14
+ * [--voice-source user-explicit] [--project-dir /path] [--personality pirate]
15
+ *
16
+ * Output (stdout):
17
+ * default / --format json : a single JSON object (the UtterancePlan).
18
+ * --format sh : safe `AV_<FIELD>=<single-quoted>` lines a POSIX
19
+ * shell can `eval`. Booleans emit 'true'/'false';
20
+ * nested music/ssh fields flatten to AV_MUSIC_*,
21
+ * AV_SSH_*. This is how bash/zsh players consume the
22
+ * plan without a JSON parser.
23
+ * Nothing else is printed to stdout so callers can parse it directly;
24
+ * diagnostics go to stderr. Exit codes: 0 = plan emitted; 2 = the resolved plan
25
+ * failed validation (a loud failure — never emit a silently-wrong plan).
26
+ */
27
+
28
+ 'use strict';
29
+
30
+ import os from 'node:os';
31
+ import { gatherInputs } from '../src/services/utterance-loader.js';
32
+ import { resolveUtterance, validatePlan } from '../src/services/utterance-resolver.js';
33
+
34
+ /** Minimal --flag value parser (no external deps; players pass simple flags). */
35
+ // Flags that take a value. For these we ALWAYS consume the next token as the
36
+ // value — even if it starts with "--" (a message like "-- shipping now" must not
37
+ // be misread as an absent value and turned into boolean true, which would make
38
+ // TTS literally speak "true"). Anything else is treated as a boolean flag.
39
+ const VALUE_FLAGS = new Set([
40
+ 'text', 'voice', 'voiceSource', 'llm', 'personality',
41
+ 'projectDir', 'packageRoot', 'format', 'language',
42
+ ]);
43
+ function parseArgs(argv) {
44
+ const out = {};
45
+ for (let i = 0; i < argv.length; i++) {
46
+ const a = argv[i];
47
+ if (!a.startsWith('--')) continue;
48
+ const key = a.slice(2).replace(/-([a-z])/g, (_, c) => c.toUpperCase());
49
+ if (VALUE_FLAGS.has(key)) {
50
+ out[key] = (i + 1 < argv.length) ? argv[++i] : '';
51
+ } else {
52
+ out[key] = true;
53
+ }
54
+ }
55
+ return out;
56
+ }
57
+
58
+ function main() {
59
+ const args = parseArgs(process.argv.slice(2));
60
+ const ctx = {
61
+ text: args.text ?? '',
62
+ voice: args.voice,
63
+ voiceSource: args.voiceSource,
64
+ llm: args.llm,
65
+ personality: args.personality,
66
+ projectDir: args.projectDir,
67
+ packageRoot: args.packageRoot,
68
+ homeDir: os.homedir(),
69
+ cwd: process.cwd(),
70
+ env: process.env,
71
+ };
72
+
73
+ let plan;
74
+ try {
75
+ const inputs = gatherInputs(ctx);
76
+ plan = resolveUtterance(inputs);
77
+ } catch (err) {
78
+ process.stderr.write(`resolve-utterance: failed to resolve plan: ${err.message}\n`);
79
+ process.exit(2);
80
+ }
81
+
82
+ const problems = validatePlan(plan);
83
+ if (problems.length) {
84
+ // Fail loud — a malformed plan must never be executed (silent-wrong audio).
85
+ process.stderr.write(`resolve-utterance: invalid plan: ${problems.join('; ')}\n`);
86
+ process.exit(2);
87
+ }
88
+
89
+ if (args.format === 'sh') {
90
+ process.stdout.write(toShell(plan));
91
+ } else {
92
+ process.stdout.write(JSON.stringify(plan) + '\n');
93
+ }
94
+ }
95
+
96
+ /** Single-quote a value for safe POSIX-shell eval (wrap, escaping embedded quotes). */
97
+ function shq(v) {
98
+ return `'${String(v).replace(/'/g, `'\\''`)}'`;
99
+ }
100
+
101
+ /** Flatten a plan into `AV_<FIELD>=<quoted>` lines for `eval` in a shell player. */
102
+ function toShell(plan) {
103
+ const b = (x) => (x ? 'true' : 'false');
104
+ const m = plan.music || {};
105
+ const s = plan.sshTarget || {};
106
+ const lines = [
107
+ `AV_TEXT=${shq(plan.text ?? '')}`,
108
+ `AV_VOICE=${shq(plan.voice ?? '')}`,
109
+ `AV_VOICE_IS_OVERRIDE=${b(plan.voiceIsOverride)}`,
110
+ `AV_ENGINE=${shq(plan.engine ?? '')}`,
111
+ `AV_TRANSPORT=${shq(plan.transport ?? 'local')}`,
112
+ `AV_VOICE_MODEL=${shq(plan.voiceModel ?? '')}`,
113
+ `AV_SPEAKER_ID=${shq(plan.speakerId ?? '')}`,
114
+ `AV_PERSONALITY=${shq(plan.personality ?? '')}`,
115
+ `AV_LANGUAGE=${shq(plan.language ?? '')}`,
116
+ `AV_PRETEXT=${shq(plan.pretext ?? '')}`,
117
+ `AV_SPEED=${shq(plan.speed ?? '')}`,
118
+ `AV_REVERB=${shq(plan.reverb ?? 'off')}`,
119
+ `AV_EFFECTS=${shq(plan.effects ?? '')}`,
120
+ `AV_MUSIC_ENABLED=${b(m.enabled)}`,
121
+ `AV_MUSIC_TRACK=${shq(m.track ?? '')}`,
122
+ `AV_MUSIC_VOLUME=${shq(m.volume ?? '')}`,
123
+ `AV_MUTE=${b(plan.mute)}`,
124
+ `AV_RDP_MODE=${b(plan.rdpMode)}`,
125
+ `AV_NO_PLAYBACK=${b(plan.noPlayback)}`,
126
+ `AV_TEST_MODE=${b(plan.testMode)}`,
127
+ `AV_LLM_KEY=${shq(plan.llmKey ?? '')}`,
128
+ `AV_PROJECT_DIR=${shq(plan.projectDir ?? '')}`,
129
+ `AV_SSH_HOST=${shq(s.host ?? '')}`,
130
+ `AV_SSH_PORT=${shq(s.port ?? '')}`,
131
+ `AV_SSH_PASS_PORT_FLAG=${b(s.passPortFlag)}`,
132
+ `AV_SSH_KEY=${shq(s.key ?? '')}`,
133
+ ];
134
+ return lines.join('\n') + '\n';
135
+ }
136
+
137
+ main();