@freely01/opencode-notify 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 luyanfeng
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,434 @@
1
+ # opencode-notify
2
+
3
+ opencode 通知插件 — 监听会话中的关键事件,通过多渠道推送通知到你的手机、群聊或桌面。
4
+
5
+ > ⚠️ **由AI辅助生成,内容及程序请辨别使用**
6
+ >
7
+ > **个人项目,按需使用**
8
+ >
9
+ > 此插件主要面向作者个人使用场景开发和测试,不一定适合所有用户和环境。
10
+ >
11
+ > **AI 提示:**
12
+ > - Windows 系统通知需额外安装 [BurntToast](https://github.com/Windos/BurntToast) PowerShell 模块
13
+ > - Linux 系统通知需 `libnotify` 包(桌面发行版通常预装)
14
+ > - 事件映射基于 @opencode-ai/plugin@1.15.12 的行为,后续版本升级可能影响兼容性
15
+ > - `run_completed` 事件暂未实现(opencode 无直接完成事件)
16
+ > - 屏幕跑马灯效果仅 Linux X11 环境支持(依赖 Python + PyGObject),Wayland/macOS/Windows 不生效
17
+ > - 仅在 Ubuntu 24.04 (X11) 环境下测试并使用,其它平台未验证
18
+ >
19
+ > 如有问题欢迎提 Issue,但不保证及时响应和修复。
20
+
21
+ ## 功能特性
22
+
23
+ - 监听 `permission_required` / `input_required` / `run_failed` 等事件
24
+ - 多渠道通知:系统通知、企业微信、飞书、自定义 Webhook(Gotify / Bark / PushDeer 等)
25
+ - YAML 配置文件,每项参数均有详细注释
26
+ - 去重机制:同一事件在时间窗口内不重复发送
27
+ - 活跃抑制:检测到用户在操作 TUI 时可自动跳过通知
28
+ - 零外部运行时依赖(仅 js-yaml 用于配置解析)
29
+ - **屏幕跑马灯**:通知时屏幕四边高亮闪烁(Linux X11,Python + GTK 内置)
30
+ - **渠道级事件过滤**:每个渠道可独立配置监听哪些事件,灵活分流
31
+
32
+ ## 平台支持
33
+
34
+ | 模块 | macOS | Linux | Windows |
35
+ |------|:-----:|:-----:|:-------:|
36
+ | 插件核心(事件监听/路由/分发) | ✅ | ✅ | ✅ |
37
+ | 自定义 Webhook / 企业微信 / 飞书 | ✅ | ✅ | ✅ |
38
+ | 诊断 CLI (`bun cli.ts`) | ✅ | ✅ | ✅ |
39
+ | **系统消息通知** | ✅ `osascript` 内置 | ⚠️ 需 `libnotify` 包 | ⚠️ 需 BurntToast 模块 |
40
+ | **屏幕跑马灯** | ❌ | ✅ Python+GTK 内置 | ❌ |
41
+
42
+ **说明:**
43
+ - **macOS**: 系统通知使用 `osascript`,系统内置,开箱即用
44
+ - **Linux**: 系统通知使用 `notify-send`,来自 `libnotify`。桌面发行版通常预装,如缺失可 `apt install libnotify-bin` / `yum install libnotify`
45
+ - **Windows**: 系统通知使用 PowerShell `New-BurntToastNotification`,需额外安装 [BurntToast](https://github.com/Windos/BurntToast) 模块。Webhook 渠道不受影响
46
+ - **屏幕跑马灯**: 仅 Linux X11 环境。使用 Python + PyGObject(GTK 3),Ubuntu GNOME 桌面内置,无需额外安装。Wayland 暂不支持
47
+ - 非系统通知模块(Webhook 推送、CLI 诊断)均为纯 HTTP/Node API,全平台一致
48
+
49
+ > **已测试渠道:** 系统通知、企业微信、自定义 Webhook(Gotify)。飞书等其他渠道理论可用,暂未做验证。
50
+
51
+ ## 快速开始
52
+
53
+ ### 1. 安装
54
+
55
+ 将插件添加到 `~/.config/opencode/opencode.json` 的 `plugin` 列表中:
56
+
57
+ **方式一:从 npm 安装(推荐)**
58
+ ```bash
59
+ npm install -g @freely01/opencode-notify
60
+ ```
61
+
62
+ ```json
63
+ {
64
+ "plugin": ["@freely01/opencode-notify"]
65
+ }
66
+ ```
67
+
68
+ **方式二:本地路径(开发调试)**
69
+ ```json
70
+ {
71
+ "plugin": [
72
+ "file:///home/<你的用户名>/path/to/opencode-notify/index.ts"
73
+ ]
74
+ }
75
+ ```
76
+
77
+ > 本地路径替换为你实际存放项目的目录。
78
+
79
+ ### 2. 配置
80
+
81
+ 创建 `~/.config/opencode/opencode-notify.yaml`,完整示例:
82
+
83
+ ```yaml
84
+ channels:
85
+ system_message:
86
+ enabled: true
87
+ # events: [permission_required, input_required] # 可选,不填继承全局
88
+
89
+ screen_flash:
90
+ enabled: true
91
+ duration: 3.5
92
+ speed: 5.0
93
+ intensity: 0.85
94
+
95
+ custom_webhook:
96
+ enabled: false
97
+ url: "https://gotify.example.com/message"
98
+ headers:
99
+ X-Gotify-Key: "your-app-token"
100
+ template: '{"title":"{{title}}","message":"{{body}}","priority":5}'
101
+
102
+ wechat_work:
103
+ enabled: false
104
+ webhook_url: "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx"
105
+
106
+ feishu:
107
+ enabled: false
108
+ webhook_url: "https://open.feishu.cn/open-apis/bot/v2/hook/xxx"
109
+
110
+ events:
111
+ - permission_required
112
+ - input_required
113
+ - run_failed
114
+
115
+ dedupe_seconds: 60
116
+ suppress_when_active: false
117
+ activity_timeout_ms: 30000
118
+ ```
119
+
120
+ ## 通知渠道
121
+
122
+ 每个渠道可以独立配置监听的事件,不填则继承全局 `events` 配置。
123
+
124
+ 可选事件值与全局 `events` 一致:
125
+
126
+ | 事件值 | 说明 |
127
+ |--------|------|
128
+ | `permission_required` | Agent 需要用户授权(执行命令、读写文件等) |
129
+ | `input_required` | Agent 等待用户输入 |
130
+ | `run_failed` | 任务执行失败 |
131
+ | `run_completed` | 任务执行完成(技术预留,暂未实现) |
132
+
133
+ ```yaml
134
+ # 自定义 Webhook 只推送权限请求和错误,不推送等待输入
135
+ custom_webhook:
136
+ enabled: true
137
+ events:
138
+ - permission_required
139
+ - run_failed
140
+ ```
141
+
142
+ ### 系统消息通知
143
+
144
+ 弹出操作系统原生通知横幅。
145
+
146
+ | 平台 | 实现 |
147
+ |------|------|
148
+ | macOS | `osascript` (display notification) |
149
+ | Linux | `notify-send`(需安装 `libnotify`) |
150
+ | Windows | PowerShell (New-BurntToastNotification) |
151
+
152
+ ### 屏幕跑马灯
153
+
154
+ 通知时在屏幕四边生成彩色高亮闪烁效果(跑马灯),视觉上更醒目:
155
+
156
+ ![跑马灯效果](doc/de.png)
157
+
158
+ - 独立渠道,可与系统通知分开启停、分开配置事件过滤
159
+ - 使用 Python + PyGObject(GTK 3) 创建透明覆盖窗口,不干扰当前操作
160
+ - 60fps 动画,彩色灯光沿四边循环运动(红→橙→黄→绿→蓝)
161
+ - 非阻塞执行,不影响通知发送速度
162
+ - 仅 Linux X11 环境,Ubuntu GNOME 桌面内置,无需额外安装
163
+
164
+ ```yaml
165
+ screen_flash:
166
+ enabled: true
167
+ # events: [run_failed] # 可选,不填继承全局
168
+ duration: 3.0 # 持续秒数(默认 3.0)
169
+ speed: 4.0 # 移动速度因子(默认 4.0)
170
+ intensity: 0.9 # 不透明度 0.0~1.0(默认 0.9)
171
+ ```
172
+
173
+ ### 自定义 Webhook
174
+
175
+ 通用 HTTP POST 发送器,支持任意 Webhook 服务。
176
+
177
+ **支持的服务举例:**
178
+
179
+ | 服务 | 文档 |
180
+ |------|------|
181
+ | Gotify | [gotify.net](https://gotify.net/) |
182
+ | Bark | [github.com/Finb/Bark](https://github.com/Finb/Bark) |
183
+ | PushDeer | [pushdeer.com](https://pushdeer.com/) |
184
+ | Slack Webhook | [api.slack.com/messaging/webhooks](https://api.slack.com/messaging/webhooks) |
185
+ | Discord Webhook | [support.discord.com](https://support.discord.com/hc/en-us/articles/228383668) |
186
+
187
+ **配置参数:**
188
+
189
+ | 参数 | 说明 |
190
+ |------|------|
191
+ | `url` | Webhook 地址 |
192
+ | `method` | 请求方法 `POST` / `GET`,默认 `POST` |
193
+ | `headers` | 自定义请求头(如 `X-Gotify-Key`) |
194
+ | `template` | 消息模板,支持占位符 `{{title}}` `{{body}}` `{{event}}` `{{agent}}` `{{sessionID}}` |
195
+
196
+ **Gotify 配置示例:**
197
+
198
+ ```yaml
199
+ custom_webhook:
200
+ enabled: true
201
+ url: "https://gotify.example.com/message"
202
+ method: "POST"
203
+ headers:
204
+ X-Gotify-Key: "your-app-token"
205
+ template: '{"title":"{{title}}","message":"{{body}}","priority":5}'
206
+ ```
207
+
208
+ ### 企业微信
209
+
210
+ 通过群机器人 Webhook 发送 Markdown 消息。
211
+
212
+ **配置步骤:**
213
+
214
+ 1. 在企业微信群中添加群机器人
215
+ 2. 复制 Webhook URL
216
+ 3. 填入配置文件
217
+
218
+ ```yaml
219
+ wechat_work:
220
+ enabled: true
221
+ webhook_url: "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx"
222
+ ```
223
+
224
+ 消息格式:Markdown,实际发送的请求体:
225
+
226
+ ```json
227
+ {
228
+ "msgtype": "markdown",
229
+ "markdown": {
230
+ "content": "**事件标题**\n\n事件详情...\n> 会话: sessionID"
231
+ }
232
+ }
233
+ ```
234
+
235
+ 消息包含:标题(加粗)、事件详情、会话 ID。
236
+
237
+ ### 飞书
238
+
239
+ 通过自定义机器人或流程触发器 Webhook 发送卡片消息。
240
+
241
+ **配置步骤:**
242
+
243
+ 1. 在飞书群中添加自定义机器人(或创建流程触发器)
244
+ 2. 复制 Webhook URL
245
+ 3. 填入配置文件
246
+
247
+ ```yaml
248
+ feishu:
249
+ enabled: true
250
+ webhook_url: "https://open.feishu.cn/open-apis/bot/v2/hook/xxx"
251
+ ```
252
+
253
+ 消息格式:卡片消息(interactive),实际发送的请求体:
254
+
255
+ ```json
256
+ {
257
+ "msg_type": "interactive",
258
+ "card": {
259
+ "header": {
260
+ "title": { "tag": "plain_text", "content": "事件标题" }
261
+ },
262
+ "elements": [
263
+ { "tag": "markdown", "content": "事件详情..." },
264
+ { "tag": "hr" },
265
+ { "tag": "note", "elements": [{ "tag": "plain_text", "content": "会话: sessionID" }] }
266
+ ]
267
+ }
268
+ }
269
+ ```
270
+
271
+ 消息包含:标题头、正文(Markdown)、分割线、脚注(会话 ID)。
272
+
273
+ ## 事件映射
274
+
275
+ | 通知事件 | 触发场景 | 对应 opencode 事件 |
276
+ |----------|---------|-------------------|
277
+ | `permission_required` | Agent 需要授权(执行命令、读写文件等) | `permission.asked` / `question.asked` |
278
+ | `input_required` | Agent 等待用户输入 | `session.idle` / `session.status` (idle) |
279
+ | `run_failed` | 任务执行失败 | `session.error` |
280
+ | `run_completed` | 任务完成(预留,暂未实现) | 待组合判断 |
281
+
282
+ ## 配置参考
283
+
284
+ ### 配置文件位置
285
+
286
+ 默认路径:`~/.config/opencode/opencode-notify.yaml`
287
+
288
+ 可通过环境变量 `OPENCODE_NOTIFY_CONFIG` 自定义路径。
289
+
290
+ ### 配置优先级
291
+
292
+ ```
293
+ YAML 文件 > plugin options (opencode.json) > 环境变量 > 默认值
294
+ ```
295
+
296
+ ### 全部配置项
297
+
298
+ ```yaml
299
+ channels:
300
+ system_message:
301
+ enabled: true # 系统通知开关
302
+ events: [] # 可选,渠道级事件过滤(不填继承全局)
303
+ # 可选值: permission_required | input_required | run_completed | run_failed
304
+ screen_flash: # 屏幕跑马灯(仅 Linux X11)
305
+ enabled: true # 开启(默认 false)
306
+ events: [] # 可选,渠道级事件过滤(不填继承全局)
307
+ # 可选值: permission_required | input_required | run_completed | run_failed
308
+ duration: 3.5 # 持续秒数
309
+ speed: 5.0 # 移动速度因子
310
+ intensity: 0.85 # 不透明度 0.0~1.0
311
+
312
+ custom_webhook:
313
+ enabled: false # 自定义 Webhook 开关
314
+ events: [] # 可选,渠道级事件过滤
315
+ # 可选值: permission_required | input_required | run_completed | run_failed
316
+ url: "" # Webhook 地址
317
+ method: "POST" # 请求方法 POST | GET
318
+ headers: {} # 自定义请求头
319
+ template: "" # 消息模板
320
+
321
+ wechat_work:
322
+ enabled: false # 企业微信开关
323
+ events: [] # 可选,渠道级事件过滤
324
+ # 可选值: permission_required | input_required | run_completed | run_failed
325
+ webhook_url: "" # 群机器人 Webhook URL
326
+ # 消息格式: Markdown (msgtype=markdown, markdown.content)
327
+
328
+ feishu:
329
+ enabled: false # 飞书开关
330
+ events: [] # 可选,渠道级事件过滤
331
+ # 可选值: permission_required | input_required | run_completed | run_failed
332
+ webhook_url: "" # 机器人/流程触发器 Webhook URL
333
+ # 消息格式: 卡片消息 (msg_type=interactive, card)
334
+
335
+ events: # 订阅的事件列表
336
+ # 可选值: permission_required | input_required | run_completed | run_failed
337
+
338
+ dedupe_seconds: 60 # 去重时间窗口(秒)
339
+ suppress_when_active: false # 用户活跃时是否跳过通知
340
+ activity_timeout_ms: 30000 # 活跃超时判定(毫秒)
341
+ debug_log: false # 写入 ~/.opencode-notify/plugin.log 调试日志(默认 false)
342
+ ```
343
+
344
+ ### 环境变量
345
+
346
+ | 变量 | 用途 |
347
+ |------|------|
348
+ | `OPENCODE_NOTIFY_CUSTOM_WEBHOOK_URL` | 覆盖 `custom_webhook.url` |
349
+ | `OPENCODE_NOTIFY_WECHAT_WEBHOOK` | 覆盖 `wechat_work.webhook_url` |
350
+ | `OPENCODE_NOTIFY_FEISHU_WEBHOOK` | 覆盖 `feishu.webhook_url` |
351
+ | `OPENCODE_NOTIFY_CONFIG` | 自定义 YAML 配置文件路径 |
352
+
353
+ ### 活跃抑制
354
+
355
+ 当用户正在操作 TUI(发消息、翻页、回应权限等),说明人在屏幕前,可跳过通知。
356
+ 检测事件:`message.updated` / `permission.replied` / `question.replied` / `command.executed` / `tui.command.execute`
357
+
358
+ ```yaml
359
+ suppress_when_active: true # 开启抑制
360
+ activity_timeout_ms: 30000 # 30 秒无操作视为离开
361
+ ```
362
+
363
+ ## 日志与故障排查
364
+
365
+ 插件日志位于 `~/.opencode-notify/plugin.log`,默认**关闭**,需在配置中开启:
366
+
367
+ ```yaml
368
+ debug_log: true
369
+ ```
370
+
371
+ 开启后日志包含:
372
+
373
+ - 插件加载信息(配置、已启用渠道)
374
+ - 收到的事件(`[event] type=...`)
375
+ - 匹配到的通知
376
+ - 发送结果
377
+
378
+ ```bash
379
+ # 实时查看日志
380
+ tail -f ~/.opencode-notify/plugin.log
381
+
382
+ # 查看最近的插件加载信息
383
+ grep "插件已加载" ~/.opencode-notify/plugin.log
384
+
385
+ # 查看事件流
386
+ grep "\[event\]" ~/.opencode-notify/plugin.log
387
+ ```
388
+
389
+ ### 常见问题
390
+
391
+ **Q: 插件未加载?**
392
+ 确认 `opencode.json` 中 `plugin` 列表的路径正确,指向 `index.ts` 文件。
393
+
394
+ **Q: 通知没有弹出?**
395
+ 1. 检查日志中是否出现 `[event] type=` 行,确认事件是否被监听到
396
+ 2. 检查渠道是否已 `enabled: true`
397
+ 3. 检查 Webhook URL 是否正确
398
+ 4. 查看 `~/.opencode-notify/plugin.log` 中是否有错误信息
399
+
400
+ **Q: 企业微信/飞书通知失败?**
401
+ 确认 Webhook URL 有效,网络可达。可通过 `curl` 直接测试:
402
+
403
+ ```bash
404
+ curl -X POST <webhook_url> -H "Content-Type: application/json" -d '{"msgtype":"markdown","markdown":{"content":"**测试**"}}'
405
+ ```
406
+
407
+ ## 项目结构
408
+
409
+ ```
410
+ opencode-notify/
411
+ ├── index.ts # 插件入口
412
+ ├── cli.ts # 诊断工具
413
+ ├── config.ts # 配置解析(YAML + options + env)
414
+ ├── events.ts # 事件路由
415
+ ├── dispatcher.ts # 去重分发
416
+ ├── store.ts # 状态存储
417
+ ├── message.ts # 消息模型
418
+ ├── scripts/
419
+ │ └── marquee.py # 屏幕跑马灯效果(Python+GTK)
420
+ ├── senders/
421
+ │ ├── types.ts # Sender 接口
422
+ │ ├── system.ts # 系统通知
423
+ │ ├── screen-flash.ts # 屏幕跑马灯
424
+ │ ├── custom-webhook.ts # 自定义 Webhook
425
+ │ ├── wechat-work.ts # 企业微信
426
+ │ └── feishu.ts # 飞书
427
+ ├── findings.md # 研究记录
428
+ ├── plan.md # 需求与实现计划
429
+ ├── task_plan.md # 任务跟踪
430
+ ├── progress.md # 进度日志
431
+ ├── package.json
432
+ └── tsconfig.json
433
+ ```
434
+