vibeaudio 0.24.0 → 0.25.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.
- package/README.md +12 -10
- package/package.json +1 -1
- package/src/cli.js +11 -5
- package/src/hooks.js +15 -0
package/README.md
CHANGED
|
@@ -423,7 +423,7 @@ Installing the Claude Code hooks also adds a `/vibe` command (`~/.claude/command
|
|
|
423
423
|
/vibe volume 20 change volume, keeping your genre
|
|
424
424
|
```
|
|
425
425
|
|
|
426
|
-
It asks Claude to run the matching `vibe` command, so Claude Code will ask permission for that command the first time. If you already have your own `vibe.md` there, VibeAudio leaves it alone and says so; `--uninstall-hooks` removes only its own.
|
|
426
|
+
The optional [`/vibeaudio` mod](#vibeaudio-instant-controls-and-a-pane-claude-code-mod) does the same instantly with no turn; `/vibe` is the version that works everywhere. It asks Claude to run the matching `vibe` command, so Claude Code will ask permission for that command the first time. If you already have your own `vibe.md` there, VibeAudio leaves it alone and says so; `--uninstall-hooks` removes only its own.
|
|
427
427
|
|
|
428
428
|
### `/vibeaudio`: instant controls and a pane (Claude Code mod)
|
|
429
429
|
|
|
@@ -436,26 +436,28 @@ claude plugin install vibeaudio-mod@vibeaudio
|
|
|
436
436
|
|
|
437
437
|
Then `/reload-plugins` or a new session; `/plugin` shows `1 mod active`.
|
|
438
438
|
|
|
439
|
+
To update later, run `claude plugin marketplace update vibeaudio` and then `claude plugin update vibeaudio-mod@vibeaudio`, followed by `/reload-plugins`. The mod does not update when the `vibe` command does.
|
|
440
|
+
|
|
439
441
|
```text
|
|
440
|
-
/vibeaudio open the pane: mute, music, genre, volume, speech, banners, test signal
|
|
442
|
+
/vibeaudio open the pane: mute, stop, music, genre, preview, volume, speech, banners, announcements, test signal
|
|
441
443
|
/vibeaudio mute 30 silence for 30 minutes (unmute ends it)
|
|
442
|
-
/vibeaudio genre jazz also: volume <n>, music on|off, speak off|auto|always, notify on|off, stop
|
|
444
|
+
/vibeaudio genre jazz also: volume <n>, music on|off, speak off|auto|always, notify on|off, announce on|off, preview, stop
|
|
443
445
|
/vibeaudio genre zen here genre, volume and music also take "here": save for this project only
|
|
444
446
|
/vibeaudio card make your week card; the pane shows it in terminals that draw images
|
|
445
|
-
/vibeaudio
|
|
446
|
-
/vibeaudio usage on add context fill and plan limits (ctx 42% 5h 31%) to the band (off by default; usage off removes it)
|
|
447
|
+
/vibeaudio band on an always-visible logo band above the prompt (off by default; band off removes it)
|
|
448
|
+
/vibeaudio usage on add context fill and plan limits (ctx ██░░░ 42% 5h █░░░░ 31%, green, amber from 60%, red from 80%) to the band (off by default; usage off removes it)
|
|
447
449
|
/vibeaudio doctor the setup check in a pane, each problem with its fix (vibe --doctor)
|
|
448
450
|
/vibeaudio help every command on one line, and the "here" option
|
|
449
451
|
```
|
|
450
452
|
|
|
451
|
-
The pane is four cards under a logo header with a status pill (Playing, Ready, Muted or Music off): Now playing, Sound, Alerts and Share, which holds your last 7 days as a small chart and the week card buttons. Its colours come from the site and adapt to your Claude Code theme, light or dark. While you are muted, a line above the prompt says how many minutes are left, so a forgotten mute does not look like a broken tool. Nothing else is shown unless you turn the strip on.
|
|
453
|
+
The pane is four cards under a logo header with a status pill (Playing, Ready, Muted or Music off): Now playing (mute for 15 minutes or an hour, stop the music, send a test signal), Sound (genre, volume, **Preview** plays one loop of the chosen genre, and where to save), Alerts (speech, banners, `vibe --announce`) and Share, which holds your last 7 days as a small chart and the week card buttons. Its colours come from the site and adapt to your Claude Code theme, light or dark. While you are muted, a line above the prompt says how many minutes are left, so a forgotten mute does not look like a broken tool. Nothing else is shown unless you turn the strip on.
|
|
452
454
|
|
|
453
|
-
The optional **
|
|
455
|
+
The optional **band** (`/vibeaudio band on`, remembered across sessions) puts the VibeAudio logo above the prompt, three level bars that move while music is playing (an SVG on the Desktop app, text bars in the terminal). Next to it: the genre and volume, your last 7 days as the week card counts them (turns and time waited, read from `~/.vibeaudio/history.jsonl`), and what your other agents are doing (`api waiting, web working`, in yellow when one needs you). The buttons are icons to save room: 🔇/🔊 mute and unmute, 🎵 music on or off, 🎼 the next genre, − and + for volume, 📊 the week card (then 🖼 to open it) and ⚙ for the controls pane. In a short window it shrinks to one line. It runs `vibe --state` every 5 seconds and redraws the text bars twice a second only in the terminal, while it is on and music is playing; on the Desktop app the SVG animates itself, so only the level bars inside the headphones move. Tab to it with Ctrl+X then Tab. With `/vibeaudio usage on` it also shows how full the context window is and, on a Claude plan, your 5-hour and 7-day limits, turning the warning colour at 80%; it reads the same figures Claude Code's status line has, and nothing else. While Claude works, the spinner also says what is playing (`· ♪ jazz…`, or `· ♪ muted`).
|
|
454
456
|
|
|
455
457
|
- **Per project.** The pane's **Saving** button switches genre, volume and music between everywhere and this project, and the pane notes when this folder has its own settings (`vibe --genre zen --here`, found from a subfolder the way the CLI does). There is no way to remove a project's settings yet, in the mod or the CLI.
|
|
456
|
-
- **It changes nothing itself.** Every action runs the `vibe` command with a fixed argument list (no shell), so settings stay in `~/.vibeaudio/config.json` and the pane cannot disagree with the CLI. The one thing it keeps for itself is whether the
|
|
458
|
+
- **It changes nothing itself.** Every action runs the `vibe` command with a fixed argument list (no shell), so settings stay in `~/.vibeaudio/config.json` and the pane cannot disagree with the CLI. The one thing it keeps for itself is whether the band is on, in Claude Code's own store for the mod. It needs `vibe` on your `PATH` (`npm i -g vibeaudio`) and **Claude Code 2.1.287 or later** (Desktop app 2.1.286). It draws in the terminal and the Desktop app; in the VS Code panel and `claude -p` the same commands answer in text. It makes no network request.
|
|
457
459
|
- **A mod is code, not configuration.** It runs inside Claude Code with your permissions and is not sandboxed, which is why `--install-hooks` never installs it for you; it prints the two commands until Claude Code lists the mod as installed. Read it first: it is [`mods/vibe/hooks/register.js`](mods/vibe/hooks/register.js), and `claude plugin validate mods/vibe` lists every call it makes (it reads three files in `~/.vibeaudio/` (`config.json`, `muted`, `history.jsonl`), your Claude Code theme, the session's usage figures (only with `usage on`), runs `vibe`, and draws).
|
|
458
|
-
- **`/vibe` stays.** It works on every Claude Code version and surface
|
|
460
|
+
- **`/vibe` stays, as the fallback.** It is a prompt, so it costs a turn, but it works on every Claude Code version and surface, including where the mod does not load (older than 2.1.287, or a surface that skips mods). Use `/vibeaudio` where the mod loads and `/vibe` everywhere else; both change the same settings in `~/.vibeaudio/config.json`. The `vibe` and `vibeaudio` commands in your shell are the same program. Remove the mod with `claude plugin uninstall vibeaudio-mod@vibeaudio`.
|
|
459
461
|
|
|
460
462
|
### Changing the sound later
|
|
461
463
|
|
|
@@ -484,7 +486,7 @@ vibe --reactive --install-hooks # on
|
|
|
484
486
|
vibe --install-hooks # off again
|
|
485
487
|
```
|
|
486
488
|
|
|
487
|
-
|
|
489
|
+
A new **genre** (saved everywhere, not with `--here`) replaces the music playing right now while a turn is running, and so does `--music off` or `on`. A new **volume** eases in within a second. `vibe --stop` ends the music and the running turns.
|
|
488
490
|
|
|
489
491
|
Removing them is one command:
|
|
490
492
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibeaudio",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.0",
|
|
4
4
|
"description": "Procedural focus music while your AI coding tools (Claude Code, Codex, Cursor, Grok, Gemini, Copilot) think — a different arrangement per project.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"vibeaudio": "bin/vibeaudio.js",
|
package/src/cli.js
CHANGED
|
@@ -1359,7 +1359,7 @@ function detectAiTools(hooked = new Set()) {
|
|
|
1359
1359
|
* natural way to phrase the request did something else entirely, and the
|
|
1360
1360
|
* README had to warn about it. It saves the default instead.
|
|
1361
1361
|
*/
|
|
1362
|
-
function saveDefaults(typed, hereOnly = false) {
|
|
1362
|
+
function saveDefaults(typed, hereOnly = false, live = null) {
|
|
1363
1363
|
const patch = {};
|
|
1364
1364
|
if (typed.genre !== undefined) patch.genre = typed.genre;
|
|
1365
1365
|
if (typed.volume !== undefined) patch.volume = Math.round(typed.volume * 100);
|
|
@@ -1386,11 +1386,17 @@ function saveDefaults(typed, hereOnly = false) {
|
|
|
1386
1386
|
|
|
1387
1387
|
// Music already in the air is the one thing this does not reach, and
|
|
1388
1388
|
// silence about it reads as the setting having done nothing at all.
|
|
1389
|
-
const
|
|
1390
|
-
|
|
1389
|
+
const hooks = require("./hooks");
|
|
1390
|
+
const playing = hooks.daemonPlaying();
|
|
1391
|
+
// A project's own settings do not say what the music in the air should be, so --here leaves it be.
|
|
1392
|
+
const retuned = live && !hereOnly && (patch.genre !== undefined || patch.music !== undefined)
|
|
1393
|
+
&& hooks.applyLiveMusic(live.genre, live.volume, { music: live.music, follow: live.follow });
|
|
1394
|
+
if (retuned) {
|
|
1395
|
+
console.log(` \x1b[90mThe music playing now changed with it.\x1b[0m`);
|
|
1396
|
+
} else if (playing && patch.genre && playing.genre && playing.genre !== patch.genre) {
|
|
1391
1397
|
console.log(` \x1b[90m${playing.genre} is still playing — vibe --stop cuts it short.\x1b[0m`);
|
|
1392
1398
|
}
|
|
1393
|
-
if (playing && patch.music === false) {
|
|
1399
|
+
if (!retuned && playing && patch.music === false) {
|
|
1394
1400
|
console.log(` \x1b[90m${playing.genre || "The music"} is still playing — vibe --stop cuts it short.\x1b[0m`);
|
|
1395
1401
|
}
|
|
1396
1402
|
if (patch.music === false) {
|
|
@@ -2031,7 +2037,7 @@ async function run() {
|
|
|
2031
2037
|
|
|
2032
2038
|
// Settings typed with no command to run: save them, don't open the launcher.
|
|
2033
2039
|
if (cmdArgs.length === 0 && Object.keys(typed).length > 0) {
|
|
2034
|
-
return saveDefaults(typed, hereOnly);
|
|
2040
|
+
return saveDefaults(typed, hereOnly, { genre, volume, music, follow: typed.volume === undefined });
|
|
2035
2041
|
}
|
|
2036
2042
|
|
|
2037
2043
|
if (hereOnly) {
|
package/src/hooks.js
CHANGED
|
@@ -1400,6 +1400,20 @@ function resumeAfterUnmute(genre, volume, { music = true, follow = false } = {})
|
|
|
1400
1400
|
return true;
|
|
1401
1401
|
}
|
|
1402
1402
|
|
|
1403
|
+
/**
|
|
1404
|
+
* A saved genre or music switch reaches music already playing now, not at the
|
|
1405
|
+
* next prompt: whoever pressed the button is listening. The player is replaced
|
|
1406
|
+
* (or just stopped for music off) while the sessions stay, so chimes, events and
|
|
1407
|
+
* --report carry on. Returns whether anything changed.
|
|
1408
|
+
*/
|
|
1409
|
+
function applyLiveMusic(genre, volume, { music = true, follow = false } = {}) {
|
|
1410
|
+
const was = daemonRunning();
|
|
1411
|
+
if (was) stopDaemon({ keepSessions: true });
|
|
1412
|
+
const start = music && !playbackDisabled() && working(listSessions()).length > 0;
|
|
1413
|
+
if (start) spawnDaemon(genre, volume, false, follow);
|
|
1414
|
+
return was || start;
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1403
1417
|
/**
|
|
1404
1418
|
* The agent's session is over (quit, /clear, logout). A turn cut off by it
|
|
1405
1419
|
* never reaches Stop. Silent: nothing finished.
|
|
@@ -1762,6 +1776,7 @@ module.exports = {
|
|
|
1762
1776
|
hookWait,
|
|
1763
1777
|
hookResume,
|
|
1764
1778
|
resumeAfterUnmute,
|
|
1779
|
+
applyLiveMusic,
|
|
1765
1780
|
isStuck,
|
|
1766
1781
|
STUCK_WINDOW,
|
|
1767
1782
|
agentState,
|