不用 Mac 也能拥有刘海:Coucou 的 Tauri Windows 版从零部署,3 步把药丸钉在屏幕顶端
【免费下载链接】coucouA tiny friend in your Mac's notch and on your iPhone that keeps an eye on your AI coding agents: Claude Code, Codex, Cursor, Gemini CLI, Antigravity and more. Approve from the notch or your Lock Screen.项目地址: https://gitcode.com/gh_mirrors/co/coucou
当 Claude Code、Codex、Cursor 这些 AI 编码代理开始接管终端时,一个新的"视觉盲区"出现了:代理在后台读文件、跑命令、请求权限,而你只能回到终端里一行行翻日志。Coucou 的解法很直接——在 macOS 上,它把一只叫 Mochi 的小精灵塞进刘海;在 Windows 上,它用 Tauri 2 在屏幕顶端"伪造"了一个刘海岛(Island),让所有代理会话以药丸(pill)的形式常驻在视野边缘。这个项目近期连续登上开源社区热门榜单,安装教程与集成指南也密集出现,但它真正值得读的,是仓库里那一套把"无边框透明置顶窗口 + 命名管道中继"玩到极致的工程细节。本文基于 windows/ 目录的真实源码,带你从零部署并拆解其实现。
一个跨平台问题的统一解法
Coucou 的仓库布局本身就在讲这个故事:NotchBuddy/ 是 macOS 原生版(Swift/SwiftUI),windows/ 是 Tauri 2 的 Windows/Linux 版,NotchBuddy/Sources/Phone/ 则是 iPhone 伴侣。Windows 版由三部分组成:TypeScript 编写的无框架前端(src/,Vite 构建)、Rust 编写的 Tauri 后端(src-tauri/),以及一个独立的 Rust 可执行文件coucou-hook.exe(hook/),后者是 Claude Code 与 Coucou 之间的中继。
Windows 版的核心前提,在 island.rs 的注释里写得很直白:"There is no notch on a PC, so the island is a black shape drawn at the top centre of the main display inside a borderless, transparent, always-on-top window that never takes focus."没有刘海,就在主显示器顶部中央画一个黑色药丸。所有平台差异被收敛进 platform/ 这一层:Windows 走 Win32 + 光标轮询,Linux 走 gtk-layer-shell(见 tauri.linux.conf.json 与 linux/arch/PKGBUILD),其余业务逻辑两端共享。
把窗口钉在屏幕顶端:Tauri 2 的无边框透明置顶窗口
窗口的形态完全由 tauri.conf.json 决定,它定义了名为island的窗口:
"windows": [{ "label": "island", "width": 240, "height": 6, "resizable": false, "decorations": false, "transparent": true, "shadow": false, "alwaysOnTop": true, "skipTaskbar": true, "focus": false, "center": false, "dragDropEnabled": false, "additionalBrowserArgs": "--disable-features=msWebOOUI,msPdfOOUI,msSmartScreenProtection --autoplay-policy=no-user-gesture-required" }]逐项看下来是标准的"刘海窗口"配方:decorations: false去掉标题栏,transparent: true让黑块之外的区域完全透明,alwaysOnTop: true保证永远压在应用之上,skipTaskbar: true不进任务栏,focus: false不抢焦点。但注意初始尺寸是240×6——那不是窗口的最终形态,而是隐藏态下贴在屏幕顶端的一条"唤醒带"(wake strip),高度只有 6 逻辑像素,平时肉眼不可见,鼠标一滑过去岛就探出头来。展开后的面板则是 720×320,常量定义在 island.rs:
pub const PANEL_W: f64 = 720.0; pub const PANEL_H: f64 = 320.0; pub const STRIP_W: f64 = 240.0; pub const STRIP_H: f64 = 6.0;focus: false在 Tauri 层面只是第一步,Windows 上真正让它"永不激活"的是 platform/windows.rs 里的make_non_activating:用WS_EX_NOACTIVATE阻止点击窃取焦点,用WS_EX_TOOLWINDOW把窗口挡在 Alt-Tab 之外;文本输入时再临时通过set_activating撤销该标志,所以聊天框里打字不会影响前台应用。定位逻辑在apply_geometry:取目标显示器的物理坐标,窗口水平居中、垂直贴顶,之后交给platform::pin_to_monitor。目标显示器支持三种选择——primary、cursor(光标所在屏)、at:<x>,<y>(记住的逻辑坐标)——并以"位置+名称+尺寸"作为显示器身份键,即使分辨率变化或拔掉副屏也能重新匹配到原位置,island.rs 里甚至为这套匹配逻辑写了专门的单元测试。
3 步从零部署:把药丸钉上屏幕
第 1 步:构建与安装。仓库根目录的 windows/README.md 给出了完整命令链,需要 Rust、Node 20+ 和 MSVC 构建工具:
cd windows npm install npm run tauri dev # 热更新的开发构建 npm run pack # 产出安装包到 windows/release/有趣的是 package.json 里predev/prebuild都会先执行cargo build --release -p coucou-hook,也就是说每次启动应用前,中继程序coucou-hook.exe会被一并编译,再通过bundle.resources打进 NSIS/MSI 安装包。首次运行会遇到 SmartScreen 的"未知发布者"警告(安装包尚未代码签名),点"更多信息 → 仍要运行"即可;社区教程里流传的"5 分钟上手"说的正是这条路径。应用启动后会在%LOCALAPPDATA%\Coucou\bin\下部署中继程序——hooks.rs 的ensure_hook_exe会从资源目录、可执行文件旁等多个候选路径逐一尝试,注释里甚至记录了历史上 glob 资源路径导致的"静默安装失败"教训。
第 2 步:装 hooks,让代理事件流进药丸。打开 Settings → Claude Code → Install hooks,你会先看到一份精确的 diff:将要写入%USERPROFILE%\.claude\settings.json的内容、以及带日期戳的备份路径——只有在你点击之后才会真正写入。写入器(逻辑在 config_file.rs,入口在 hooks.rs)遵循严格规程:严格读取、拒绝意外类型、生成 diff、备份必须成功、用 fingerprint 校验预览与当前文件一致、最后原子写入。如果预览之后有人改了 settings.json,写入会被拒绝而不是覆盖;Coucou 只会合并自己的条目、移除自己的条目,别的工具的 hooks 一概不动——测试专门验证了"保留他人钩子"与"重复安装只留一份"。
第 3 步:日常使用。鼠标滑到屏幕顶端中央——6 像素唤醒带被触发,Mochi 探出头(见 fsm.ts 的状态机与 island.ts 的wakeStrip监听)。Claude Code 发起权限请求时,岛自动展开为审批卡;在卡片上点 Allow/Deny,或按Ctrl+Alt+A跳到等待中的请求。审批完成、任务结束、集成变红变绿,药丸都会以徽标加音效的方式通知你。
Rust 后端与命名管道中继:审批闭环的核心
整个"从终端到药丸"的链路是 Coucou 最值得读的工程部分。Claude Code 每次事件都会执行coucou-hook.exe <Event>(hook/main.rs),这个中继程序把 stdin 上的 hook JSON 规范化、裁剪(单字段上限 2000 字节,但 Edit/Write 的 diff 文本会保留到 256KB 以支持"实时 diff"),然后写入命名管道。管道名是\\.\pipe\coucou-<SID>——SID 后缀是关键:命名管道位于机器级命名空间,任何账户都能抢先创建,把 SID 拼进名字从物理上杜绝了不同账户之间的干扰;而 hook/win.rs 在连接后还会用GetNamedPipeServerProcessId校验服务端进程确实属于自己,双端防御。
服务的接受端在 pipe.rs。普通事件是"发出即忘"(fire-and-forget),唯独PermissionRequest会保持连接:岛的卡片确认上屏后回复ack,人类做出选择后回复allow/deny(或针对提问回复{"answers":{…}}),再由中继程序把裸词翻译成 Claude Code 期望的hookSpecificOutputJSON——Claude Code 期望的线格式只存在于一个地方,这是整个设计的纪律性所在。
"绝不阻塞代理"是硬规则,由三层超时共同保证:
coucou-hook侧:连接管道 300ms 超时,Coucou 不在就直接退出,不打印任何输出;- 普通事件整体预算 2 秒;权限请求最长等 110 秒,到点由终端接管;
- 应用侧:等卡片上屏的 ACK 只有800ms,之后才进入最长 108 秒的人类决策等待(pipe.rs)。
这套"先确认 UI 真的显示了、再进入长等待"的两段式协议,保证了一个暂停的岛或一个卡死的 webview 最多让代理停顿几百毫秒,而不是几分钟。同一条管道还服务于十多种代理:Gemini CLI、Copilot CLI、Codex、Muse Code、OpenCode、Amp、Hermes、Cursor、Antigravity 各自的事件名与字段会在 hook/src/normalize.rs 被映射到 Claude Code 的语义上,而 agents.rs 根据每个代理的 shell 生成不同的命令行引用方式——Git Bash 用正斜杠加引号、PowerShell 用& '...'、cmd /C则裸写路径。第三方工具甚至可以直接向管道写入带coucou_agent字段的 JSON 来获得自己的药丸,接入规范见 docs/AGENTS.md。
没有刘海的药丸替代方案:点击穿透与"隐藏即休眠"
Windows 上没有刘海可供"躲藏",交互因此被设计成三种形态:隐藏(只留 6px 唤醒带)、紧凑(288×32 的小药丸)、展开(最大 640×160 的面板),几何常量集中在 layout.ts。真正复杂的是点击穿透:一个置顶的透明窗口如果拦截鼠标,底下所有应用都会遭殃。macOS 上 NSPanel 有现成的ignoresMouseEvents,Windows 上 Coucou 用的是"光标轮询 + 动态切换 WS_EX_TRANSPARENT"方案——island.rs 的spawn_cursor_poll以约 60Hz(16ms)读取全局光标位置,前端把岛的矩形形状上报给 Rust(set_island_rect),Rust 在同一个 tick 里决定光标是否落在岛上,命中则关闭透明标志、离开则重新开启:
let on_island = r.w > 0.0 && x >= r.x - HIT_MARGIN && x <= r.x + r.w + HIT_MARGIN && y >= r.y - HIT_MARGIN && y <= r.y + r.h + HIT_MARGIN;HIT_MARGIN设为 14px(比 macOS 的 6pt 宽),注释给出的理由是"点击绝不能被吞掉"——移动中的光标还没到按钮,穿透标志已经先一步关闭。光标轮询线程平时挂在Condvar上(PollGate),岛隐藏时整个线程休眠,成本为零;Linux 没有全局光标,轮询周期直接放宽到 500ms 只做显示器布局监测。前端同样遵守"隐藏即休眠":island.ts的帧循环在岛收起时停止requestAnimationFrame,动画、引擎、粒子全部冻结——这正是社区文章里"隐藏时 0% CPU 占用"传说的源码出处。
Windows 专属的工程细节还有两个值得注意。一是文件拖放:webview_drop.rs 发现 Tauri 默认的 drop target 会被 WebView2 的子窗口挡住,经典 Explorer 文件夹视图根本拖不进文件,于是直接让 WebView2 接管拖放,页面用chrome.webview.postMessageWithAdditionalObjects把 File 对象交回 Rust 换回真实路径。二是"Open terminal":session_window.rs 从中继进程沿进程树向上走(WindowsTerminal → pwsh → node → bash → coucou-hook 这条链),锁定拥有窗口的祖先进程再SetForegroundWindow把它带到前台——比 macOS 版"只监听 VS Code 会话"的限制宽松得多,任何终端都能工作。密钥则全部存放在 Windows Credential Manager,磁盘上只有不敏感的偏好 JSON;settings.rs 甚至会对损坏的配置文件做字节级隔离备份,并兼容 PowerShell 写出的 UTF-8 BOM。
Coucou 的 Windows 版是一份高质量的 Tauri 2 参考实现:它示范了如何用声明式窗口配置加少量平台代码,在 WebView2 之上搭出一个"不抢焦点、可穿透、隐藏零开销"的系统级 UI;也示范了如何把一个 AI 代理的权限审批闭环做成真正非阻塞的异步协议。三个超时、双端 SID 校验、diff-预览-指纹-原子写,每一处都对应一条可以照抄的工程规则。如果你也在做桌面端的 AI 伴侣或代理监控工具,windows/ 目录值得通读——它把"没有刘海"从遗憾变成了一个更通用的设计起点。
【免费下载链接】coucouA tiny friend in your Mac's notch and on your iPhone that keeps an eye on your AI coding agents: Claude Code, Codex, Cursor, Gemini CLI, Antigravity and more. Approve from the notch or your Lock Screen.项目地址: https://gitcode.com/gh_mirrors/co/coucou
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考