zyx1121/music-mod
music-mod
/music:在提示列上方用一行显示 macOS Music.app 正在播放的内容。可点击的播放/暂停图标、track · artist · album、带时间的进度条,以及可点击的下一首图标。每 5 秒读取一次 Music.app,由所有打开的工作阶段共享;其间时钟继续跳动。
关于这个 mod
music-mod
/musicfor Claude Code:实时显示 Music.app 正在播放的内容,位于提示列上方的一行;播放/暂停和下一首都可以点击。
claude-code · mod · function-hooks · macos · music · now-playing
▶️ Tipsy · WANUKA · Greenhorn ████████████░░░░░░░░ 2:43 / 3:39 ⏭️
<sub>在任何布局中,提示列正上方的横条。显示时它的时钟每秒跳动;▶️ 和 ⏭️ 可以点击。</sub>
长时间的工作阶段需要配乐,但打开 Music.app 查看当前播放内容会打断流程。这个 mod 让答案只需一个指令就在眼前,直接显示在你正在使用的终端里:曲目、播放位置,以及两个可以暂停或跳过的图标。
这是一个 Claude Code mod:功能位于 TypeScript hooks 模块中的插件,使用与内置 /diff 面板相同的引擎 API。它绘制在 AbovePrompt 横条中,因此无论逐字稿是全屏还是内嵌,都会位于输入框上方,不会占用侧边停靠栏。无 shell hooks、无 MCP server;无论打开多少会话,每 5 秒只调用一次 osascript。
安装
function hooks 处于早期体验阶段,因此只有打开旗标时引擎才会加载 mod。将它加入 shell 配置文件:
export CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1
然后从 GitHub 或本地 clone 作为插件安装:
/plugin marketplace add zyx1121/music-mod
/plugin install music-mod@music-mod
也可以不安装,在一个工作阶段中试用:
claude --plugin-dir /path/to/music-mod
互动工作阶段一开始,这一行就会显示。在工作阶段中:
/music 隐藏或再次显示
上一次选择会在工作阶段之间记住。
仅限 macOS:通过 Apple events 读取 Music.app。第一次读取时,终端可能会询问你是否允许控制 Music。
读取操作绝不会启动 Music.app,即使读取发生时你正在退出它也一样:事件会根据进程 ID 发送给正在运行的进程,已经退出的进程会被视为已关闭。只有点击状态图标或 ⏭️ 时,才会按名称与 Music.app 通信。
显示内容
从左到右的一行:
| 部分 | 内容 |
|------|---------|
| ▶️ ⏸️ ⏩ ⏪ | 播放器状态。点击即可播放或暂停。 |
| 标题 | track · artist · album;横条太窄时会以省略号截断 |
| 横条 | 进度会延伸填满标题留下的宽度(至少 6 个单元格),然后显示位置 / 时长 |
| ⏭️ | 点击跳到下一首。 |
Music.app 关闭或停止时,横条会改为显示相应状态。osascript 失败时(未授权、超时),横条会显示原因并继续轮询。需要占用横条的 survey 会让出位置。
配置
| 字段 | 类型 | 默认值 | 功能 |
|-------|------|---------|--------------|
| refreshMs | number | 5000 | 横条显示时,两次读取 Music.app 之间的毫秒数。每个打开的工作阶段每个间隔共用一次读取,时钟在间隔中间继续跳动。最低为 1000。 |
| showOnStart | boolean | true | 互动工作阶段一开始就显示这一行。使用过 /music 后,你的选择优先于此项。 |
在任意插件 userConfig 字段中设置:使用 /config,或在设置中填写 music-mod.refreshMs。
构建方式
hooks/register.ts导出register(on, options)。在session.start时注册/music并显示横条(从$.store读取上一次的/music选择,否则使用showOnStart);command.run会切换并记住它;每秒一次的$.clock.everytick 会根据上次读取重绘时钟,并在refreshMs已经过(或曲目播放完)后重新读取;session.end时取消计时器;点击图标会运行其 AppleScript 并立即读取。hooks/now-playing.ts保存 JXA 脚本(由osascript -l JavaScript运行)、将 JSON 转成Model的解析器、时钟与进度条格式化器、读取之间延续的位置,以及每个图标背后的一行 AppleScript。脚本只请求横条要绘制的内容:不读取系统音量(读取会唤醒coreaudiod),也不遍历播放列表。hooks/shared-read.ts是所有工作阶段共用的读取机制:位于$TMPDIR/music-mod/now.json的小型 JSON 文件。读取足够新时,工作阶段会直接取用;否则它会取得文件、运行osascript并写回结果,让其他工作阶段等待,而不是各自执行。hooks/views/band-view.tsx在ui.render中使用引擎的Box、Text和Button,为AbovePrompt组件绘制Model。types/claude-code.d.ts是这个 mod 所依据的引擎契约,复制自anthropics/claude-code/mods/types。
bunx -p typescript tsc -p tsconfig.json # typecheck
CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1 claude plugin test . # 35 tests, the engine's own harness
这些 mod 所依据的 API 可能在版本之间无预告地变化。发生变化时,从上游更新 types/claude-code.d.ts,让类型检查指出移动了哪些内容。
贡献
欢迎提交 issue 和 PR。基本规则位于 CONTRIBUTING.md。
许可证
MIT · now playing: whatever you left on
安装
请先查看作者 README 确认 marketplace 和插件名称;命令可能随仓库结构改变。
claude plugin marketplace add zyx1121/music-mod claude plugin install music-mod
原文 / README
music-mod
/musicfor Claude Code: what Music.app is playing, in one line above the prompt, live, with play/pause and next a click away.
claude-code · mod · function-hooks · macos · music · now-playing
▶️ Tipsy · WANUKA · Greenhorn ████████████░░░░░░░░ 2:43 / 3:39 ⏭️
<sub>The band directly above the prompt, in any layout. Its clock ticks every second while shown; ▶️ and ⏭️ are clickable.</sub>
Long sessions have a soundtrack, and reaching for Music.app to check what is on breaks the flow. This mod keeps the answer one command away, inside the terminal you are already looking at: the track, where it is, and two glyphs to pause it or skip it.
It is a Claude Code mod: a plugin whose behaviour lives in a TypeScript hooks module, written against the same engine API as the built-in /diff pane. It draws into the AbovePrompt band, so it sits above the input whether the transcript is fullscreen or inline, and never takes a side dock. No shell hooks, no MCP server, and one osascript call every five seconds however many sessions are open.
Install
Function hooks are early access, so the engine loads a mod only with the flag on. Put it in your shell profile:
export CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1
Then install it as a plugin, from GitHub or from a local clone:
/plugin marketplace add zyx1121/music-mod
/plugin install music-mod@music-mod
Or try it for one session without installing:
claude --plugin-dir /path/to/music-mod
The line shows as soon as an interactive session starts. In the session:
/music hide it, or show it again
Your last choice is remembered between sessions.
macOS only: it reads Music.app through Apple events. The first read may ask you to allow your terminal to control Music.
Reading never launches Music.app, not even when a read lands while you quit it: the events go to the running process by its ID, and a process that has gone reads as closed. Only a click on the state glyph or ⏭️ talks to Music.app by name.
What it shows
One line, left to right:
| Part | Content |
|------|---------|
| ▶️ ⏸️ ⏩ ⏪ | The player state. Click it to play or pause. |
| Title | track · artist · album, cut with an ellipsis when the band is narrow |
| Bar | Progress, stretched to fill whatever width the title leaves (6 cells at the least), then position / duration |
| ⏭️ | Click it to skip to the next track. |
When Music.app is closed or stopped the band says so instead. When osascript fails (not authorized, timed out), the band shows the reason and keeps polling. A survey that takes the band is yielded to.
Configuration
| Field | Type | Default | What it does |
|-------|------|---------|--------------|
| refreshMs | number | 5000 | Milliseconds between reads of Music.app while the band is shown. Every open session shares one read per interval, and the clock ticks in between. Floored at 1000. |
| showOnStart | boolean | true | Show the line as soon as an interactive session starts. Once you have used /music, that choice wins over this. |
Set it as any plugin userConfig field: /config, or music-mod.refreshMs in settings.
How it is built
hooks/register.tsexportsregister(on, options). Onsession.startit registers/musicand shows the band (the last/musicchoice from$.store, elseshowOnStart);command.runtoggles it and remembers; a one-second$.clock.everytick redraws the clock from the last reading and, oncerefreshMshas passed (or the track has run out), takes a new one; the timer is cancelled onsession.end; a pressed glyph runs its AppleScript and reads at once.hooks/now-playing.tsholds the JXA scriptosascript -l JavaScriptruns, the parser that turns its JSON into aModel, the clock and progress-bar formatters, the position carried forward between reads, and the one-line AppleScript behind each glyph. The script asks only for what the band draws: no system volume (reading it wakescoreaudiod) and no playlist walk.hooks/shared-read.tsis the reading every session shares: a small JSON file at$TMPDIR/music-mod/now.json. A session takes the reading there when it is recent enough, else claims the file, runsosascriptand writes the result back, so the other sessions wait for it instead of running their own.hooks/views/band-view.tsxdraws theModelwith the engine'sBox,TextandButtononui.renderfor theAbovePromptcomponent.types/claude-code.d.tsis the engine contract this mod is typed against, copied fromanthropics/claude-code/mods/types.
bunx -p typescript tsc -p tsconfig.json # typecheck
CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1 claude plugin test . # 35 tests, the engine's own harness
The API these mods are written against may change between releases without notice. When it does, refresh types/claude-code.d.ts from upstream and let the typecheck point at what moved.
Contributing
Issues and PRs are welcome. Ground rules live in CONTRIBUTING.md.
License
MIT · now playing: whatever you left on

