@freely01/opencode-notify 0.1.1 → 0.3.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/README.md +126 -38
- package/cli.ts +27 -15
- package/config.ts +298 -37
- package/delayed-dispatcher.ts +135 -0
- package/dispatcher.ts +11 -6
- package/events.ts +35 -43
- package/index.ts +115 -62
- package/log.ts +90 -0
- package/message.ts +39 -2
- package/package.json +1 -1
- package/senders/screen-flash/index.ts +32 -0
- package/senders/screen-flash/linux.ts +29 -0
- package/senders/screen-flash/win32.ts +129 -0
- package/senders/system/darwin.ts +17 -0
- package/senders/system/index.ts +67 -0
- package/senders/system/linux.ts +16 -0
- package/senders/system/win32.ts +51 -0
- package/session-tracker.ts +133 -0
- package/store.ts +5 -4
- package/terminator-detect.ts +164 -0
- package/senders/screen-flash.ts +0 -42
- package/senders/system.ts +0 -88
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ opencode 通知插件 — 监听会话中的关键事件,通过多渠道推送
|
|
|
13
13
|
> - Linux 系统通知需 `libnotify` 包(桌面发行版通常预装)
|
|
14
14
|
> - 事件映射基于 @opencode-ai/plugin@1.15.12 的行为,后续版本升级可能影响兼容性
|
|
15
15
|
> - `run_completed` 事件暂未实现(opencode 无直接完成事件)
|
|
16
|
-
> -
|
|
16
|
+
> - 屏幕跑马灯效果:Linux X11(Python + PyGObject)/ Windows(PowerShell + WinForms)四边彩色流动
|
|
17
17
|
> - 仅在 Ubuntu 24.04 (X11) 环境下测试并使用,其它平台未验证
|
|
18
18
|
>
|
|
19
19
|
> 如有问题欢迎提 Issue,但不保证及时响应和修复。
|
|
@@ -24,10 +24,12 @@ opencode 通知插件 — 监听会话中的关键事件,通过多渠道推送
|
|
|
24
24
|
- 多渠道通知:系统通知、企业微信、飞书、自定义 Webhook(Gotify / Bark / PushDeer 等)
|
|
25
25
|
- YAML 配置文件,每项参数均有详细注释
|
|
26
26
|
- 去重机制:同一事件在时间窗口内不重复发送
|
|
27
|
-
-
|
|
27
|
+
- 会话感知抑制:活跃会话按事件类型智能过滤,不遗漏 `run_failed` 等重要通知
|
|
28
28
|
- 零外部运行时依赖(仅 js-yaml 用于配置解析)
|
|
29
|
-
- **屏幕跑马灯**:通知时屏幕四边高亮闪烁(Linux X11,Python + GTK
|
|
29
|
+
- **屏幕跑马灯**:通知时屏幕四边高亮闪烁(Linux X11,Python + GTK 内置;Windows 实验性,PowerShell + WinForms)
|
|
30
30
|
- **渠道级事件过滤**:每个渠道可独立配置监听哪些事件,灵活分流
|
|
31
|
+
- **远程延迟推送**:正常通知发出后,指定渠道额外延迟推送以防遗漏
|
|
32
|
+
- **Terminator 子屏检测**:自动检测子屏最大化场景,被遮挡的会话强制通知
|
|
31
33
|
|
|
32
34
|
## 平台支持
|
|
33
35
|
|
|
@@ -37,13 +39,13 @@ opencode 通知插件 — 监听会话中的关键事件,通过多渠道推送
|
|
|
37
39
|
| 自定义 Webhook / 企业微信 / 飞书 | ✅ | ✅ | ✅ |
|
|
38
40
|
| 诊断 CLI (`bun cli.ts`) | ✅ | ✅ | ✅ |
|
|
39
41
|
| **系统消息通知** | ✅ `osascript` 内置 | ⚠️ 需 `libnotify` 包 | ⚠️ 需 BurntToast 模块 |
|
|
40
|
-
| **屏幕跑马灯** | ❌ | ✅ Python+GTK 内置 |
|
|
42
|
+
| **屏幕跑马灯** | ❌ | ✅ Python+GTK 内置 | ✅ PowerShell+WinForms |
|
|
41
43
|
|
|
42
44
|
**说明:**
|
|
43
45
|
- **macOS**: 系统通知使用 `osascript`,系统内置,开箱即用
|
|
44
46
|
- **Linux**: 系统通知使用 `notify-send`,来自 `libnotify`。桌面发行版通常预装,如缺失可 `apt install libnotify-bin` / `yum install libnotify`
|
|
45
47
|
- **Windows**: 系统通知使用 PowerShell `New-BurntToastNotification`,需额外安装 [BurntToast](https://github.com/Windos/BurntToast) 模块。Webhook 渠道不受影响
|
|
46
|
-
- **屏幕跑马灯**:
|
|
48
|
+
- **屏幕跑马灯**: Linux X11 使用 Python + PyGObject(GTK 3) 创建透明覆盖窗口,60fps 彩色四边跑马灯动画;Windows 使用 PowerShell + .NET WinForms 创建屏幕四边彩色闪烁边框(实验性)。中间完全透明可点击穿透,不影响操作。macOS 暂不支持
|
|
47
49
|
- 非系统通知模块(Webhook 推送、CLI 诊断)均为纯 HTTP/Node API,全平台一致
|
|
48
50
|
|
|
49
51
|
> **已测试渠道:** 系统通知、企业微信、自定义 Webhook(Gotify)。飞书等其他渠道理论可用,暂未做验证。
|
|
@@ -156,10 +158,9 @@ custom_webhook:
|
|
|
156
158
|

|
|
157
159
|
|
|
158
160
|
- 独立渠道,可与系统通知分开启停、分开配置事件过滤
|
|
159
|
-
- 使用 Python + PyGObject(GTK 3)
|
|
160
|
-
-
|
|
161
|
+
- Linux X11: 使用 Python + PyGObject(GTK 3) 创建透明覆盖窗口,60fps 彩色灯光沿四边循环运动
|
|
162
|
+
- Windows: 使用 PowerShell + .NET WinForms 创建屏幕四边彩色闪烁边框(8px 宽),中间完全透明可点击穿透,不阻挡任何操作
|
|
161
163
|
- 非阻塞执行,不影响通知发送速度
|
|
162
|
-
- 仅 Linux X11 环境,Ubuntu GNOME 桌面内置,无需额外安装
|
|
163
164
|
|
|
164
165
|
```yaml
|
|
165
166
|
screen_flash:
|
|
@@ -270,6 +271,41 @@ feishu:
|
|
|
270
271
|
|
|
271
272
|
消息包含:标题头、正文(Markdown)、分割线、脚注(会话 ID)。
|
|
272
273
|
|
|
274
|
+
### 远程延迟推送
|
|
275
|
+
|
|
276
|
+
正常通知发出后,如果用户长时间未操作(未回到 opencode TUI),针对指定渠道额外再推送一次。
|
|
277
|
+
用户在延迟期间回到 TUI 操作 → 自动取消该会话所有待发延迟通知。
|
|
278
|
+
|
|
279
|
+
**适用场景:** 用户离开电脑后,系统通知可能一闪而过没看到;延迟推送在用户仍未回来时再次尝试发出。
|
|
280
|
+
|
|
281
|
+
```yaml
|
|
282
|
+
remote_delay_channels: # 哪些渠道需要额外延迟推送(空=不启用)
|
|
283
|
+
- system_message
|
|
284
|
+
- wechat_work
|
|
285
|
+
- feishu
|
|
286
|
+
- custom_webhook
|
|
287
|
+
remote_delay_seconds: 60 # 延迟秒数(默认 60)
|
|
288
|
+
remote_delay_max_count: 3 # 最多重复次数(默认 3)
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
**注意:**
|
|
292
|
+
- `remote_delay_channels` 仅影响**额外延迟推送**,不影响正常通知(正常通知该发就发)
|
|
293
|
+
- 延迟推送使用渠道自身的事件过滤规则,只有渠道订阅的事件才会延迟推送
|
|
294
|
+
- 用户在该会话中进行任何操作(输入消息、回应权限、执行命令等)都会取消该会话所有待发延迟
|
|
295
|
+
- 达到 `remote_delay_max_count` 次后停止推送
|
|
296
|
+
|
|
297
|
+
### Terminator 子屏遮挡检测(自动)
|
|
298
|
+
|
|
299
|
+
当用户在 **Terminator** 中最大化某个子屏幕时(`Ctrl+Shift+X`),
|
|
300
|
+
其他子屏幕中的 opencode 会话虽活跃但被遮挡。插件自动检测该场景,
|
|
301
|
+
被遮挡的会话即使活跃也会强制发送通知。
|
|
302
|
+
|
|
303
|
+
**检测原理**:`$TERMINATOR_UUID` + `$TERMINATOR_DBUS_NAME` + `$TERMINATOR_DBUS_PATH`
|
|
304
|
+
环境变量确认在 Terminator 中 → DBus 查询焦点终端 UUID → 与本屏对比
|
|
305
|
+
→ 不一致则强制通知,无需额外配置。
|
|
306
|
+
|
|
307
|
+
**外部依赖**(任一即可):`busctl`(systemd 内置)| `python3-dbus` | `gdbus` | `xdotool`
|
|
308
|
+
|
|
273
309
|
## 事件映射
|
|
274
310
|
|
|
275
311
|
| 通知事件 | 触发场景 | 对应 opencode 事件 |
|
|
@@ -285,12 +321,10 @@ feishu:
|
|
|
285
321
|
|
|
286
322
|
默认路径:`~/.config/opencode/opencode-notify.yaml`
|
|
287
323
|
|
|
288
|
-
可通过环境变量 `OPENCODE_NOTIFY_CONFIG` 自定义路径。
|
|
289
|
-
|
|
290
324
|
### 配置优先级
|
|
291
325
|
|
|
292
326
|
```
|
|
293
|
-
YAML 文件 > plugin options (opencode.json) >
|
|
327
|
+
YAML 文件 > plugin options (opencode.json) > 默认值
|
|
294
328
|
```
|
|
295
329
|
|
|
296
330
|
### 全部配置项
|
|
@@ -336,44 +370,81 @@ events: # 订阅的事件列表
|
|
|
336
370
|
# 可选值: permission_required | input_required | run_completed | run_failed
|
|
337
371
|
|
|
338
372
|
dedupe_seconds: 60 # 去重时间窗口(秒)
|
|
339
|
-
suppress_when_active:
|
|
340
|
-
activity_timeout_ms:
|
|
341
|
-
|
|
373
|
+
suppress_when_active: true # 会话感知抑制开关(按 suppress_events 列表过滤)
|
|
374
|
+
activity_timeout_ms: 15000 # 会话活跃超时(毫秒),超过此时间无操作视为离开
|
|
375
|
+
suppress_events_when_active: # 活跃时抑制哪些事件(不填=默认列表)
|
|
376
|
+
- permission_required
|
|
377
|
+
- input_required
|
|
378
|
+
# run_failed / run_completed 不在列表中 → 始终通知
|
|
379
|
+
session_stale_timeout_ms: 600000 # 超时会话自动淘汰(毫秒),默认 10 分钟
|
|
380
|
+
remote_delay_channels: [] # 远程延迟推送渠道列表(空=不启用)
|
|
381
|
+
# 可选值: system_message, screen_flash, wechat_work, feishu, custom_webhook
|
|
382
|
+
remote_delay_seconds: 60 # 远程延迟秒数(默认 60)
|
|
383
|
+
remote_delay_max_count: 3 # 远程延迟最多重复次数(默认 3)
|
|
384
|
+
log: # 日志配置
|
|
385
|
+
level: info # 等级: error | warn | info | debug(默认 info)
|
|
386
|
+
# error - 仅记录错误
|
|
387
|
+
# warn - 错误 + 警告
|
|
388
|
+
# info - 错误 + 警告 + 常规信息(推荐)
|
|
389
|
+
# debug - 全部日志(排查时使用)
|
|
390
|
+
# file: "~/.opencode-notify/plugin.log" # 日志文件路径(可选,默认同上)
|
|
342
391
|
```
|
|
343
392
|
|
|
344
|
-
###
|
|
393
|
+
### 活跃抑制
|
|
394
|
+
|
|
395
|
+
当用户正在 opencode TUI 中操作(输入消息、回应权限等),通知可能冗余(屏上已可见)。
|
|
396
|
+
插件通过**会话感知抑制**解决:追踪每个会话的用户操作时间戳,活跃会话按事件类型选择性过滤。
|
|
345
397
|
|
|
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 配置文件路径 |
|
|
398
|
+
**检测的用户操作事件:**
|
|
399
|
+
`message.updated` / `permission.replied` / `question.replied` / `command.executed` / `tui.command.execute`
|
|
352
400
|
|
|
353
|
-
|
|
401
|
+
**抑制规则:**
|
|
354
402
|
|
|
355
|
-
|
|
356
|
-
|
|
403
|
+
| 通知事件 | 活跃时默认行为 | 理由 |
|
|
404
|
+
|---------|:------------:|------|
|
|
405
|
+
| `permission_required` | ✅ 抑制 | 权限弹窗就在屏幕上 |
|
|
406
|
+
| `input_required` | ✅ 抑制 | TUI 明确在等输入 |
|
|
407
|
+
| `run_failed` | ❌ 不抑制 | 异步结果,人可能走开 |
|
|
408
|
+
| `run_completed` | ❌ 不抑制 | 同上 |
|
|
409
|
+
|
|
410
|
+
**配置示例:**
|
|
357
411
|
|
|
358
412
|
```yaml
|
|
359
|
-
suppress_when_active: true
|
|
360
|
-
activity_timeout_ms:
|
|
413
|
+
suppress_when_active: true # 开启会话感知抑制
|
|
414
|
+
activity_timeout_ms: 15000 # 15 秒无操作视为不活跃
|
|
415
|
+
suppress_events_when_active: # 活跃时抑制哪些事件
|
|
416
|
+
- permission_required
|
|
417
|
+
- input_required
|
|
418
|
+
session_stale_timeout_ms: 600000 # 10 分钟无活动自动淘汰会话(防内存泄漏)
|
|
361
419
|
```
|
|
362
420
|
|
|
363
421
|
## 日志与故障排查
|
|
364
422
|
|
|
365
|
-
插件日志位于 `~/.opencode-notify/plugin.log
|
|
423
|
+
插件日志位于 `~/.opencode-notify/plugin.log`(可通过 `log.file` 配置自定义)。
|
|
424
|
+
|
|
425
|
+
日志等级由 `log.level` 控制:
|
|
426
|
+
|
|
427
|
+
| 等级 | 包含内容 | 建议用途 |
|
|
428
|
+
|------|---------|---------|
|
|
429
|
+
| `error` | 仅错误 | 生产环境,只关心失败 |
|
|
430
|
+
| `warn` | 错误 + 警告 | 生产环境,关注潜在问题 |
|
|
431
|
+
| `info` | 错误 + 警告 + 常规信息 | 日常运行(默认) |
|
|
432
|
+
| `debug` | 全部日志(含详细事件流) | 排查问题 |
|
|
366
433
|
|
|
367
434
|
```yaml
|
|
368
|
-
|
|
435
|
+
log:
|
|
436
|
+
level: info # 推荐:日常使用记录所有关键信息
|
|
437
|
+
# level: debug # 排查问题时改为 debug
|
|
438
|
+
# file: "~/.opencode-notify/plugin.log" # 可选自定义路径
|
|
369
439
|
```
|
|
370
440
|
|
|
371
|
-
|
|
441
|
+
日志包含:
|
|
372
442
|
|
|
373
|
-
-
|
|
374
|
-
-
|
|
375
|
-
-
|
|
376
|
-
-
|
|
443
|
+
- 插件加载信息(配置、已启用渠道、日志等级)
|
|
444
|
+
- 渠道发送失败 / 成功
|
|
445
|
+
- 会话活跃跳过通知
|
|
446
|
+
- 远程延迟推送调度 / 取消 / 推送
|
|
447
|
+
- 去重命中、状态存储异常等诊断信息
|
|
377
448
|
|
|
378
449
|
```bash
|
|
379
450
|
# 实时查看日志
|
|
@@ -382,8 +453,11 @@ tail -f ~/.opencode-notify/plugin.log
|
|
|
382
453
|
# 查看最近的插件加载信息
|
|
383
454
|
grep "插件已加载" ~/.opencode-notify/plugin.log
|
|
384
455
|
|
|
385
|
-
#
|
|
386
|
-
grep "\[
|
|
456
|
+
# 只看错误
|
|
457
|
+
grep "\[ERROR\]" ~/.opencode-notify/plugin.log
|
|
458
|
+
|
|
459
|
+
# 只看警告
|
|
460
|
+
grep "\[WARN\]" ~/.opencode-notify/plugin.log
|
|
387
461
|
```
|
|
388
462
|
|
|
389
463
|
### 常见问题
|
|
@@ -410,17 +484,31 @@ curl -X POST <webhook_url> -H "Content-Type: application/json" -d '{"msgtype":"m
|
|
|
410
484
|
opencode-notify/
|
|
411
485
|
├── index.ts # 插件入口
|
|
412
486
|
├── cli.ts # 诊断工具
|
|
413
|
-
├── config.ts # 配置解析(YAML + options
|
|
487
|
+
├── config.ts # 配置解析(YAML + plugin options)
|
|
414
488
|
├── events.ts # 事件路由
|
|
489
|
+
├── log.ts # 共享日志模块
|
|
490
|
+
├── session-tracker.ts # 会话感知抑制
|
|
491
|
+
├── terminator-detect.ts # Terminator 子屏最大化检测
|
|
492
|
+
├── delayed-dispatcher.ts # 远程延迟推送调度器
|
|
415
493
|
├── dispatcher.ts # 去重分发
|
|
416
494
|
├── store.ts # 状态存储
|
|
417
495
|
├── message.ts # 消息模型
|
|
496
|
+
├── doc/
|
|
497
|
+
│ ├── de.png # 跑马灯效果截图
|
|
498
|
+
│ └── features.md # 功能说明(含 Terminator 友好体验说明)
|
|
418
499
|
├── scripts/
|
|
419
500
|
│ └── marquee.py # 屏幕跑马灯效果(Python+GTK)
|
|
420
501
|
├── senders/
|
|
421
502
|
│ ├── types.ts # Sender 接口
|
|
422
|
-
│ ├── system
|
|
423
|
-
│ ├──
|
|
503
|
+
│ ├── system/ # 系统通知(平台分包)
|
|
504
|
+
│ │ ├── index.ts # 注册表 + 自动选择平台
|
|
505
|
+
│ │ ├── darwin.ts # macOS (osascript)
|
|
506
|
+
│ │ ├── linux.ts # Linux (notify-send)
|
|
507
|
+
│ │ └── win32.ts # Windows (PowerShell)
|
|
508
|
+
│ ├── screen-flash/ # 屏幕跑马灯(Linux + Windows)
|
|
509
|
+
│ │ ├── index.ts # 入口 + 平台路由
|
|
510
|
+
│ │ ├── linux.ts # Linux 实现 (Python+GTK)
|
|
511
|
+
│ │ └── win32.ts # Windows 实现 (PowerShell+WinForms)
|
|
424
512
|
│ ├── custom-webhook.ts # 自定义 Webhook
|
|
425
513
|
│ ├── wechat-work.ts # 企业微信
|
|
426
514
|
│ └── feishu.ts # 飞书
|
package/cli.ts
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
import { loadYamlConfig, resolveConfig, mergeConfig } from "./config.js"
|
|
15
15
|
import type { PluginConfig, ChannelsConfig } from "./config.js"
|
|
16
16
|
import type { Message } from "./message.js"
|
|
17
|
-
import { SystemSender } from "./senders/system.js"
|
|
17
|
+
import { SystemSender } from "./senders/system/index.js"
|
|
18
18
|
import { CustomWebhookSender } from "./senders/custom-webhook.js"
|
|
19
19
|
import { WechatWorkSender } from "./senders/wechat-work.js"
|
|
20
20
|
import { FeishuSender } from "./senders/feishu.js"
|
|
@@ -25,8 +25,14 @@ import { join } from "node:path"
|
|
|
25
25
|
// ─── 常量 ───────────────────────────────────────────────────────────────────
|
|
26
26
|
|
|
27
27
|
const PKG = JSON.parse(readFileSync(join(import.meta.dirname, "package.json"), "utf-8"))
|
|
28
|
-
const
|
|
29
|
-
const YAML_PATH =
|
|
28
|
+
const DEFAULT_LOG_FILE = join(homedir(), ".opencode-notify", "plugin.log")
|
|
29
|
+
const YAML_PATH = join(homedir(), ".config", "opencode", "opencode-notify.yaml")
|
|
30
|
+
|
|
31
|
+
/** 读取有效日志文件路径(优先从配置中读取) */
|
|
32
|
+
function getLogFile(): string {
|
|
33
|
+
const yamlCfg = loadYamlConfig()
|
|
34
|
+
return yamlCfg?.log?.file ?? DEFAULT_LOG_FILE
|
|
35
|
+
}
|
|
30
36
|
|
|
31
37
|
const SAMPLE_MSG: Message = {
|
|
32
38
|
agent: "opencode",
|
|
@@ -72,7 +78,7 @@ function cmdCheck() {
|
|
|
72
78
|
// 1. 检查配置文件是否存在
|
|
73
79
|
if (!existsSync(YAML_PATH)) {
|
|
74
80
|
console.log(`\n❌ 配置文件不存在: ${YAML_PATH}`)
|
|
75
|
-
console.log("
|
|
81
|
+
console.log(" 请创建 ~/.config/opencode/opencode-notify.yaml 配置文件")
|
|
76
82
|
process.exit(1)
|
|
77
83
|
}
|
|
78
84
|
console.log(`\n✅ 配置文件: ${YAML_PATH}`)
|
|
@@ -145,6 +151,9 @@ function cmdCheck() {
|
|
|
145
151
|
// 6. 检查活跃抑制
|
|
146
152
|
console.log(`\n🔇 活跃抑制: ${cfg.suppress_when_active ? "开启" : "关闭"} (超时 ${cfg.activity_timeout_ms}ms)`)
|
|
147
153
|
|
|
154
|
+
// 6.5 日志配置
|
|
155
|
+
console.log(`\n📝 日志: 等级=${cfg.log?.level ?? "info"} 文件=${getLogFile()}`)
|
|
156
|
+
|
|
148
157
|
// 7. 检查去重
|
|
149
158
|
console.log(`\n🔄 去重窗口: ${cfg.dedupe_seconds} 秒`)
|
|
150
159
|
|
|
@@ -219,17 +228,18 @@ async function cmdTest(channel?: string) {
|
|
|
219
228
|
// ─── 命令: log ───────────────────────────────────────────────────────────────
|
|
220
229
|
|
|
221
230
|
function cmdLog(lines: number) {
|
|
222
|
-
|
|
223
|
-
|
|
231
|
+
const logFile = getLogFile()
|
|
232
|
+
if (!existsSync(logFile)) {
|
|
233
|
+
console.log(`日志文件不存在: ${logFile}`)
|
|
224
234
|
console.log("插件尚未运行过,或日志已被清理。")
|
|
225
235
|
process.exit(1)
|
|
226
236
|
}
|
|
227
237
|
|
|
228
|
-
const stat = statSync(
|
|
229
|
-
const all = readFileSync(
|
|
238
|
+
const stat = statSync(logFile)
|
|
239
|
+
const all = readFileSync(logFile, "utf-8").trimEnd()
|
|
230
240
|
const entries = all.split("\n")
|
|
231
241
|
|
|
232
|
-
console.log(`📄 ${
|
|
242
|
+
console.log(`📄 ${logFile} (${(stat.size / 1024).toFixed(1)} KB, ${entries.length} 行)\n`)
|
|
233
243
|
|
|
234
244
|
const tail = entries.slice(-lines)
|
|
235
245
|
for (const line of tail) {
|
|
@@ -270,16 +280,17 @@ function cmdInfo() {
|
|
|
270
280
|
}
|
|
271
281
|
|
|
272
282
|
// 日志文件
|
|
283
|
+
const logFile = getLogFile()
|
|
273
284
|
console.log(`\n 📝 日志文件:`)
|
|
274
|
-
if (existsSync(
|
|
275
|
-
const stat = statSync(
|
|
276
|
-
const lines = readFileSync(
|
|
277
|
-
const recent = readFileSync(
|
|
278
|
-
console.log(` 路径: ${
|
|
285
|
+
if (existsSync(logFile)) {
|
|
286
|
+
const stat = statSync(logFile)
|
|
287
|
+
const lines = readFileSync(logFile, "utf-8").split("\n").length
|
|
288
|
+
const recent = readFileSync(logFile, "utf-8").trimEnd().split("\n").slice(-1)[0] ?? ""
|
|
289
|
+
console.log(` 路径: ${logFile}`)
|
|
279
290
|
console.log(` 大小: ${(stat.size / 1024).toFixed(1)} KB, ${lines} 行`)
|
|
280
291
|
console.log(` 最新: ${recent}`)
|
|
281
292
|
} else {
|
|
282
|
-
console.log(` 路径: ${
|
|
293
|
+
console.log(` 路径: ${logFile} (暂无日志)`)
|
|
283
294
|
}
|
|
284
295
|
|
|
285
296
|
// 配置详情
|
|
@@ -308,6 +319,7 @@ function cmdInfo() {
|
|
|
308
319
|
|
|
309
320
|
console.log(`\n 📋 订阅事件: ${cfg.events?.join(", ") ?? "(无)"}`)
|
|
310
321
|
console.log(` 🔇 活跃抑制: ${cfg.suppress_when_active ? "开启" : "关闭"}`)
|
|
322
|
+
console.log(` 📝 日志等级: ${cfg.log?.level ?? "info"}`)
|
|
311
323
|
console.log(` ⏱ 去重窗口: ${cfg.dedupe_seconds} 秒`)
|
|
312
324
|
} else {
|
|
313
325
|
console.log(`\n ⚠️ 未加载到配置`)
|