5.0 KiB
5.0 KiB
Claude Code Notify
为 Claude Code 提供原生 Windows 通知:任务完成或需要你输入时弹出 toast,点击即可跳回原终端 / 编辑器窗口(并能切回正确的 Windows Terminal 标签页)。
原版 Rust 项目的 C# / .NET 10 + Avalonia 12 重写版,采用「CLI 子命令 + 常驻 Host」进程模型,由 Claude Code 的 hook 驱动。仅支持 Windows 10 / 11 (x64)。
功能
- 任务完成 / 需要输入时弹出原生 toast,可堆叠、自由定位(水平 × 垂直 + 留白)、跨虚拟桌面显示
- 点击 toast 跳回发起请求的窗口,并能切回原 Windows Terminal 标签页
- 自动识别并显示调用方 App 图标(VSCode / Cursor / JetBrains / 终端…)
- 输入类通知常驻、完成类自动消失(正盯着目标窗口时停留更短)
- 非阻塞投递,钩子毫秒级返回,不拖慢 Claude Code
- NativeAOT 单文件、无运行时依赖
架构
flowchart LR
CC[Claude Code] -->|UserPromptSubmit| SAVE["notify save"]
CC -->|Stop| NOTIFY["notify notify"]
CC -->|Notification / PreToolUse| INPUT["notify input"]
CC -->|SessionEnd| CLEAN["notify cleanup"]
SAVE --> ST[(状态文件)]
CLEAN -.删除.-> ST
NOTIFY --> SP[(spool 队列)]
INPUT --> SP
SP --> HOST
ST -.读取.-> NOTIFY
ST -.读取.-> INPUT
subgraph HOST["notify host (Avalonia 常驻)"]
W[FileSystemWatcher] --> T1[Toast]
W --> T2[Toast]
end
T1 -->|点击| ACT[激活窗口 + 切 WT 标签]
- CLI 子命令(
save/notify/input/cleanup):纯 Win32 互操作 + 落盘,不加载 Avalonia,做完即退,毫秒级返回。 - Host:Avalonia 单例常驻,仅托盘存在,监视 spool 目录弹通知。
时序
整体生命周期
sequenceDiagram
autonumber
actor User as 用户
participant CC as Claude Code
participant Cli as notify (CLI)
participant State as 状态文件
participant Spool as spool 队列
participant Host as notify host
participant Win as 目标窗口
User->>CC: 发送消息
CC->>Cli: notify save (stdin: session_id + prompt)
Cli->>Cli: 抓前台窗口 / 进程树取图标 / WT 标签
Cli->>State: 写入状态
Cli-->>CC: 立即退出
Note over CC: Claude 处理中…
alt 任务完成
CC->>Cli: notify notify
else 需要输入 / 提问 / 出 Plan
CC->>Cli: notify input
end
Cli->>State: 读取状态
Cli->>Spool: 原子写入 NotifyMessage
Cli->>Host: 不在则拉起(不等待)
Cli-->>CC: 立即退出(~100ms)
Host->>Spool: FileSystemWatcher 消费
Host-->>User: 弹出 toast
User->>Host: 左键点击 toast
Host->>Win: 抢前台激活 (+ 切回 WT 标签)
Win-->>User: 回到原窗口
User->>CC: 结束会话
CC->>State: notify cleanup 删除状态
非阻塞投递
CLI 写完 spool 即走、不等 Host,因此钩子毫秒级返回。
sequenceDiagram
autonumber
participant Cli as notify notify/input
participant Spool as spool 目录
participant Mtx as 单例互斥量
participant Host as notify host
Cli->>Spool: 写 tmp → 原子改名 json
Cli->>Mtx: TryOpenExisting?
alt Host 已在跑
Mtx-->>Cli: 存在 → 不拉起
else Host 未运行
Cli->>Host: Process.Start("host", UseShellExecute=true)
end
Cli-->>Cli: 立即返回(~100ms)
Host->>Spool: 启动 DrainExisting + Watcher 增量
Host->>Host: 读取并删除文件 → UI 线程弹 toast
点击 toast → 激活原窗口
sequenceDiagram
autonumber
actor User as 用户
participant Toast as ToastWindow
participant Act as WindowActivator
participant WT as WinTerminalTabs
participant Win as 目标窗口
User->>Toast: 左键点击主体
Toast->>Act: Activate(targetHwnd)
Act->>Win: ALT 模拟 + AttachThreadInput + SetForegroundWindow 组合技
Win-->>User: 窗口回到前台
opt 目标是 Windows Terminal 且有 RuntimeId
Toast->>WT: SelectTab(hwnd, runtimeId)
WT->>Win: UIAutomation 找到标签 → Select()
end
Toast->>Toast: 淡出关闭
安装
claude plugin marketplace add https://git.pchuan.top/cc-tools/notify.git
claude plugin install claude-code-notify@claude-code-notify
重启 Claude Code 后即生效。首次触发钩子时,scripts/notify.cmd 会自动从 Release 下载单文件 notify.exe,之后常驻。
- 托盘左键单击打开设置,右键退出。
- 从源码构建见 docs/build-and-install.md。
文档
| 文档 | 内容 |
|---|---|
| architecture.md | 进程模型、组件、目录结构 |
| hooks-and-cli.md | hook 事件、子命令、stdin、状态文件 |
| interop.md | 原生互操作与 AOT 说明 |
| build-and-install.md | 构建、安装、排错 |