agentvibes 5.1.4 → 5.2.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 (32) hide show
  1. package/.agentvibes/config.json +23 -13
  2. package/.claude/commands/agent-vibes/verbosity.md +98 -89
  3. package/.claude/config/audio-effects.cfg +4 -1
  4. package/.claude/hooks/bmad-speak.sh +2 -2
  5. package/.claude/hooks/piper-download-voices.sh +233 -225
  6. package/.claude/hooks/piper-installer.sh +1 -1
  7. package/.claude/hooks/piper-voice-manager.sh +125 -0
  8. package/.claude/hooks/play-tts-agentvibes-receiver-for-voiceless-connections.sh +97 -90
  9. package/.claude/hooks/play-tts-enhanced.sh +1 -1
  10. package/.claude/hooks/play-tts-piper.sh +16 -5
  11. package/.claude/hooks/play-tts-ssh-remote.sh +168 -167
  12. package/.claude/hooks/play-tts.sh +21 -9
  13. package/.claude/hooks/session-start-tts.sh +4 -1
  14. package/.claude/hooks/stop-tts.sh +1 -1
  15. package/.claude/hooks/verbosity-manager.sh +185 -178
  16. package/.claude/hooks-windows/download-extra-voices.ps1 +243 -185
  17. package/.claude/hooks-windows/play-tts-piper.ps1 +7 -2
  18. package/.claude/hooks-windows/play-tts.ps1 +7 -1
  19. package/.claude/hooks-windows/session-start-tts.ps1 +2 -1
  20. package/.claude/hooks-windows/verbosity-manager.ps1 +126 -119
  21. package/README.md +10 -2
  22. package/RELEASE_NOTES.md +36 -0
  23. package/bin/agentvibes-voice-browser.js +1939 -1840
  24. package/mcp-server/server.py +52 -9
  25. package/package.json +1 -1
  26. package/src/console/tabs/receiver-tab.js +1527 -1483
  27. package/src/console/tabs/settings-tab.js +2 -2
  28. package/src/console/tabs/setup-tab.js +53 -8
  29. package/src/console/tabs/voices-tab.js +130 -13
  30. package/src/i18n/en.js +202 -202
  31. package/src/services/verbosity-service.js +159 -157
  32. package/templates/agentvibes-receiver.sh +3 -2
