vibeaudio 0.24.0 → 0.25.1

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 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 strip on an always-visible logo band above the prompt (off by default; strip off removes it)
447
+ /vibeaudio band on an always-visible logo band above the prompt (off by default; band off removes it)
446
448
  /vibeaudio usage on add context fill and plan limits (ctx 42% 5h 31%) 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 band on.
452
454
 
453
- The optional **strip** (`/vibeaudio strip 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 **Mute**/**Unmute**, **Music**, **Genre >** (the next genre), **Vol -**, **Vol +**, **Week card** (makes the share card, then **Open card**) and **Controls**. 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`).
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`). The bars also move while another agent on the machine is working. The buttons are compact icons that show the current state: 🔊/🔇 sound on or muted (press to flip it), ♪ on/off for music, ♫ with the current genre (press for the next one), − and + for volume, ▤ week for 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 strip 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.
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; the mod is the faster path where it loads. Remove the mod with `claude plugin uninstall vibeaudio-mod@vibeaudio`.
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
- Music already playing keeps the old genre until the next prompt swaps the daemon — `vibe --stop` cuts it short. A new **volume** is the exception: the music playing now eases to it within a second.
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.24.0",
3
+ "version": "0.25.1",
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 playing = require("./hooks").daemonPlaying();
1390
- if (playing && patch.genre && playing.genre && playing.genre !== patch.genre) {
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,