agentvibes 4.6.3 → 4.6.6
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.
- package/.claude/github-star-reminder.txt +1 -1
- package/.claude/hooks/audio-processor.sh +433 -433
- package/.claude/hooks/play-tts-macos.sh +368 -368
- package/.claude/hooks/play-tts-piper.sh +679 -679
- package/.claude/hooks/play-tts-soprano.sh +356 -356
- package/.clawdbot/skill/SKILL.md +237 -241
- package/CLAUDE.md +41 -0
- package/README.md +2162 -2121
- package/RELEASE_NOTES.md +60 -0
- package/bin/agentvibes.js +15 -0
- package/package.json +1 -1
- package/src/console/app.js +41 -19
- package/src/console/tabs/agents-tab.js +5 -5
- package/src/console/tabs/help-tab.js +1 -1
- package/src/console/tabs/install-tab.js +5 -8
- package/src/console/tabs/music-tab.js +1 -1
- package/src/console/tabs/readme-tab.js +4 -1
- package/src/console/tabs/receiver-tab.js +1 -1
- package/src/console/tabs/settings-tab.js +93 -106
- package/src/console/tabs/voices-tab.js +1 -1
- package/src/installer.js +76 -27
- package/.claude/config/background-music-enabled.txt +0 -1
package/RELEASE_NOTES.md
CHANGED
|
@@ -1,5 +1,65 @@
|
|
|
1
1
|
# AgentVibes Release Notes
|
|
2
2
|
|
|
3
|
+
## 🧭 v4.6.6 — Natural TUI Navigation
|
|
4
|
+
|
|
5
|
+
**Release Date:** April 2026
|
|
6
|
+
|
|
7
|
+
### Improvements
|
|
8
|
+
|
|
9
|
+
The Settings TUI now navigates the way you'd expect. Arrow keys flow naturally top-to-bottom through the interface — main header → sub-tab bar → content → footer — with no surprising jumps or dead ends.
|
|
10
|
+
|
|
11
|
+
- **Down from the main header** lands on the active sub-tab bar item, so you're always oriented before pressing further.
|
|
12
|
+
- **Down through content** moves row-by-row within the current tab, reaching Full Preview and the Save buttons at the bottom. It no longer auto-jumps to the next sub-tab.
|
|
13
|
+
- **Up from the first content row** returns you to the current sub-tab (not always Voice).
|
|
14
|
+
- **Left/Right in the sub-tab bar** is the natural way to switch between Voice, Effects, Personality, Output, and Language tabs.
|
|
15
|
+
- **Left/Right in the footer** moves between Full Preview, Save Globally, Save Locally, and Cancel Changes.
|
|
16
|
+
- **Language tab** now has a proper scrollable list — arrow down to enter it, Up/Down to select a language, Enter to apply, Down past the last item to reach the footer.
|
|
17
|
+
- **Readme tab** falls back to the AgentVibes package README when opened in a project folder that has no README of its own.
|
|
18
|
+
- **Escape from the installer** now navigates cleanly to Settings instead of getting stuck.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 🔧 v4.6.5 — Patch Release
|
|
23
|
+
|
|
24
|
+
**Release Date:** April 2026
|
|
25
|
+
|
|
26
|
+
### Improvements
|
|
27
|
+
|
|
28
|
+
- **TUI non-interactive hint** — Installer header now shows a two-tone hint on row 2: `Skip this TUI?` (white) + `npx agentvibes install --non-interactive` (yellow), with a sponsor link on the right. Useful for CI/CD pipelines and scripted installs.
|
|
29
|
+
|
|
30
|
+
- **`--non-interactive` routing fix** — `npx agentvibes install --non-interactive` (and `--yes`/`-y`) now correctly bypasses the TUI and routes directly to the CLI installer. Previously the TUI would still launch.
|
|
31
|
+
|
|
32
|
+
- **Sponsor link in TUI header** — Row 2 of the header now shows a `♡ Sponsor this Developer github.com/sponsors/paulpreibisch` link on the right side, alongside the non-interactive hint on the left.
|
|
33
|
+
|
|
34
|
+
- **Consistent line endings via `.gitattributes`** — Added `.gitattributes` to enforce `LF` for shell scripts, JS, JSON, and markdown, and `CRLF` for PowerShell scripts. Prevents spurious `bin/` file modifications showing as dirty on Windows due to CRLF noise.
|
|
35
|
+
|
|
36
|
+
- **`bin/` execute bits restored** — Re-indexed `bin/agent-vibes`, `bin/agentvibes-voice-browser.js`, `bin/mcp-server.js`, and `bin/test-bmad-pr` to ensure consistent line endings; verified all four retain `chmod +x` (`100755` mode).
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
### User Impact
|
|
40
|
+
|
|
41
|
+
- No functional changes — infrastructure and tooling improvements only
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## 🐛 v4.6.4 — Patch Release
|
|
46
|
+
|
|
47
|
+
**Release Date:** April 2026
|
|
48
|
+
|
|
49
|
+
### Bug Fixes
|
|
50
|
+
|
|
51
|
+
- **CI green on macOS** — `mktemp` with a file extension suffix (e.g. `tts-XXXXXX.wav`) works on Linux (GNU mktemp) but silently fails on macOS (BSD mktemp), which requires `XXXXXX` to be at the very end of the template. Fixed all 12 occurrences across `play-tts-piper.sh`, `play-tts-soprano.sh`, `play-tts-macos.sh`, and `audio-processor.sh` by creating the temp file without extension then renaming to add `.wav`/`.aiff`.
|
|
52
|
+
|
|
53
|
+
- **macOS path symlink in test 213** — macOS transparently resolves `/var/folders/...` to `/private/var/folders/...` via a symlink. The voice-manager replay test was comparing against the unresolved path and failing. Fixed by using `cd && pwd` to get the real path before asserting.
|
|
54
|
+
|
|
55
|
+
- **`bmad-party-speak.sh` execute permission** — The bash hook lost its `+x` bit, causing `party mode scripts ship with the package` CI test to fail. Restored `100755` mode via `git update-index`.
|
|
56
|
+
|
|
57
|
+
### User Impact
|
|
58
|
+
|
|
59
|
+
- No user-facing changes — CI infrastructure fixes only
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
3
63
|
## 🐛 v4.6.3 — Patch Release
|
|
4
64
|
|
|
5
65
|
**Release Date:** April 2026
|
package/bin/agentvibes.js
CHANGED
|
@@ -67,6 +67,11 @@ export function resolveStartTab(args, configService) {
|
|
|
67
67
|
const cmd = args[0];
|
|
68
68
|
|
|
69
69
|
if (cmd === 'install') {
|
|
70
|
+
// Non-interactive flags → delegate to CLI installer (src/installer.js), not TUI
|
|
71
|
+
const isNonInteractive = args.includes('--non-interactive') || args.includes('--yes') || args.includes('-y');
|
|
72
|
+
if (isNonInteractive) {
|
|
73
|
+
return { cliInstall: true, args: args.slice(1) };
|
|
74
|
+
}
|
|
70
75
|
return { startTab: 'install' };
|
|
71
76
|
}
|
|
72
77
|
|
|
@@ -139,6 +144,16 @@ if (_argv1 === _thisFile) {
|
|
|
139
144
|
process.exit(1);
|
|
140
145
|
}
|
|
141
146
|
|
|
147
|
+
if (result.cliInstall) {
|
|
148
|
+
// Route to CLI installer for non-interactive installs
|
|
149
|
+
const installerPath = path.resolve(__dirname, '..', 'src', 'installer.js');
|
|
150
|
+
execFileSync(process.execPath, [installerPath, 'install', ...result.args], {
|
|
151
|
+
stdio: 'inherit',
|
|
152
|
+
shell: false,
|
|
153
|
+
});
|
|
154
|
+
process.exit(0);
|
|
155
|
+
}
|
|
156
|
+
|
|
142
157
|
launchConsole({ startTab: result.startTab }).catch(err => {
|
|
143
158
|
process.stderr.write(`Failed to launch AgentVibes console: ${err.message}\n`);
|
|
144
159
|
process.exit(1);
|
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": "4.6.
|
|
4
|
+
"version": "4.6.6",
|
|
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": [
|
package/src/console/app.js
CHANGED
|
@@ -151,7 +151,7 @@ export class AgentVibesConsole {
|
|
|
151
151
|
top: 0,
|
|
152
152
|
left: 0,
|
|
153
153
|
width: '100%',
|
|
154
|
-
height:
|
|
154
|
+
height: 4,
|
|
155
155
|
tags: false,
|
|
156
156
|
wrap: false,
|
|
157
157
|
scrollable: false,
|
|
@@ -192,6 +192,28 @@ export class AgentVibesConsole {
|
|
|
192
192
|
style: { bg: COLORS.headerBg },
|
|
193
193
|
});
|
|
194
194
|
|
|
195
|
+
// Row 2: non-interactive mode hint — direct screen child (like tab items) so tags render correctly
|
|
196
|
+
blessed.text({
|
|
197
|
+
parent: this.screen,
|
|
198
|
+
top: 2,
|
|
199
|
+
left: 2,
|
|
200
|
+
shrink: true,
|
|
201
|
+
tags: true,
|
|
202
|
+
content: `{white-fg}Skip this TUI?{/white-fg} {yellow-fg}npx agentvibes install --non-interactive{/yellow-fg}`,
|
|
203
|
+
style: { bg: COLORS.headerBg },
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
// Row 2 (right): sponsor message
|
|
207
|
+
blessed.text({
|
|
208
|
+
parent: this.screen,
|
|
209
|
+
top: 2,
|
|
210
|
+
right: 2,
|
|
211
|
+
shrink: true,
|
|
212
|
+
tags: true,
|
|
213
|
+
content: `{magenta-fg}\u2661{/magenta-fg} {white-fg}Sponsor this Developer{/white-fg} {magenta-fg}github.com/sponsors/paulpreibisch{/magenta-fg}`,
|
|
214
|
+
style: { bg: COLORS.headerBg },
|
|
215
|
+
});
|
|
216
|
+
|
|
195
217
|
// Row 1 (right): Active settings summary [provider][voice][effects][music]
|
|
196
218
|
this._headerStatusText = blessed.text({
|
|
197
219
|
parent: this.headerBox,
|
|
@@ -281,17 +303,17 @@ export class AgentVibesConsole {
|
|
|
281
303
|
// Background strip — screen child so blessed uses absolute coordinates directly.
|
|
282
304
|
// Tab items are ALSO screen children (not children of tabBarBox) to avoid the
|
|
283
305
|
// WSL/Windows Terminal parent-relative positioning bug that renders them 1 row
|
|
284
|
-
// too high (at row
|
|
306
|
+
// too high (at row 3 instead of row 4), producing a ghost duplicate tab bar.
|
|
285
307
|
this.tabBarBox = blessed.box({
|
|
286
308
|
parent: this.screen,
|
|
287
|
-
top:
|
|
309
|
+
top: 4,
|
|
288
310
|
left: 0,
|
|
289
311
|
width: '100%',
|
|
290
312
|
height: 1,
|
|
291
313
|
style: { bg: COLORS.tabBarBg },
|
|
292
314
|
});
|
|
293
315
|
|
|
294
|
-
// One box per tab — direct screen children at absolute top:
|
|
316
|
+
// One box per tab — direct screen children at absolute top:4. No tag parsing, no wrapping.
|
|
295
317
|
this._tabItems = {};
|
|
296
318
|
this._tabItemXOffsets = {}; // track x positions for label refresh
|
|
297
319
|
let xOffset = 1;
|
|
@@ -302,7 +324,7 @@ export class AgentVibesConsole {
|
|
|
302
324
|
const text = ` [${shortcutKey}] ${label} `;
|
|
303
325
|
const el = blessed.box({
|
|
304
326
|
parent: this.screen,
|
|
305
|
-
top:
|
|
327
|
+
top: 4,
|
|
306
328
|
left: xOffset,
|
|
307
329
|
width: text.length,
|
|
308
330
|
height: 1,
|
|
@@ -318,14 +340,14 @@ export class AgentVibesConsole {
|
|
|
318
340
|
xOffset += text.length + 1; // 1-space gap between tabs
|
|
319
341
|
}
|
|
320
342
|
|
|
321
|
-
// Right-aligned Quit item — direct screen child at absolute top:
|
|
343
|
+
// Right-aligned Quit item — direct screen child at absolute top:4
|
|
322
344
|
const _quitText = ' [Q] Quit ';
|
|
323
345
|
const _quitBase = _quitText;
|
|
324
346
|
const _quitBlock = _quitText.slice(0, -1) + '█';
|
|
325
347
|
let _quitInterval = null;
|
|
326
348
|
this._quitItem = blessed.box({
|
|
327
349
|
parent: this.screen,
|
|
328
|
-
top:
|
|
350
|
+
top: 4,
|
|
329
351
|
right: 1,
|
|
330
352
|
width: _quitText.length,
|
|
331
353
|
height: 1,
|
|
@@ -532,12 +554,12 @@ export class AgentVibesConsole {
|
|
|
532
554
|
}
|
|
533
555
|
|
|
534
556
|
// ---------------------------------------------------------------------------
|
|
535
|
-
// Private: Content area (rows
|
|
557
|
+
// Private: Content area (rows 5..N-1) — tab components mount here
|
|
536
558
|
|
|
537
559
|
_createContentArea() {
|
|
538
560
|
// bottom: 2 reserves 2 rows at the bottom: context footer (story 6.3) + GitHub footer
|
|
539
561
|
this.contentArea = blessed.box({
|
|
540
|
-
top:
|
|
562
|
+
top: 5,
|
|
541
563
|
left: 0,
|
|
542
564
|
width: '100%',
|
|
543
565
|
bottom: 2,
|
|
@@ -747,18 +769,18 @@ export class AgentVibesConsole {
|
|
|
747
769
|
this.screen.render = () => {};
|
|
748
770
|
|
|
749
771
|
try {
|
|
750
|
-
// Nuclear clear: wipe the content area (row
|
|
751
|
-
// from the previous tab. Start at row
|
|
772
|
+
// Nuclear clear: wipe the content area (row 5+) to remove stale cell content
|
|
773
|
+
// from the previous tab. Start at row 5 — header (0-3) and tab bar (4) are
|
|
752
774
|
// static widgets that don't need clearing; wiping them causes the double
|
|
753
|
-
// tab bar artifact (row
|
|
775
|
+
// tab bar artifact (row 3 of header shows tab bar ghost from prior render).
|
|
754
776
|
// blessed's render loop never resets the `lines` buffer before rendering
|
|
755
777
|
// (see: blessed/lib/widgets/screen.js line 733, commented-out clear).
|
|
756
|
-
this.screen.clearRegion(0, this.screen.cols,
|
|
778
|
+
this.screen.clearRegion(0, this.screen.cols, 5, this.screen.rows - 2);
|
|
757
779
|
|
|
758
780
|
// Force-invalidate olines for the entire visible area (rows 0..rows-3).
|
|
759
|
-
// Includes header rows 0-
|
|
781
|
+
// Includes header rows 0-3 so the branded header is always redrawn on
|
|
760
782
|
// tab switches — prevents corruption from persisting across tabs.
|
|
761
|
-
// Row
|
|
783
|
+
// Row 3 (header bottom), row 4 (tab bar) and content rows accumulate
|
|
762
784
|
// ghost rendering artifacts — draw() skips them when lines==olines even
|
|
763
785
|
// though the terminal still shows stale chars from earlier renders.
|
|
764
786
|
// Setting attr=-1 is impossible for any real cell, so draw() is forced
|
|
@@ -772,13 +794,13 @@ export class AgentVibesConsole {
|
|
|
772
794
|
orow.dirty = true;
|
|
773
795
|
}
|
|
774
796
|
|
|
775
|
-
// Row
|
|
797
|
+
// Row 3 (header bottom) is never dirty after draw 1 — its content (headerBg+
|
|
776
798
|
// spaces) never changes so element.render() never marks it dirty. The olines
|
|
777
|
-
// invalidation above sets olines[
|
|
799
|
+
// invalidation above sets olines[3][c][0]=-1, but draw() only compares cells
|
|
778
800
|
// when lines[r].dirty is true; a false dirty flag skips the entire row without
|
|
779
801
|
// ever consulting olines. Force-mark it dirty so draw() emits the explicit
|
|
780
|
-
// cup(
|
|
781
|
-
if (this.screen.lines?.[
|
|
802
|
+
// cup(4,1)+headerBg+spaces sequence and overwrites any ghost terminal content.
|
|
803
|
+
if (this.screen.lines?.[3]) this.screen.lines[3].dirty = true;
|
|
782
804
|
|
|
783
805
|
// Update tab bar, footer, and header status inside suppression — no intermediate render.
|
|
784
806
|
this._updateTabBar(tabId);
|
|
@@ -124,7 +124,7 @@ const COLORS = {
|
|
|
124
124
|
sectionHdr: '#7b1fa2',
|
|
125
125
|
labelFg: '#e3f2fd',
|
|
126
126
|
valueFg: '#ffff00',
|
|
127
|
-
|
|
127
|
+
|
|
128
128
|
btnDefault: '#6a1b9a',
|
|
129
129
|
btnFocus: '#2e7d32', // Green — focused/selected
|
|
130
130
|
btnFocusFg: '#ffffff',
|
|
@@ -227,7 +227,7 @@ ${_tl('bmadDesc')}
|
|
|
227
227
|
|
|
228
228
|
const box = blessed.box({
|
|
229
229
|
parent: screen,
|
|
230
|
-
top:
|
|
230
|
+
top: 5,
|
|
231
231
|
left: 0,
|
|
232
232
|
width: '100%',
|
|
233
233
|
bottom: 2,
|
|
@@ -304,7 +304,7 @@ ${_tl('bmadDesc')}
|
|
|
304
304
|
fg: COLORS.labelFg,
|
|
305
305
|
bg: COLORS.contentBg,
|
|
306
306
|
border: { fg: COLORS.borderFg },
|
|
307
|
-
selected: { bg: '
|
|
307
|
+
selected: { bg: 'blue', fg: 'yellow' },
|
|
308
308
|
item: { fg: COLORS.labelFg },
|
|
309
309
|
},
|
|
310
310
|
});
|
|
@@ -681,7 +681,7 @@ ${_tl('bmadDesc')}
|
|
|
681
681
|
fg: COLORS.labelFg,
|
|
682
682
|
bg: COLORS.contentBg,
|
|
683
683
|
border: { fg: '#4a148c' },
|
|
684
|
-
selected: { bg: '
|
|
684
|
+
selected: { bg: 'blue', fg: 'yellow' },
|
|
685
685
|
item: { fg: COLORS.labelFg },
|
|
686
686
|
},
|
|
687
687
|
});
|
|
@@ -1529,7 +1529,7 @@ ${_tl('bmadDesc')}
|
|
|
1529
1529
|
fg: COLORS.labelFg,
|
|
1530
1530
|
bg: COLORS.contentBg,
|
|
1531
1531
|
border: { fg: COLORS.btnFocus },
|
|
1532
|
-
selected: { bg: '
|
|
1532
|
+
selected: { bg: 'blue', fg: 'yellow' },
|
|
1533
1533
|
item: { fg: COLORS.labelFg },
|
|
1534
1534
|
},
|
|
1535
1535
|
});
|
|
@@ -166,7 +166,7 @@ export function createInstallTab(screen, services) {
|
|
|
166
166
|
|
|
167
167
|
const box = blessed.box({
|
|
168
168
|
parent: screen,
|
|
169
|
-
top:
|
|
169
|
+
top: 5,
|
|
170
170
|
left: 0,
|
|
171
171
|
width: '100%',
|
|
172
172
|
bottom: 2,
|
|
@@ -942,13 +942,10 @@ export function createInstallTab(screen, services) {
|
|
|
942
942
|
_screen--;
|
|
943
943
|
_showCurrentScreen();
|
|
944
944
|
} else {
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
//
|
|
948
|
-
|
|
949
|
-
// item mid-event, causing its own key(['escape']) handler to fire in the same
|
|
950
|
-
// emission and call onFocus() → re-focus a button inside the now-hidden box.
|
|
951
|
-
if (typeof focusMainTabBar === 'function') setTimeout(() => focusMainTabBar(), 0);
|
|
945
|
+
// User pressed Escape at the first screen — they want out of the installer.
|
|
946
|
+
// Switch to Settings so they can configure without being stuck on the install tab.
|
|
947
|
+
// (focusMainTabBar would re-focus the install tab item, which loops back here.)
|
|
948
|
+
setTimeout(() => navigationService?.switchTab('settings'), 0);
|
|
952
949
|
}
|
|
953
950
|
});
|
|
954
951
|
|
|
@@ -132,7 +132,7 @@ export function createReadmeTab(screen, services) {
|
|
|
132
132
|
|
|
133
133
|
const box = blessed.box({
|
|
134
134
|
parent: screen,
|
|
135
|
-
top:
|
|
135
|
+
top: 5,
|
|
136
136
|
left: 0,
|
|
137
137
|
width: '100%',
|
|
138
138
|
bottom: 2,
|
|
@@ -146,9 +146,12 @@ export function createReadmeTab(screen, services) {
|
|
|
146
146
|
// Load README.md
|
|
147
147
|
|
|
148
148
|
function _loadReadme() {
|
|
149
|
+
// Package root — works whether installed globally (node_modules/.bin) or run from source
|
|
150
|
+
const pkgRoot = path.resolve(new URL(import.meta.url).pathname, '..', '..', '..', '..');
|
|
149
151
|
const candidates = [
|
|
150
152
|
path.resolve(process.cwd(), 'README.md'),
|
|
151
153
|
path.resolve(process.cwd(), 'readme.md'),
|
|
154
|
+
path.resolve(pkgRoot, 'README.md'), // AgentVibes package README fallback
|
|
152
155
|
];
|
|
153
156
|
for (const p of candidates) {
|
|
154
157
|
if (fs.existsSync(p)) {
|