# opencode-widget **Repository Path**: fushoujiang/opencode-widget ## Basic Information - **Project Name**: opencode-widget - **Description**: OpenCode 桌面悬浮挂件:圆形头像 + 状态环,实时显示 OpenCode 当前运行状态 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-08-19 - **Last Updated**: 2026-09-04 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # OpenCode Widget 一个常驻桌面的圆形悬浮小挂件(macOS),实时显示 [OpenCode](https://opencode.ai) 当前正在做什么,并且可以**直接在挂件上确认/拒绝 OpenCode 的权限请求**,不用切回 OpenCode 窗口。 ## 演示 [![演示视频](assets/cover.jpg)](https://github.com/user-attachments/assets/bae20744-84c2-4d5b-968e-06867cb97aba) [点击播放演示视频](https://github.com/user-attachments/assets/bae20744-84c2-4d5b-968e-06867cb97aba) · [GitHub 仓库(页内自动播放)](https://github.com/fushoujiang/opencode-widget) ## 特性 - **圆形头像挂件**:头像 + 状态环 + 实时动作提示 - **实时状态**: - 🟢 绿环呼吸 = 正在运行工具(如 `⚡ bash · git status`) - 🟠 橙环 = 正在思考 / 生成文本 - 🔴 红环 + 角标 = 有权限请求等待人工确认 - ⚪ 灰环 = 空闲(`摸鱼中 🐟`) - **内联权限确认**(v2 新增): - OpenCode 弹出「是否允许执行」时,挂件红环告警 + **系统通知 + 提示音** - 头像下方直接显示当前待确认:工具图标 + 命令 + 剩余条数徽标 - 三个圆形图标按钮:✓ 本次允许、∞ 总是允许(记住规则)、✕ 拒绝 - **悬停命令行原地展开**完整命令(多行),移开收回 - 点击后 OpenCode 继续执行,无需切窗口;回复失败会闪红警示 - 处理完一条自动显示下一条,全部完成恢复原样 - **只展示活跃会话**:最近 20 秒内有活动的会话才显示 - **自定义头像**:把照片存为 `avatar.png` 放同一目录,重启即可 ## 环境要求 - macOS(需 Xcode CommandLineTools,即 `swiftc`) - OpenCode 桌面端已安装并运行过(读取 `~/.local/share/opencode/opencode.db`) - OpenCode 版本需支持 `GET /permission` 接口(v1.18+) ## 构建 / 运行 ```bash ./build.sh # 编译 -> 裸二进制 + OpenCode Widget.app(已 ad-hoc 签名) open "OpenCode Widget.app" # 推荐:双击/命令行启动 bundle # 或开发模式:./opencode-widget & ``` 停止:`pkill -f opencode-widget` > bundle 模式才能用「通知点击展开」等系统能力;首次使用请在 系统设置 → 通知 里允许 OpenCode Widget。 ## 权限确认怎么连上 OpenCode? 挂件通过 OpenCode server 的 HTTP API 工作(`GET /permission` 轮询待确认列表,`POST /permission/:id/reply` 回复),按以下顺序自动发现并连接 server: 1. 环境变量 `OPENCODE_WIDGET_SERVER`(如 `http://127.0.0.1:4096`,可带 `user:pass@`) 2. **桥接文件** `~/.local/state/opencode-widget/server*.json`(见下,插件自动维护) 3. 桌面端日志里解析出的 sidecar 地址 4. `lsof` 扫描本机 opencode 进程的监听端口 ### 推荐方式:安装桥接插件(全自动) 桌面端的内置 server 每次启动会生成随机密码,外部进程拿不到。安装官方插件机制的桥接插件后**全自动**: ```bash cp plugin/widget-bridge.js ~/.config/opencode/plugins/ ``` 插件会在 opencode 启动时自动做两件事: - 把 server 地址和凭据写入 `~/.local/state/opencode-widget/server-.json`(桌面端重启后挂件自动重连,无需任何手动操作) - 把 `permission.asked / permission.replied` 事件实时落盘到 `~/.local/state/opencode-widget/pending/`,挂件监听该目录获得**毫秒级提醒**(轮询作为交叉校验;server 完全不可达时以该目录内容兜底显示) > 注:插件在 opencode **启动时**加载,安装后需重启桌面端 / TUI 生效。 ### 备用方式:手动桥接命令 没装插件时,可用 `/widget-bridge` 命令让 opencode 自己把凭据写给挂件: ```bash cp command/widget-bridge.md ~/.config/opencode/command/ ``` 然后在 OpenCode 里执行一次 `/widget-bridge`。桌面端每次重启后密码会变,需要重新执行。 ### 终端 TUI / opencode serve - 没设密码:挂件自动连接,无需任何配置 - 设了 `OPENCODE_SERVER_PASSWORD`:给挂件也设同样的 `OPENCODE_WIDGET_PASSWORD` 环境变量 > 注:若桌面端开了「信任/自动放行」模式,server 端会直接放行所有工具调用,不会产生待确认请求(挂件自然也不弹)。此时待确认主要来自 TUI / 手动 `opencode serve` 的会话。 ## 使用自定义头像 把图片命名为 `avatar.png`(或 `.jpg` / `.jpeg`)放到挂件二进制同目录,重启挂件即可自动加载。没放就用默认 🤖。 ## 工作原理 **状态展示**:OpenCode 把会话、消息、工具调用等全部存在本地 SQLite(`~/.local/share/opencode/opencode.db`),挂件以只读方式打开该库,读取最新的 `session` → 最新的 `part` → 解析类型和状态: | part 类型 | 状态 | |---|---| | `tool` + `status=running` | 🟢 运行中 | | `reasoning` / `step-start` | 🟠 思考中 | | `text` | 🟠 生成文本中 | | `step-finish` / 其他 | ⚪ 空闲 | 事件驱动刷新:`DispatchSource` 监听 `opencode.db-wal` 写入事件 + 5 秒兜底定时器。 **权限确认(PermissionBridge)**: - 发现链:env → 桥接文件(插件维护)→ 桌面端日志 → lsof 扫描(后台队列 + 2s 看门狗,防止 lsof 偶发挂死) - 认证:Basic auth,凭据来自桥接文件;探测时自动识别 ok / locked(缺凭据)/ unsupported(版本过旧)/ dead 四种状态,底部小字提示 - 轮询 `GET /permission`(1.2s)+ 插件 spool 目录监听(毫秒级唤醒);连续 5 次失败自动重走发现链 - 回复 `POST /permission/:id/reply`(`once` / `always` / `reject`),失败闪红警示 - 新请求到达:系统通知(osascript)+ Glass 提示音 **窗口**:单窗口无框(borderless、无系统阴影——透明内容动画期间系统阴影层会产生残影),SwiftUI 测量内容自然高度后回调 `setFrame`(顶部锚定、宽度恒定 120 保证悬停稳定)。 ## 可配置 - 数据库路径:环境变量 `OPENCODE_WIDGET_DB`(默认 `~/.local/share/opencode/opencode.db`) - 指定 server:`OPENCODE_WIDGET_SERVER`(覆盖自动发现) - server 密码:`OPENCODE_WIDGET_PASSWORD` - 桥接/spool 目录:`OPENCODE_WIDGET_BRIDGE_DIR`(默认 `~/.local/state/opencode-widget`,插件侧同名变量保持一致) - 调试日志:`OPENCODE_WIDGET_DEBUG=1` - 活跃判定窗口:`main.swift` 里 `activeWindowMs`(默认 20 秒) ## 测试 / 回归 ```bash tests/run_regression.sh # 自动化回归:编译、连接、待确认解析、locked/old/密码认证分支、断连自愈 ``` 人工回归清单(需肉眼/点击):三按钮回复语义、悬停命令展开 + 多请求预览、通知点击展开、桌面端重启后插件自动桥接。 ## 更多文档 - [docs/deploy.md](docs/deploy.md) —— **部署运维手册**:从零部署清单、故障排查表、重启自愈链路 - [docs/opencode-integration.md](docs/opencode-integration.md) —— opencode server 外部集成契约(做任何 opencode 周边工具可直接参考) - [docs/pitfalls.md](docs/pitfalls.md) —— macOS 悬浮挂件 SwiftUI 踩坑实录(重影/膨胀/抖动/挂死…) - [docs/design-notes.md](docs/design-notes.md) —— 已知边界与设计取舍(轮询竞态、双通道语义、真实 ask 场景盘点、UI 迭代记录) ## License [MIT](LICENSE)