@yoooclaw/phone-notifications 1.4.16

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 ADDED
@@ -0,0 +1,344 @@
1
+ # @openclaw/phone-notifications
2
+
3
+ OpenClaw 手机通知同步插件:接收手机通知并写入本地 JSON 文件系统,供 Agent 查询和消费。
4
+
5
+ ## 工作方式
6
+
7
+ 插件支持两种接入模式:
8
+
9
+ 1. Gateway Native(默认)
10
+ - 手机端通过 gateway 已有连接调用 `notifications.push`
11
+ - 插件通过 `registerGatewayMethod` 接收 `params.items`
12
+
13
+ 2. HTTP 备选模式
14
+ - 开启 `httpEnabled=true` 后,注册 `POST /notifications`
15
+ - 通过 `Authorization: Bearer <apiKey>` 鉴权
16
+
17
+ ## 存储设计
18
+
19
+ 通知按以下目录结构写入(JSON):
20
+
21
+ ```text
22
+ <workspace>/notifications/
23
+ ├── 2026-03-02.json
24
+ ├── 2026-03-03.json
25
+ └── 2026-03-04.json
26
+ ```
27
+
28
+ 补充规则:
29
+ - `workspaceDir` 可用时,根目录是 `<workspace>/notifications`
30
+ - `workspaceDir` 不可用或不可写时,回退到 `<stateDir>/plugins/phone-notifications/notifications`
31
+ - 通知写入 `YYYY-MM-DD.json` 的 JSON 数组(append-only)
32
+ - 通知条目字段为 `appName`、`title`、`content`、`timestamp`(ISO 8601 含时区)
33
+ - 同一天内按 `notification-id` 去重(使用内部索引文件)
34
+ - `retentionDays`(默认 30)会清理过期日期文件
35
+
36
+ ## 前置要求
37
+
38
+ - **Node.js >= 22.12.0**(含 npm)
39
+ - **curl**(用于下载安装包)
40
+ - **tar**
41
+
42
+ ## 安装
43
+
44
+ 推荐使用一键安装脚本,脚本会自动从 CDN 获取最新版本、下载、解压、注册插件并写入配置。
45
+
46
+ ### 最简安装(自动获取最新版本)
47
+
48
+ ```bash
49
+ curl -fsSL https://cdn.yoootek.com/openclaw-plugin/install.sh | bash
50
+ ```
51
+
52
+ ### 指定版本安装
53
+
54
+ ```bash
55
+ curl -fsSL https://cdn.yoootek.com/openclaw-plugin/install.sh | bash -s -- --version 1.2.3
56
+ ```
57
+
58
+ ### 带 Token 安装
59
+
60
+ 安装时同时写入灯控鉴权 Token(写入 `~/.openclaw/credentials.json`):
61
+
62
+ ```bash
63
+ curl -fsSL https://cdn.yoootek.com/openclaw-plugin/install.sh | bash -s -- --token eyJhbGciOi...
64
+ ```
65
+
66
+ ### 使用本地包安装
67
+
68
+ 如果已有 `.tgz` 文件,可跳过下载直接安装:
69
+
70
+ ```bash
71
+ bash install.sh --tgz-url ./yoooclaw-phone-notifications-1.2.3.tgz
72
+ ```
73
+
74
+ ### 全部安装选项
75
+
76
+ | 选项 | 说明 | 默认值 |
77
+ |---|---|---|
78
+ | `--version <ver>` | 指定版本号 | 自动获取最新版本 |
79
+ | `--tgz-url <url\|path>` | 直接指定插件包地址(跳过版本检测) | - |
80
+ | `--target-dir <path>` | 安装目录 | `~/.openclaw/extensions/phone-notifications` |
81
+ | `--token <token>` | 灯控鉴权 Token | - |
82
+ | `--retention-days <n>` | 通知数据保留天数 | 30 |
83
+
84
+ ### 安装脚本做了什么
85
+
86
+ 1. 从 CDN 下载最新版本的插件 tgz 包(或使用你指定的版本/地址)
87
+ 2. 解压并验证包完整性(检查 `package.json`、入口文件可加载)
88
+ 3. 备份旧版本(如有),原子替换到 `~/.openclaw/extensions/phone-notifications`
89
+ 4. 写入 `~/.openclaw/openclaw.json` 配置:
90
+ - `plugins.allow` — 将插件加入白名单
91
+ - `plugins.entries` — 启用插件,合并用户配置
92
+ - `plugins.installs` — 记录安装来源和版本
93
+ - 清理该插件旧的 `plugins.load.paths` / 旧安装记录,避免继续命中之前通过 `openclaw plugins install` 或 `--link` 保留的副本
94
+ 5. 如传入 `--token`,写入 `~/.openclaw/credentials.json`
95
+ 6. 安装失败时自动回滚到旧版本
96
+
97
+ ### 升级
98
+
99
+ 升级方式与安装相同,重新运行安装脚本即可。脚本会自动备份旧版本并替换。
100
+
101
+ ```bash
102
+ curl -fsSL https://cdn.yoootek.com/openclaw-plugin/install.sh | bash
103
+ ```
104
+
105
+ ### 验证安装
106
+
107
+ ```bash
108
+ openclaw ntf --help
109
+ ```
110
+
111
+ ```bash
112
+ openclaw ntf --version
113
+ ```
114
+
115
+ 如果环境里已有其他插件占用了 `ntf`,可改用不冲突的别名:
116
+
117
+ ```bash
118
+ openclaw phone-notifications --help
119
+ ```
120
+
121
+ ```bash
122
+ openclaw phone-notifications -v
123
+ ```
124
+
125
+ ## 配置
126
+
127
+ 安装脚本会自动写入必要的插件注册配置。如需手动调整:
128
+
129
+ ```bash
130
+ # 可选:数据保留天数(默认 30)
131
+ openclaw config set plugins.entries.phone-notifications.config.retentionDays 30
132
+
133
+ # 可选:忽略特定 app
134
+ openclaw config set plugins.entries.phone-notifications.config.ignoredApps '["com.android.systemui"]'
135
+ ```
136
+
137
+ 配置项说明:
138
+ - `retentionDays?: number`(默认 30)
139
+ - `ignoredApps?: string[]`
140
+
141
+ ## 数据协议
142
+
143
+ ### Gateway Native:`notifications.push`
144
+
145
+ ```json
146
+ {
147
+ "type": "req",
148
+ "id": "n_abc",
149
+ "method": "notifications.push",
150
+ "params": {
151
+ "items": [
152
+ {
153
+ "id": "n_001",
154
+ "app": "WeChat",
155
+ "title": "张三",
156
+ "body": "在吗?",
157
+ "timestamp": "2026-03-02T08:30:00+08:00",
158
+ "category": "message",
159
+ "metadata": { "chatId": "c1" }
160
+ }
161
+ ]
162
+ }
163
+ }
164
+ ```
165
+
166
+ 说明:
167
+ - `id` 用于同一天内去重(写入 `.ids` 索引),不会作为通知正文字段落盘。
168
+ - `app` 是手机端上报字段;插件落盘时会标准化为 `appName`。
169
+
170
+ ### HTTP 备选:`POST /notifications`
171
+
172
+ ```http
173
+ POST /notifications
174
+ Authorization: Bearer ntf-xxxxxxxxxxxx
175
+ Content-Type: application/json
176
+ ```
177
+
178
+ ```json
179
+ {
180
+ "notifications": [
181
+ {
182
+ "id": "n_001",
183
+ "app": "SMS",
184
+ "title": "京东快递",
185
+ "body": "包裹已发出",
186
+ "timestamp": "2026-03-02T08:30:00+08:00"
187
+ }
188
+ ]
189
+ }
190
+ ```
191
+
192
+ 响应示例:
193
+
194
+ ```json
195
+ { "ok": true, "ingested": 1 }
196
+ ```
197
+
198
+ ## CLI 命令
199
+
200
+ 插件注册了 `openclaw ntf` 命令组,并提供 `openclaw phone-notifications` 作为无冲突别名,供 Agent 直接消费。所有命令输出 JSON。
201
+
202
+ ### 认证管理
203
+
204
+ ```bash
205
+ # 设置用户 Token(灯效下发等接口需要)
206
+ openclaw ntf auth set-token "eyJhbGciOi..."
207
+
208
+ # 查看当前认证状态
209
+ openclaw ntf auth show
210
+
211
+ # 清除认证信息
212
+ openclaw ntf auth clear
213
+ ```
214
+
215
+ ### 通知查询
216
+
217
+ ```bash
218
+ # 查询最近 7 天通知
219
+ openclaw ntf search
220
+
221
+ # 查询指定应用的通知
222
+ openclaw ntf search --app wechat --from 2026-03-01 --to 2026-03-09
223
+
224
+ # 按关键词搜索
225
+ openclaw ntf search --keyword "开会" --limit 20
226
+
227
+ # 按发送人过滤
228
+ openclaw ntf search --sender "张三" --from 2026-03-01
229
+ ```
230
+
231
+ ### 通知统计
232
+
233
+ ```bash
234
+ # 全维度统计
235
+ openclaw ntf stats
236
+
237
+ # 按应用维度统计
238
+ openclaw ntf stats --dim app --from 2026-03-01
239
+
240
+ # 按时段维度统计
241
+ openclaw ntf stats --dim hour --from 2026-03-01 --to 2026-03-09
242
+ ```
243
+
244
+ ### 通知同步(记忆系统)
245
+
246
+ ```bash
247
+ # 扫描未同步通知
248
+ openclaw ntf sync scan
249
+
250
+ # 获取指定日期未处理通知
251
+ openclaw ntf sync fetch --date 2026-03-09
252
+
253
+ # 标记同步完成
254
+ openclaw ntf sync commit --date 2026-03-09
255
+ ```
256
+
257
+ ### 通知监控任务
258
+
259
+ ```bash
260
+ # 创建监控任务
261
+ openclaw ntf monitor create boss-alert \
262
+ --description "监控老板微信消息" \
263
+ --match-rules '{"appName":"wechat","senderKeywords":["张总"]}' \
264
+ --schedule "*/30 * * * *"
265
+
266
+ # 列出监控任务
267
+ openclaw ntf monitor list
268
+
269
+ # 查看监控任务详情
270
+ openclaw ntf monitor show boss-alert
271
+
272
+ # 启用/暂停监控任务
273
+ openclaw ntf monitor enable boss-alert
274
+ openclaw ntf monitor disable boss-alert
275
+
276
+ # 删除监控任务
277
+ openclaw ntf monitor delete boss-alert --yes
278
+ ```
279
+
280
+ ### 灯效控制
281
+
282
+ ```bash
283
+ # 直接发送灯效指令到硬件设备(需要先 set-token)
284
+ openclaw ntf light send \
285
+ --segments '[{"mode":"wave","duration_s":4,"brightness":192,"color":{"r":255,"g":0,"b":0}}]'
286
+
287
+ # 呼吸灯效
288
+ openclaw ntf light send \
289
+ --segments '[{"mode":"breath","duration_s":6,"brightness":128,"color":{"r":0,"g":255,"b":0}}]'
290
+ ```
291
+
292
+ ### 灯效规则管理
293
+
294
+ ```bash
295
+ # 添加灯效规则
296
+ openclaw ntf light rules add "老板消息提醒" \
297
+ --trigger "收到老板的微信消息" \
298
+ --segments '[{"mode":"wave","duration_s":4,"brightness":192,"color":{"r":255,"g":0,"b":0}}]'
299
+
300
+ # 列出灯效规则
301
+ openclaw ntf light rules list
302
+
303
+ # 查看灯效规则详情
304
+ openclaw ntf light rules show "老板消息提醒"
305
+
306
+ # 校验灯效参数(不写入)
307
+ openclaw ntf light rules validate \
308
+ --segments '[{"mode":"breath","duration_s":6,"brightness":128,"color":{"r":0,"g":255,"b":0}}]'
309
+
310
+ # 移除灯效规则
311
+ openclaw ntf light rules remove "老板消息提醒" --yes
312
+ ```
313
+
314
+ ## 开发
315
+
316
+ ```bash
317
+ pnpm install
318
+ pnpm run build # tsc 编译
319
+ pnpm test # vitest 测试
320
+ ```
321
+
322
+ ## 目录结构
323
+
324
+ ```text
325
+ src/
326
+ ├── types.ts # 类型定义
327
+ ├── index.ts # 插件入口:service + gateway method + http route + tool + cli
328
+ ├── storage.ts # 文件系统 JSON 存储引擎
329
+ ├── light-protocol.ts # 灯效 ANCS 协议编码
330
+ └── cli/
331
+ ├── index.ts # CLI 注册汇总入口
332
+ ├── helpers.ts # 共享工具(路径解析、日期处理、JSON 输出)
333
+ ├── auth.ts # openclaw ntf auth
334
+ ├── ntf-search.ts # openclaw ntf search
335
+ ├── ntf-stats.ts # openclaw ntf stats
336
+ ├── ntf-sync.ts # openclaw ntf sync
337
+ ├── ntf-monitor.ts # openclaw ntf monitor
338
+ ├── light-rules.ts # openclaw ntf light rules
339
+ └── light-send.ts # openclaw ntf light send
340
+ ```
341
+
342
+ ## License
343
+
344
+ GPL-3.0
@@ -0,0 +1,67 @@
1
+ import { IncomingMessage, ServerResponse } from 'node:http';
2
+
3
+ interface PluginApi {
4
+ logger: {
5
+ info: (msg: string) => void;
6
+ warn: (msg: string) => void;
7
+ error: (msg: string) => void;
8
+ };
9
+ pluginConfig?: Record<string, unknown>;
10
+ runtime: {
11
+ state: {
12
+ resolveStateDir: () => string;
13
+ };
14
+ };
15
+ registerService: (service: {
16
+ id: string;
17
+ start: (ctx: {
18
+ stateDir: string;
19
+ workspaceDir?: string;
20
+ }) => void | Promise<void>;
21
+ stop?: () => void | Promise<void>;
22
+ }) => void;
23
+ registerGatewayMethod: (method: string, handler: (opts: {
24
+ params: Record<string, unknown>;
25
+ /** 发起本次请求的 WSS 客户端(operator 节点为 null) */
26
+ client: {
27
+ connId?: string;
28
+ } | null;
29
+ context: {
30
+ /** 向所有已连接的 operator 客户端广播 event 帧 */
31
+ broadcast: (event: string, payload: unknown) => void;
32
+ /** 向指定 connId 集合广播 event 帧 */
33
+ broadcastToConnIds: (event: string, payload: unknown, connIds: ReadonlySet<string>) => void;
34
+ };
35
+ respond: (ok: boolean, payload?: unknown, error?: {
36
+ code: string;
37
+ message: string;
38
+ }) => void;
39
+ }) => void | Promise<void>) => void;
40
+ /** 注册供 AI Agent 调用的 tool,声明即实现 */
41
+ registerTool: (tool: {
42
+ name: string;
43
+ description: string;
44
+ parameters: Record<string, unknown>;
45
+ execute: (toolCallId: string, params: unknown) => unknown | Promise<unknown>;
46
+ }) => void;
47
+ registerHttpRoute: (params: {
48
+ path: string;
49
+ handler: (req: IncomingMessage, res: ServerResponse) => void | Promise<void>;
50
+ auth?: "gateway" | "plugin";
51
+ }) => void;
52
+ registerCli: (registrar: (ctx: {
53
+ program: any;
54
+ stateDir?: string;
55
+ workspaceDir?: string;
56
+ logger: PluginApi["logger"];
57
+ }) => void | Promise<void>, opts?: {
58
+ commands?: string[];
59
+ }) => void;
60
+ }
61
+ declare const _default: {
62
+ id: string;
63
+ name: string;
64
+ register(api: PluginApi): void;
65
+ };
66
+
67
+ export { _default as default };