@@ -1,157 +1,159 @@
1
- /**
2
- * AgentVibes VerbosityService
3
- * Epic 10: Stories 10.1-10.4
4
- *
5
- * Centralises verbosity logic for 5 levels: minimal, low, medium, high, custom.
6
- *
7
- * Hook types:
8
- * - 'prompt-submit' — fires when user submits a prompt
9
- * - 'response-complete' — fires when Claude finishes responding
10
- */
11
-
12
- // ---------------------------------------------------------------------------
13
-
14
- /**
15
- * Ordered verbosity levels from quietest to most verbose.
16
- * @type {string[]}
17
- */
18
- export const VERBOSITY_LEVELS = Object.freeze(['minimal', 'low', 'medium', 'high', 'custom']);
19
-
20
- // Per-level shouldSpeak configuration (fixed levels only; custom reads from config)
21
- const LEVEL_SPEAK = Object.freeze({
22
- minimal: { 'prompt-submit': false, 'response-complete': true },
23
- low: { 'prompt-submit': false, 'response-complete': true },
24
- medium: { 'prompt-submit': true, 'response-complete': true },
25
- high: { 'prompt-submit': true, 'response-complete': true },
26
- });
27
-
28
- // Per-level static messages (null = use hook default message)
29
- const LEVEL_MESSAGES = Object.freeze({
30
- minimal: {
31
- 'prompt-submit': null,
32
- 'response-complete': 'Claude is ready for your input',
33
- },
34
- low: {
35
- 'prompt-submit': null,
36
- 'response-complete': null, // built dynamically: "Done. <summary>"
37
- },
38
- medium: { 'prompt-submit': null, 'response-complete': null },
39
- high: { 'prompt-submit': null, 'response-complete': null },
40
- });
41
-
42
- // ---------------------------------------------------------------------------
43
-
44
- export class VerbosityService {
45
- /**
46
- * @param {object} configService - AgentVibes ConfigService instance
47
- */
48
- constructor(configService) {
49
- this._config = configService;
50
- this._migrated = false; // tracks whether migration ran in this session
51
- }
52
-
53
- /**
54
- * Returns the current verbosity level.
55
- * Defaults to 'high' if not configured or unrecognised.
56
- * @returns {'minimal'|'low'|'medium'|'high'|'custom'}
57
- */
58
- getLevel() {
59
- const cfg = this._config.getConfig();
60
- const level = cfg.verbosity;
61
- return VERBOSITY_LEVELS.includes(level) ? level : 'high';
62
- }
63
-
64
- /**
65
- * Returns whether TTS should speak for the given hook type.
66
- *
67
- * @param {'prompt-submit'|'response-complete'} hookType
68
- * @returns {boolean}
69
- */
70
- shouldSpeak(hookType) {
71
- const level = this.getLevel();
72
- if (level === 'custom') {
73
- return this._customShouldSpeak(hookType);
74
- }
75
- const table = LEVEL_SPEAK[level] ?? LEVEL_SPEAK.high;
76
- return table[hookType] ?? true;
77
- }
78
-
79
- /**
80
- * Returns the message for the given hook type and context.
81
- * Returns null to use the hook's own default message.
82
- *
83
- * @param {'prompt-submit'|'response-complete'} hookType
84
- * @param {object} context - { summary?: string }
85
- * @returns {string|null}
86
- */
87
- getMessage(hookType, context) {
88
- const level = this.getLevel();
89
- if (level === 'high' || level === 'medium') return null;
90
-
91
- if (level === 'low' && hookType === 'response-complete') {
92
- const summary = context?.summary ?? '';
93
- const trimmed = summary.slice(0, 30);
94
- return trimmed.length > 0 ? `Done. ${trimmed}` : 'Done';
95
- }
96
-
97
- if (level === 'custom') return null; // custom uses hook defaults
98
-
99
- return LEVEL_MESSAGES[level]?.[hookType] ?? null;
100
- }
101
-
102
- /**
103
- * Checks if migration is needed (old 'low' → 'medium').
104
- * If needed and not already done, performs migration and returns true.
105
- * @returns {boolean} true if migration was performed, false otherwise
106
- */
107
- checkMigration() {
108
- const cfg = this._config.getConfig();
109
- if (cfg.verbosityMigrated) return false;
110
- if (cfg.verbosity !== 'low') return false;
111
-
112
- // Migrate: old 'low' users get 'medium' in new system
113
- this._config.set('verbosity', 'medium');
114
- this._config.set('verbosityMigrated', true);
115
- this._migrated = true;
116
- return true;
117
- }
118
-
119
- /**
120
- * Returns true if a migration notice should be shown to the user.
121
- * @returns {boolean}
122
- */
123
- needsMigrationNotice() {
124
- if (!this._migrated) return false;
125
- const cfg = this._config.getConfig();
126
- return !cfg.migrationNoticeDismissed;
127
- }
128
-
129
- /**
130
- * Marks the migration notice as dismissed.
131
- */
132
- dismissMigrationNotice() {
133
- this._config.set('migrationNoticeDismissed', true);
134
- }
135
-
136
- // ---------------------------------------------------------------------------
137
- // Private
138
-
139
- /**
140
- * shouldSpeak for CUSTOM level — reads per-hook toggles from config.customVerbosity.
141
- * @param {string} hookType
142
- * @returns {boolean}
143
- */
144
- _customShouldSpeak(hookType) {
145
- const cfg = this._config.getConfig();
146
- const custom = cfg.customVerbosity ?? {};
147
- const keyMap = {
148
- 'prompt-submit': 'promptSubmit',
149
- 'response-complete': 'responseComplete',
150
- };
151
- const key = keyMap[hookType];
152
- if (key === undefined) return true;
153
- return custom[key] !== false; // default true if not configured
154
- }
155
- }
156
-
157
- export default VerbosityService;
1
+ /**
2
+ * AgentVibes VerbosityService
3
+ * Epic 10: Stories 10.1-10.4
4
+ *
5
+ * Centralises verbosity logic for 5 levels: minimal, low, medium, high, custom.
6
+ *
7
+ * Hook types:
8
+ * - 'prompt-submit' — fires when user submits a prompt
9
+ * - 'response-complete' — fires when Claude finishes responding
10
+ */
11
+
12
+ // ---------------------------------------------------------------------------
13
+
14
+ /**
15
+ * Ordered verbosity levels from quietest to most verbose.
16
+ * @type {string[]}
17
+ */
18
+ export const VERBOSITY_LEVELS = Object.freeze(['minimal', 'low', 'medium', 'high', 'caveman', 'custom']);
19
+
20
+ // Per-level shouldSpeak configuration (fixed levels only; custom reads from config)
21
+ const LEVEL_SPEAK = Object.freeze({
22
+ minimal: { 'prompt-submit': false, 'response-complete': true },
23
+ low: { 'prompt-submit': false, 'response-complete': true },
24
+ medium: { 'prompt-submit': true, 'response-complete': true },
25
+ high: { 'prompt-submit': true, 'response-complete': true },
26
+ caveman: { 'prompt-submit': true, 'response-complete': true },
27
+ });
28
+
29
+ // Per-level static messages (null = use hook default message)
30
+ const LEVEL_MESSAGES = Object.freeze({
31
+ minimal: {
32
+ 'prompt-submit': null,
33
+ 'response-complete': 'Claude is ready for your input',
34
+ },
35
+ low: {
36
+ 'prompt-submit': null,
37
+ 'response-complete': null, // built dynamically: "Done. <summary>"
38
+ },
39
+ medium: { 'prompt-submit': null, 'response-complete': null },
40
+ high: { 'prompt-submit': null, 'response-complete': null },
41
+ caveman: { 'prompt-submit': null, 'response-complete': null },
42
+ });
43
+
44
+ // ---------------------------------------------------------------------------
45
+
46
+ export class VerbosityService {
47
+ /**
48
+ * @param {object} configService - AgentVibes ConfigService instance
49
+ */
50
+ constructor(configService) {
51
+ this._config = configService;
52
+ this._migrated = false; // tracks whether migration ran in this session
53
+ }
54
+
55
+ /**
56
+ * Returns the current verbosity level.
57
+ * Defaults to 'high' if not configured or unrecognised.
58
+ * @returns {'minimal'|'low'|'medium'|'high'|'custom'}
59
+ */
60
+ getLevel() {
61
+ const cfg = this._config.getConfig();
62
+ const level = cfg.verbosity;
63
+ return VERBOSITY_LEVELS.includes(level) ? level : 'high';
64
+ }
65
+
66
+ /**
67
+ * Returns whether TTS should speak for the given hook type.
68
+ *
69
+ * @param {'prompt-submit'|'response-complete'} hookType
70
+ * @returns {boolean}
71
+ */
72
+ shouldSpeak(hookType) {
73
+ const level = this.getLevel();
74
+ if (level === 'custom') {
75
+ return this._customShouldSpeak(hookType);
76
+ }
77
+ const table = LEVEL_SPEAK[level] ?? LEVEL_SPEAK.high;
78
+ return table[hookType] ?? true;
79
+ }
80
+
81
+ /**
82
+ * Returns the message for the given hook type and context.
83
+ * Returns null to use the hook's own default message.
84
+ *
85
+ * @param {'prompt-submit'|'response-complete'} hookType
86
+ * @param {object} context - { summary?: string }
87
+ * @returns {string|null}
88
+ */
89
+ getMessage(hookType, context) {
90
+ const level = this.getLevel();
91
+ if (level === 'high' || level === 'medium' || level === 'caveman') return null;
92
+
93
+ if (level === 'low' && hookType === 'response-complete') {
94
+ const summary = context?.summary ?? '';
95
+ const trimmed = summary.slice(0, 30);
96
+ return trimmed.length > 0 ? `Done. ${trimmed}` : 'Done';
97
+ }
98
+
99
+ if (level === 'custom') return null; // custom uses hook defaults
100
+
101
+ return LEVEL_MESSAGES[level]?.[hookType] ?? null;
102
+ }
103
+
104
+ /**
105
+ * Checks if migration is needed (old 'low' → 'medium').
106
+ * If needed and not already done, performs migration and returns true.
107
+ * @returns {boolean} true if migration was performed, false otherwise
108
+ */
109
+ checkMigration() {
110
+ const cfg = this._config.getConfig();
111
+ if (cfg.verbosityMigrated) return false;
112
+ if (cfg.verbosity !== 'low') return false;
113
+
114
+ // Migrate: old 'low' users get 'medium' in new system
115
+ this._config.set('verbosity', 'medium');
116
+ this._config.set('verbosityMigrated', true);
117
+ this._migrated = true;
118
+ return true;
119
+ }
120
+
121
+ /**
122
+ * Returns true if a migration notice should be shown to the user.
123
+ * @returns {boolean}
124
+ */
125
+ needsMigrationNotice() {
126
+ if (!this._migrated) return false;
127
+ const cfg = this._config.getConfig();
128
+ return !cfg.migrationNoticeDismissed;
129
+ }
130
+
131
+ /**
132
+ * Marks the migration notice as dismissed.
133
+ */
134
+ dismissMigrationNotice() {
135
+ this._config.set('migrationNoticeDismissed', true);
136
+ }
137
+
138
+ // ---------------------------------------------------------------------------
139
+ // Private
140
+
141
+ /**
142
+ * shouldSpeak for CUSTOM level — reads per-hook toggles from config.customVerbosity.
143
+ * @param {string} hookType
144
+ * @returns {boolean}
145
+ */
146
+ _customShouldSpeak(hookType) {
147
+ const cfg = this._config.getConfig();
148
+ const custom = cfg.customVerbosity ?? {};
149
+ const keyMap = {
150
+ 'prompt-submit': 'promptSubmit',
151
+ 'response-complete': 'responseComplete',
152
+ };
153
+ const key = keyMap[hookType];
154
+ if (key === undefined) return true;
155
+ return custom[key] !== false; // default true if not configured
156
+ }
157
+ }
158
+
159
+ export default VerbosityService;
@@ -201,8 +201,9 @@ if [[ -z "$TEXT" ]]; then
201
201
  exit 1
202
202
  fi
203
203
 
204
- # SECURITY: Validate voice format (alphanumeric, hyphens, underscores only)
205
- if [[ ! "$VOICE" =~ ^[a-zA-Z0-9_-]+$ ]]; then
204
+ # SECURITY: Validate voice format (allow :: for multi-speaker, . for locale, space for names)
205
+ _voice_re='^[a-zA-Z0-9_.: -]+$'
206
+ if [[ ! "$VOICE" =~ $_voice_re ]]; then
206
207
  echo "Error: Invalid voice format" >&2
207
208
  exit 1
208
209
  fi