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,45 @@
1
+ /**
2
+ * AgentVibes TUI Console — Placeholder Tab Component
3
+ * Story 6.2: Tab Bar & Global Keyboard Navigation
4
+ *
5
+ * Creates a stub content box for each tab ID.
6
+ * These are replaced by real tab implementations in Epics 7-11.
7
+ */
8
+
9
+ import blessed from 'blessed';
10
+
11
+ /**
12
+ * Create a hidden placeholder box for a tab, appended into the content area.
13
+ *
14
+ * @param {object} contentArea - Blessed box to append into (this.contentArea from app.js)
15
+ * @param {string} label - Human-readable tab name for display (e.g. 'Settings')
16
+ * @returns {object} The created Blessed box widget
17
+ */
18
+ export function createPlaceholderTab(contentArea, label) {
19
+ const box = blessed.box({
20
+ parent: contentArea,
21
+ top: 0,
22
+ left: 0,
23
+ width: '100%',
24
+ height: '100%',
25
+ content: `{center}{bold}${label}{/bold}{/center}\n\n{center}Coming in a future story...{/center}`,
26
+ tags: true,
27
+ hidden: true,
28
+ style: {
29
+ fg: '#90a4ae',
30
+ bg: '#0a0e1a',
31
+ },
32
+ });
33
+
34
+ return box;
35
+ }
36
+
37
+ /** Map of tabId → display label for all 7 tabs */
38
+ export const TAB_DISPLAY_LABELS = {
39
+ settings: 'Settings',
40
+ voices: 'Voices',
41
+ music: 'Music',
42
+ readme: 'Readme',
43
+ help: 'Help',
44
+ install: 'Install',
45
+ };
@@ -0,0 +1,267 @@
1
+ /**
2
+ * AgentVibes TUI Console — Readme Tab
3
+ * Epic 13: Story 13.2
4
+ *
5
+ * Implements the Tab Component Contract:
6
+ * createReadmeTab(screen, services) → { box, show, hide, onFocus, onBlur, getFooterText, getFooterColor }
7
+ *
8
+ * Features: renders README.md with styled markdown, scrolling, search.
9
+ */
10
+
11
+ import fs from 'node:fs';
12
+ import path from 'node:path';
13
+
14
+ const IS_TEST = process.env.AGENTVIBES_TEST_MODE === 'true';
15
+
16
+ let blessed;
17
+ if (!IS_TEST) {
18
+ const { default: b } = await import('blessed');
19
+ blessed = b;
20
+ }
21
+
22
+ // ---------------------------------------------------------------------------
23
+
24
+ const COLORS = {
25
+ contentBg: '#0a0e1a',
26
+ h1Fg: '#69f0ae', // Green — H1
27
+ h2Fg: '#82b1ff', // Blue — H2
28
+ h3Fg: '#80d8ff', // Light blue — H3
29
+ codeFg: '#ffff00', // Yellow — code spans
30
+ boldFg: '#e3f2fd', // Bright — bold text
31
+ quoteFg: '#90a4ae', // Gray — blockquotes
32
+ labelFg: '#e3f2fd',
33
+ borderFg: '#455a64',
34
+ footerBg: '#455a64', // Dark gray — Readme tab footer
35
+ };
36
+
37
+ const FOOTER_TEXT = '[↑↓/jk] Scroll [PgUp/PgDn] Page [/] Search [S/V/M/A/R] Tab [Q] Quit';
38
+
39
+ // ---------------------------------------------------------------------------
40
+ // Markdown renderer (story 13.2)
41
+
42
+ /**
43
+ * Render a single markdown line to blessed tagged string.
44
+ * Handles: H1/H2/H3, bold (**), code spans (`), blockquotes (>), plain text.
45
+ *
46
+ * @param {string} line
47
+ * @returns {string}
48
+ */
49
+ export function renderMarkdownLine(line) {
50
+ // H1
51
+ if (/^# /.test(line)) {
52
+ const text = line.replace(/^# /, '');
53
+ return `{bold}{${COLORS.h1Fg}-fg}${text}{/${COLORS.h1Fg}-fg}{/bold}`;
54
+ }
55
+ // H2
56
+ if (/^## /.test(line)) {
57
+ const text = line.replace(/^## /, '');
58
+ return `{bold}{${COLORS.h2Fg}-fg}${text}{/${COLORS.h2Fg}-fg}{/bold}`;
59
+ }
60
+ // H3
61
+ if (/^### /.test(line)) {
62
+ const text = line.replace(/^### /, '');
63
+ return `{${COLORS.h3Fg}-fg}${text}{/${COLORS.h3Fg}-fg}`;
64
+ }
65
+ // Blockquote
66
+ if (/^> /.test(line)) {
67
+ const text = line.replace(/^> /, '');
68
+ return `{${COLORS.quoteFg}-fg}│ ${text}{/${COLORS.quoteFg}-fg}`;
69
+ }
70
+ // Horizontal rule
71
+ if (/^---+$/.test(line.trim())) {
72
+ return `{${COLORS.quoteFg}-fg}${'─'.repeat(66)}{/${COLORS.quoteFg}-fg}`;
73
+ }
74
+
75
+ // Inline: code spans, bold
76
+ let result = line;
77
+ // Escape existing blessed tags (literal braces in content)
78
+ // Code spans: `text`
79
+ result = result.replace(/`([^`]+)`/g, `{${COLORS.codeFg}-fg}$1{/${COLORS.codeFg}-fg}`);
80
+ // Bold: **text**
81
+ result = result.replace(/\*\*([^*]+)\*\*/g, `{bold}$1{/bold}`);
82
+ // Italic: *text*
83
+ result = result.replace(/\*([^*]+)\*/g, `{${COLORS.h3Fg}-fg}$1{/${COLORS.h3Fg}-fg}`);
84
+
85
+ return result;
86
+ }
87
+
88
+ /**
89
+ * Render full markdown content to blessed tagged multi-line string.
90
+ * @param {string} markdown
91
+ * @returns {string}
92
+ */
93
+ export function renderMarkdown(markdown) {
94
+ return markdown
95
+ .split('\n')
96
+ .map(line => renderMarkdownLine(line))
97
+ .join('\n');
98
+ }
99
+
100
+ // ---------------------------------------------------------------------------
101
+
102
+ function createTestStub() {
103
+ return {
104
+ box: {},
105
+ show: () => {},
106
+ hide: () => {},
107
+ onFocus: () => {},
108
+ onBlur: () => {},
109
+ getFooterText: () => FOOTER_TEXT,
110
+ getFooterColor: () => COLORS.footerBg,
111
+ };
112
+ }
113
+
114
+ // ---------------------------------------------------------------------------
115
+
116
+ /**
117
+ * Create the Readme tab component.
118
+ *
119
+ * @param {object} screen - Blessed screen instance
120
+ * @param {object} services
121
+ * @returns {{ box, show, hide, onFocus, onBlur, getFooterText, getFooterColor }}
122
+ */
123
+ export function createReadmeTab(screen, services) {
124
+ if (IS_TEST) return createTestStub();
125
+
126
+ const { focusMainTabBar } = services;
127
+
128
+ // -------------------------------------------------------------------------
129
+ // Container
130
+
131
+ const box = blessed.box({
132
+ parent: screen,
133
+ top: 4,
134
+ left: 0,
135
+ width: '100%',
136
+ bottom: 2,
137
+ hidden: true,
138
+ style: { fg: COLORS.labelFg, bg: COLORS.contentBg },
139
+ border: { type: 'line' },
140
+ borderStyle: { fg: COLORS.borderFg },
141
+ });
142
+
143
+ // -------------------------------------------------------------------------
144
+ // Load README.md
145
+
146
+ function _loadReadme() {
147
+ const candidates = [
148
+ path.resolve(process.cwd(), 'README.md'),
149
+ path.resolve(process.cwd(), 'readme.md'),
150
+ ];
151
+ for (const p of candidates) {
152
+ if (fs.existsSync(p)) {
153
+ try {
154
+ return fs.readFileSync(p, 'utf8');
155
+ } catch {
156
+ // Unreadable
157
+ }
158
+ }
159
+ }
160
+ return '# README\n\n*(No README.md found in current directory)*';
161
+ }
162
+
163
+ // -------------------------------------------------------------------------
164
+ // Scrollable content
165
+
166
+ const scrollBox = blessed.box({
167
+ parent: box,
168
+ top: 1,
169
+ left: 2,
170
+ width: '96%',
171
+ bottom: 4,
172
+ scrollable: true,
173
+ alwaysScroll: true,
174
+ tags: true,
175
+ keys: true,
176
+ vi: true,
177
+ mouse: true,
178
+ scrollbar: { ch: '│', style: { fg: COLORS.borderFg } },
179
+ content: '',
180
+ style: { fg: COLORS.labelFg, bg: COLORS.contentBg },
181
+ });
182
+
183
+ // Scroll indicator
184
+ const scrollIndicator = blessed.text({
185
+ parent: box,
186
+ bottom: 2,
187
+ right: 2,
188
+ content: '',
189
+ tags: true,
190
+ style: { fg: COLORS.quoteFg, bg: COLORS.contentBg },
191
+ });
192
+
193
+ // -------------------------------------------------------------------------
194
+ // Render
195
+
196
+ function refreshContent() {
197
+ const markdown = _loadReadme();
198
+ const rendered = renderMarkdown(markdown);
199
+ scrollBox.setContent(rendered);
200
+ scrollIndicator.setContent('{#607d8b-fg}↓ Scroll for more content ↓{/#607d8b-fg}');
201
+ screen.render();
202
+ }
203
+
204
+ // Scroll events update indicator
205
+ scrollBox.on('scroll', () => {
206
+ const atBottom = scrollBox.getScrollPerc() >= 99;
207
+ scrollIndicator.setContent(
208
+ atBottom ? '' : '{#607d8b-fg}↓ Scroll for more content ↓{/#607d8b-fg}'
209
+ );
210
+ screen.render();
211
+ });
212
+
213
+ // PgUp/PgDn
214
+ scrollBox.key(['pageup'], () => {
215
+ scrollBox.scroll(-10);
216
+ screen.render();
217
+ });
218
+ scrollBox.key(['pagedown'], () => {
219
+ scrollBox.scroll(10);
220
+ screen.render();
221
+ });
222
+
223
+ // [↑] at top of content → jump to main header tab bar
224
+ scrollBox.key(['up'], () => {
225
+ if (scrollBox.getScroll() === 0 && typeof focusMainTabBar === 'function') {
226
+ focusMainTabBar();
227
+ }
228
+ });
229
+
230
+ // Escape → return to header tab bar
231
+ scrollBox.key(['escape'], () => {
232
+ if (typeof focusMainTabBar === 'function') { focusMainTabBar(); screen.render(); }
233
+ });
234
+
235
+ // -------------------------------------------------------------------------
236
+ // Tab Component Contract
237
+
238
+ return {
239
+ box,
240
+
241
+ show() {
242
+ box.show();
243
+ refreshContent();
244
+ screen.render();
245
+ },
246
+
247
+ hide() {
248
+ box.hide();
249
+ screen.render();
250
+ },
251
+
252
+ onFocus() {
253
+ scrollBox.focus();
254
+ screen.render();
255
+ },
256
+
257
+ onBlur() {},
258
+
259
+ getFooterText() {
260
+ return FOOTER_TEXT;
261
+ },
262
+
263
+ getFooterColor() {
264
+ return COLORS.footerBg;
265
+ },
266
+ };
267
+ }