vibeaudio 0.25.2 → 0.26.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 CHANGED
@@ -300,7 +300,7 @@ Where an agent reports more than start and stop, VibeAudio listens for that too
300
300
  | :--- | :--- |
301
301
  | **Five agents tell you when they're waiting on you** | When a permission dialog opens the music stops rather than sounding busy while the agent is stuck on you, and it resumes once the thing you answered has run. Claude Code covers the terminal, desktop app and IDEs alike, plus MCP servers asking for input. Copilot CLI's own `PermissionRequest` fires before *every* permission check — dialog or not — so VibeAudio listens for its permission-prompt notification instead. Cursor and Grok have no such event that's been verified, so they keep playing through a prompt. |
302
302
  | **Claude Code turns that never reach `Stop` still end the music** | An API error or rate limit ends the turn with `StopFailure` instead, which plays the failure chime. Interrupting (Esc, or the stop button in the desktop app) fires no hook at all, so the background player watches the session transcript for Claude Code's interrupt entry and stops silently within half a second — whether the agent was writing or running a tool. A prompt that another hook blocks (a token-saving proxy, say) never reaches `Stop` either, so the same watcher ends the music on Claude Code's "prompt blocked" entry — or never starts it, when the blocker was quicker than we were. Closing the session mid-turn stops it too — but only if that session started the music, so closing an idle terminal never silences another one. |
303
- | **Codex asks you to trust the hook once** | Codex keeps a per-hook trust hash in `~/.codex/config.toml` and won't run a hook it hasn't been told to trust, so the install isn't live until you approve each one the first time it fires. |
303
+ | **Codex asks you to trust the hook once** | Codex keeps a per-hook trust hash in `~/.codex/config.toml` and won't run a hook it hasn't been told to trust, so the install isn't live until you approve each one. The CLI asks the first time each fires; the Codex desktop app shows **Review hooks** in the composer, where **Allow all** approves them in one go. Both write the same records, so approving in one covers the other. |
304
304
  | **Cursor and Antigravity say how a turn ended** | Cursor's stop event reports whether the turn completed, aborted or errored, and Antigravity's gives a termination reason, so an error plays the failure chime. Claude Code and Qwen Code send a separate `StopFailure` for an API error. The others send no verdict, so a turn there always ends on the success chime — VibeAudio won't invent a failure the agent never claimed. |
305
305
  | <a id="antigravity-hooks"></a>**Antigravity never gets a pre-tool hook** | Its pre-tool hook has to approve or deny every tool call — one that answers nothing blocks the tool — so VibeAudio installs none, and `--reactive` does nothing there. It has no prompt event either: the start event fires before every model call, and VibeAudio starts the music on the first one of each prompt only. Its hooks live in `~/.gemini/config/hooks.json` under a name of their own, so your other named hooks there are never touched. Verified with the `agy` CLI; the desktop app reads the same file by Antigravity's own docs but hasn't been checked live. |
306
306
  | **Upgraded, and a new feature isn't there?** | Hooks are written into your agent's config once, at install time, and an upgrade doesn't touch them. When a new version listens for more events (0.13.1 added Codex's `Interrupt` and `SessionEnd`), `vibe --doctor` and `vibe --status` name what's missing, and `vibe --install-hooks` adds it. |
@@ -334,6 +334,8 @@ Sessions with no id in their payload share a single slot, so they behave as one.
334
334
 
335
335
  > **The Claude Code desktop app is covered too**, not just the terminal — both read the same `~/.claude/settings.json` (or `$CLAUDE_CONFIG_DIR/settings.json`). (The separate **Claude Desktop** chat app is a different product with no hooks; that one needs [MCP](#-everything-else-claude-desktop-vs-code-via-mcp).)
336
336
 
337
+ > **So is the Codex desktop app** (the Codex side of the ChatGPT app): it runs the same Codex engine on the same `~/.codex/hooks.json`, so `--install-hooks` covers it with nothing extra. Approve the hooks once from its **Review hooks** prompt. Its stop button ends the music silently, as Codex's `Interrupt` does in the CLI.
338
+
337
339
  > **One player is shared.** Prompt two agents at once and the last prompt owns the music. One person, one set of speakers — deliberate, not a limitation being worked around.
338
340
 
339
341
  ### 🔔 Desktop banners: `vibe --notify`
@@ -878,6 +880,7 @@ The full order, highest first: **a flag** → **an environment variable** → **
878
880
  | `--report [days]` | How long you waited on agents, and on which projects, from the local turn log | `7` days |
879
881
  | `--card [--out <path>]` | With `--report`: the totals as a shareable image - PNG on macOS, SVG anywhere - saved to `~/.vibeaudio/card.png`, replaced each run | off |
880
882
  | `--statusline` | The same state as one plain line for tmux or a shell prompt (`working ×2`, `waiting: api`); prints nothing when idle | — |
883
+ | `--why` | Why the music is playing or silent, as one plain line (the first line of `--status`) | — |
881
884
  | `--state` | What every agent on the machine is doing, as one line of JSON: `idle`, `working`, `stuck` or `waiting` | — |
882
885
  | `--events` | Stream agent state changes as JSON lines, starting with the current state, until stopped | — |
883
886
  | `--dashboard` | Serve a read-only live view of every agent on this machine at `http://127.0.0.1:4747`, and open it. `--port <n>` and `--no-open` adjust it | — |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibeaudio",
3
- "version": "0.25.2",
3
+ "version": "0.26.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
@@ -99,6 +99,7 @@ Procedural focus music while your AI coding tools think.
99
99
  --port <n> With --dashboard: the port (default ${require("./dashboard").DEFAULT_PORT}, else a free one)
100
100
  --no-open With --dashboard: do not open the browser
101
101
  --statusline Print that as one plain line for tmux or a prompt; prints nothing when idle
102
+ --why One plain line: why the music is playing or silent (the first line of --status)
102
103
  --events Stream agent state changes as JSON lines, until stopped
103
104
  --doctor Check the setup; each problem comes with its fix (exit 1 if any)
104
105
  --stop Stop the background player, then exit
@@ -238,6 +239,7 @@ function parseArgs(argv) {
238
239
  let statusFlag = false;
239
240
  let stateFlag = false;
240
241
  let statuslineFlag = false;
242
+ let whyFlag = false;
241
243
  let eventsFlag = false;
242
244
  let doctorFlag = false;
243
245
  let notifyFlag = null;
@@ -422,6 +424,12 @@ function parseArgs(argv) {
422
424
  continue;
423
425
  }
424
426
 
427
+ if (arg === "--why") {
428
+ whyFlag = true;
429
+ i += 1;
430
+ continue;
431
+ }
432
+
425
433
  if (arg === "--state" || arg === "--events") {
426
434
  if (arg === "--state") stateFlag = true;
427
435
  else eventsFlag = true;
@@ -649,6 +657,7 @@ function parseArgs(argv) {
649
657
  status: statusFlag,
650
658
  state: stateFlag,
651
659
  statusline: statuslineFlag,
660
+ why: whyFlag,
652
661
  music,
653
662
  events: eventsFlag,
654
663
  doctor: doctorFlag,
@@ -1837,6 +1846,7 @@ async function run() {
1837
1846
  status: showStatus,
1838
1847
  state: showState,
1839
1848
  statusline: showStatusline,
1849
+ why: showWhy,
1840
1850
  music,
1841
1851
  events: followEvents,
1842
1852
  doctor: showDoctor,
@@ -2011,6 +2021,13 @@ async function run() {
2011
2021
  return;
2012
2022
  }
2013
2023
 
2024
+ // --status's first line without the rest, plain: for the mod's pane and band (#60), a prompt segment, a script.
2025
+ if (showWhy) {
2026
+ const hooks = require("./hooks");
2027
+ console.log(hooks.explainMusic(musicFacts()).text);
2028
+ return;
2029
+ }
2030
+
2014
2031
  if (dashboard) {
2015
2032
  const { startDashboard } = require("./dashboard");
2016
2033
  let server;
package/src/hooks.js CHANGED
@@ -266,7 +266,7 @@ const TARGETS = {
266
266
  seed: () => ({}),
267
267
  // Codex records a trusted_hash per hook in config.toml and asks before
268
268
  // running one it has not seen, so the install is not live until approved.
269
- note: "Codex asks you to trust each new hook the first time it fires — approve each one once."
269
+ note: "Codex asks you to trust each new hook once — in the desktop app via Review hooks in the composer (Allow all), in the CLI the first time each fires."
270
270
  },
271
271
  cursor: {
272
272
  name: "Cursor",