weflow-cli 1.17.0 → 1.19.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.
Files changed (71) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +3 -0
  3. package/bin/weflow-cli.ts +167 -0
  4. package/dist/bin/weflow-cli.js +199 -0
  5. package/dist/bin/weflow-cli.js.map +1 -1
  6. package/dist/src/services/diagnosticReport.d.ts +6 -0
  7. package/dist/src/services/diagnosticReport.d.ts.map +1 -1
  8. package/dist/src/services/diagnosticReport.js +16 -0
  9. package/dist/src/services/diagnosticReport.js.map +1 -1
  10. package/dist/src/services/wechatCompat.d.ts +29 -0
  11. package/dist/src/services/wechatCompat.d.ts.map +1 -0
  12. package/dist/src/services/wechatCompat.js +65 -0
  13. package/dist/src/services/wechatCompat.js.map +1 -0
  14. package/docs/DATA_CONTRACT.md +25 -25
  15. package/docs/DECISIONS.md +26 -0
  16. package/docs/FUNCTIONAL-IMPROVEMENT-SPEC.md +365 -365
  17. package/docs/HEALTH-CHECK.md +104 -104
  18. package/docs/JEV/345/272/224/347/224/250/346/226/275/345/267/245/346/226/207/346/241/243.md +310 -310
  19. package/docs/NEXT_ACTIONS.md +236 -236
  20. package/docs/NPM-PUBLISH.md +130 -130
  21. package/docs/NT_DATABASES.md +47 -0
  22. package/docs/POSITIONING.md +68 -68
  23. package/docs/PROJECT_STATE.md +2 -1
  24. package/docs/RELEASING.md +4 -0
  25. package/package.json +1 -1
  26. package/requirements-3x.txt +4 -4
  27. package/requirements-voice.txt +15 -15
  28. package/resources/js/graph3d/NOTICE.txt +35 -35
  29. package/resources/js/graph3d/d3-binarytree.min.js +2 -2
  30. package/resources/js/graph3d/d3-dispatch.min.js +2 -2
  31. package/resources/js/graph3d/d3-force-3d.min.js +2 -2
  32. package/resources/js/graph3d/d3-octree.min.js +2 -2
  33. package/resources/js/graph3d/d3-quadtree.min.js +2 -2
  34. package/resources/js/graph3d/d3-timer.min.js +2 -2
  35. package/resources/js/graph3d/three.min.js +6 -6
  36. package/resources/panel/quick-menu.cjs +197 -197
  37. package/scripts/_utils.py +1338 -1338
  38. package/scripts/annual_report.py +3 -1
  39. package/scripts/article_notes.py +423 -423
  40. package/scripts/contact_schema.py +339 -339
  41. package/scripts/create_reading_notes.py +11 -11
  42. package/scripts/daily_task.ps1 +213 -213
  43. package/scripts/extract_todos.py +3 -1
  44. package/scripts/fav_notes.py +321 -321
  45. package/scripts/health_check.py +473 -473
  46. package/scripts/imported_chats.py +68 -68
  47. package/scripts/install_tasks.ps1 +105 -105
  48. package/scripts/leads.py +179 -179
  49. package/scripts/mcp_bridge.py +3 -1
  50. package/scripts/media_index.py +150 -0
  51. package/scripts/network.py +206 -206
  52. package/scripts/nt_common.py +32 -0
  53. package/scripts/nt_decrypt.py +19 -15
  54. package/scripts/opinion_timeline.py +138 -138
  55. package/scripts/replay.py +803 -803
  56. package/scripts/run_hidden.vbs +24 -24
  57. package/scripts/semantic_search.py +5 -1
  58. package/scripts/user_notes.py +315 -315
  59. package/scripts/voice_transcribe.py +139 -139
  60. package/scripts/watch_issues.py +212 -212
  61. package/scripts/watch_mail.py +131 -131
  62. package/scripts/wechat_avatar.py +185 -0
  63. package/scripts/wechat_ledger.py +190 -0
  64. package/src/services/cursorProbe.ts +222 -222
  65. package/src/services/diagnosticReport.ts +22 -0
  66. package/src/services/qchatImport.ts +327 -327
  67. package/src/services/setupVenv.ts +238 -238
  68. package/src/services/syncService.ts +363 -363
  69. package/src/services/syncState.ts +275 -275
  70. package/src/services/wechatCompat.ts +67 -0
  71. package/src/services/wechatMedia.ts +166 -166
@@ -1,104 +1,104 @@
1
- # 定期体检
2
-
3
- ## 为什么是脚本,不是清单
4
-
5
- 人工清单有两个必然结局:要么没人跑,要么跑了也没人愿意逐条读输出再判断。
6
- 所以体检做成 `scripts/health_check.py`——**纯脚本,零 token**,退出码即结论。
7
-
8
- 每一项检查都对应一个**真实发生过、且当时看不出来**的故障。没有对应故障的检查
9
- 不往里加,否则报告会变长到没人看。
10
-
11
- ## 跑一次
12
-
13
- ```powershell
14
- py scripts/health_check.py # 人读的报告
15
- py scripts/health_check.py --json # 机器读
16
- ```
17
-
18
- 退出码 `0` = 全部通过,`1` = 有失败项。报告长这样(版本号、日期、字节数都是
19
- 当次运行的真实值,仅作示例):
20
-
21
- ```
22
- WeFlow 健康检查 · 2026-09-19 10:04
23
-
24
- [OK ] 版本一致 CLI X.Y.Z / package X.Y.Z
25
- [OK ] 环境自检 已初始化=True 消息库=True
26
- [OK ] 微信客户端 4.1.15.13(D:\WeiXin\4.1.15.13) ⚠ 残留版本目录(没有 Weixin.dll,加载会失败): 4.1.15.11(1 个文件)
27
- [OK ] Python 依赖 齐全
28
- [OK ] 会话新鲜度 最新会话 2026-09-19 10:03(0.0 天前)
29
- [OK ] 读取路径一致 (wxid_6xx1ehe4h…) json 最新 2026-09-19 10:03 / html 最新 2026-09-19 10:03:12
30
- [OK ] 导出格式 json 938 字节
31
- [OK ] 导出格式 txt 145 字节
32
- [OK ] 导出格式 excel 6788 字节
33
- [OK ] 计划任务 均在位且上次成功
34
-
35
- 全部通过(10 项)
36
- ```
37
-
38
- 全程约 1 分钟,其中大部分是 `export html` 扫描媒体索引的固定开销。
39
-
40
- ## 检查项与它们防的故障
41
-
42
- | 检查 | 防的是什么 |
43
- | --- | --- |
44
- | **版本一致** | `1.6.0` 的 `--version` 写死成 `1.5.1`,导致「我到底跑的哪个版本」无法回答,Issue #8 的诊断因此卡住 |
45
- | **环境自检** | 未初始化 / 缺 Python 依赖时,命令报的是「数据库连接失败」,指向错误的方向 |
46
- | **微信客户端** | 体检从没报过客户端版本,而这是"数据读不出来 / 客户端起不来"时第一个要问的。判据只能是**活进程命令行的 `--user-lib-dir`** —— exe 里那个版本字面量只是**兜底**(实测它恰好与目录同名,所以"读字面量"是个看着会对的错判据);磁盘上**有**版本目录也不代表能用(本机就有一个只剩 1 个文件的残留目录,指向它的加载会失败)。同一份进程表还给出:**客户端自报的数据目录**(与配置推出来的根**按真身比**,本机那条是软链)、**崩溃记录**(只报条数与最近时间)、以及 `update\update.data` 在场时那句"命令行给的版本未必是加载的那个"。**取不到就写"未知"**,并把这个字段整个缺失当成**不通过**(那意味着 CLI 没重建) |
47
- | **Python 依赖** | `nt_decrypt.py` 是子进程,缺 `sqlcipher3` 的表现和密码错一模一样 |
48
- | **会话新鲜度** | 读取只覆盖部分分片时,会话列表停在十几天前,而每条命令都返回「成功」。⚠️ **但"这段时间没聊天"是同一个观测** —— 所以提示里两种解释都写,并点出判别器在隔壁:`读取路径一致` 绿着多半是没聊天,两项一起红才更像读取断了 |
49
- | **选择样本会话**(下面两项的前置) | 挑不出样本会话时,`读取路径一致` 与 `导出格式` 会**整段不跑**。没有会话时会报红;**有会话、却一条都拿不到 `username`**(字段长变了、列表是半截的)原来直接返回空 ⇒ 那两项静默跳过、报告照样写"全部通过",只是项数悄悄少了两个。现在这一支也报红并说明"这两项没跑,不代表通过" |
50
- | **读取路径一致** | 同一会话,`export json` 走 NT 路径、`export html` 走 Python 路径。二者曾差 1114 条消息——json 只读到第一个分片。**它曾经会假红**:判据是"两边报的最新消息精确到分钟相同",而 json 先导、html 后导(中间一两分钟)⇒ 检查期间来一条新消息就必然不一致。放宽容差会把这一项唯一要抓的东西(分片半读,繁忙群里轮转就在分钟级)放过去,所以改成**不一致时再读一次 json 仲裁**:那一读能看到 html 那条 ⇒ 是"消息是新的"(判过并说明);看不到 ⇒ 两条路径确实不一致(判红)。仲裁只在本来就不一致时才多花一次导出 |
51
- | **导出格式 json/txt/excel** | `excel` 曾**从未成功过**,报错只有「导出失败」四个字 |
52
- | **计划任务** | 提醒脚本静默停跑,没有任何人会知道。**它还会假绿**:判据是从 `schtasks` 的文本输出里找 `Last Result` / `上次运行结果` 那一行,而系统语言或输出格式一变就找不到它 —— 那时两个清单都是空的,它会报"均在位且上次成功"。现在读不出来就报**"没有验证"**(红),与"取不到就说未知"是同一条纪律。**同一条纪律还修了另一处(2026-10-11)**:任务刚注册、还没到第一次触发时,`schtasks` 报的是 `SCHED_S_TASK_HAS_NOT_RUN`(`267011` / `0x41303`)—— 原来它落进"上次运行失败"那一支,提示还写着"脚本可能抛异常了",会把刚注册的人引去查一个并不存在的异常。现在它是**自己的状态**("还没跑过"),**仍然算不通过**:这一项要的是"跑过一次且成功",而"一直没跑过"正是它要防的。(这两个 watcher 任务的**注册命令**此前从没写下来过,只在 `RELEASING.md` 的「新动态邮件提醒」一节里有名字 —— 已补上。)|
53
-
54
- ### 「读取路径一致」为什么用时间戳而不是条数
55
-
56
- 条数会受分页、去重、日期过滤影响,两个路径本来就可能差一点。**最新一条消息的时间**
57
- 是确定的:两条路径读同一个会话,如果连最新消息都不是同一条,那就是有一边没读到。
58
-
59
- 这一项正是分片故障的探测器。把分片合并关掉后它立刻报:
60
-
61
- ```
62
- [FAIL] 读取路径一致 (47966561144@ch…) json 最新 2026-08-30 15:30 / html 最新 2026-09-17 23:02:23
63
- ```
64
-
65
- ### 「会话新鲜度」的阈值
66
-
67
- 默认 7 天(脚本顶部 `STALE_SESSION_DAYS`)。不是每个人都天天有微信消息,所以故意
68
- 放宽;但如果连最近 5 个会话都超过 7 天没动,基本可以断定读取出了问题,而不是没人聊天。
69
-
70
- ## 怎么让它定期跑
71
-
72
- 和 `WeFlow Issue Watch`、`WeFlow Mail Watch` 一样交给计划任务,不依赖任何编辑器或
73
- Claude 会话开着:
74
-
75
- ```powershell
76
- schtasks /create /tn "WeFlow Health Check" ^
77
- /tr "py \"<仓库路径>\scripts\health_check.py\"" ^
78
- /sc daily /st 09:07
79
- ```
80
-
81
- - 查看:`Get-ScheduledTask -TaskName 'WeFlow Health Check'`
82
- - 手动跑:`Start-ScheduledTask -TaskName 'WeFlow Health Check'`
83
- - 上次结果:`schtasks /query /tn "WeFlow Health Check" /fo LIST /v`
84
-
85
- > 体检脚本自身也在检查计划任务,所以它挂了会在下一次运行时报出来(前提是它还能被
86
- > 触发——所以别把它的触发条件设成「上次成功才跑」)。
87
-
88
- ## 目前已知、但**未修**的问题
89
-
90
- 体检脚本覆盖不到这些;它们需要人判断,所以留在这里而不是塞进自动检查。
91
- **修好的行留在表里并标"已修"** —— 这一节的价值一半在教训,其中一行正是因为没人回头核而多挂了些日子。
92
-
93
- | 问题 | 现象 | 为什么没自动修 |
94
- | --- | --- | --- |
95
- | 判断层按**地区**不可用 | `decide.py` 与日报的 Jev 分类都拿到 `HTTP 451: {"title":"Typesafe is not available in your region."}` | **不能修**(服务端策略;本机 2026-10-10 实测)。功能不坏,是**逐篇/整轮退回老路径**:助手按设计回退(日志里那行 `判断层不可用: HTTP 451…`),日报每篇退回 LLM 解析。**已改**:同一条失败在日报日志里**折叠成一次**(`另有 N 篇因**同一条**失败被折叠`),此前上百篇会刷上百行同一句话;要连这一次尝试也省掉就用 `--classifier llm`(`OPERATIONS.md` 里已写明)。 |
96
- | 未知 talker 的退出码不一致 | `messages <拼错的wxid>` 退出 0 且 `success:true`;同样输入 `export` 退出 1 | **退出码刻意不动**("没有消息"不是错误,脚本与 MCP 依赖它),但**歧义已经说出来**(2026-10-09):`messages` 遇到 `wxid_`/`@chatroom`/`@openim` 形状、而会话与联系人都不认识它时,人看的输出补一句「这个 ID 既不在会话里、也不在联系人里……先确认有没有拼错」,`--json` 里多一个可选的 `note` 字段(`success` 与退出码都不变)。真实命令跑过:`messages wxid_zzz_not_a_real_id --json` → `{"success":true,…,"note":"这个 ID 既不在会话里、也不在联系人里:…"}`,退出码 0。判定逻辑是纯函数 `emptyMessagesNote`(`src/services/messageQuery.ts`),接线处有守卫测试 |
97
- | `whitelist list` / `blacklist list` 空列表 | 曾只输出一个换行,没有「为空」提示 | **已修**(2026-10-09 复核):不带参数时打印 `白名单为空` / `黑名单为空` 加一条「怎么添加」(`bin/weflow-cli.ts:2269`、`:2457`);`whitelist list --json` 与 `blacklist list --json` 都返回 `{"success":true,"entries":[]}` —— 三条都用真实命令跑过,不是读代码推断的 |
98
- | `dashscopeApiKey` **曾**无法通过 `config set` 写入 | 脚本会读它,但它当时不在 `CliConfig` 里 ⇒ `config set` 拒绝、只能手改 config.json | **已修**(`favPassphrase` 是同一轮发现的):键已声明、加密存储、`config set` 可写;守卫见 `test/config_keys_declared_test.py` |
99
- | 朋友圈/收藏密钥缺失 | `fav list` 曾把「没配密钥」报成「需 4.x NT 连接」——已修,现在会明确说缺密钥 | — |
100
-
101
- ## 相关文档
102
-
103
- - 发布流程与发布后自检:[RELEASING.md](RELEASING.md)
104
- - 数据契约:[DATA_CONTRACT.md](DATA_CONTRACT.md)
1
+ # 定期体检
2
+
3
+ ## 为什么是脚本,不是清单
4
+
5
+ 人工清单有两个必然结局:要么没人跑,要么跑了也没人愿意逐条读输出再判断。
6
+ 所以体检做成 `scripts/health_check.py`——**纯脚本,零 token**,退出码即结论。
7
+
8
+ 每一项检查都对应一个**真实发生过、且当时看不出来**的故障。没有对应故障的检查
9
+ 不往里加,否则报告会变长到没人看。
10
+
11
+ ## 跑一次
12
+
13
+ ```powershell
14
+ py scripts/health_check.py # 人读的报告
15
+ py scripts/health_check.py --json # 机器读
16
+ ```
17
+
18
+ 退出码 `0` = 全部通过,`1` = 有失败项。报告长这样(版本号、日期、字节数都是
19
+ 当次运行的真实值,仅作示例):
20
+
21
+ ```
22
+ WeFlow 健康检查 · 2026-09-19 10:04
23
+
24
+ [OK ] 版本一致 CLI X.Y.Z / package X.Y.Z
25
+ [OK ] 环境自检 已初始化=True 消息库=True
26
+ [OK ] 微信客户端 4.1.15.13(D:\WeiXin\4.1.15.13) ⚠ 残留版本目录(没有 Weixin.dll,加载会失败): 4.1.15.11(1 个文件)
27
+ [OK ] Python 依赖 齐全
28
+ [OK ] 会话新鲜度 最新会话 2026-09-19 10:03(0.0 天前)
29
+ [OK ] 读取路径一致 (wxid_6xx1ehe4h…) json 最新 2026-09-19 10:03 / html 最新 2026-09-19 10:03:12
30
+ [OK ] 导出格式 json 938 字节
31
+ [OK ] 导出格式 txt 145 字节
32
+ [OK ] 导出格式 excel 6788 字节
33
+ [OK ] 计划任务 均在位且上次成功
34
+
35
+ 全部通过(10 项)
36
+ ```
37
+
38
+ 全程约 1 分钟,其中大部分是 `export html` 扫描媒体索引的固定开销。
39
+
40
+ ## 检查项与它们防的故障
41
+
42
+ | 检查 | 防的是什么 |
43
+ | --- | --- |
44
+ | **版本一致** | `1.6.0` 的 `--version` 写死成 `1.5.1`,导致「我到底跑的哪个版本」无法回答,Issue #8 的诊断因此卡住 |
45
+ | **环境自检** | 未初始化 / 缺 Python 依赖时,命令报的是「数据库连接失败」,指向错误的方向 |
46
+ | **微信客户端** | 体检从没报过客户端版本,而这是"数据读不出来 / 客户端起不来"时第一个要问的。判据只能是**活进程命令行的 `--user-lib-dir`** —— exe 里那个版本字面量只是**兜底**(实测它恰好与目录同名,所以"读字面量"是个看着会对的错判据);磁盘上**有**版本目录也不代表能用(本机就有一个只剩 1 个文件的残留目录,指向它的加载会失败)。同一份进程表还给出:**客户端自报的数据目录**(与配置推出来的根**按真身比**,本机那条是软链)、**崩溃记录**(只报条数与最近时间)、以及 `update\update.data` 在场时那句"命令行给的版本未必是加载的那个"。**取不到就写"未知"**,并把这个字段整个缺失当成**不通过**(那意味着 CLI 没重建) |
47
+ | **Python 依赖** | `nt_decrypt.py` 是子进程,缺 `sqlcipher3` 的表现和密码错一模一样 |
48
+ | **会话新鲜度** | 读取只覆盖部分分片时,会话列表停在十几天前,而每条命令都返回「成功」。⚠️ **但"这段时间没聊天"是同一个观测** —— 所以提示里两种解释都写,并点出判别器在隔壁:`读取路径一致` 绿着多半是没聊天,两项一起红才更像读取断了 |
49
+ | **选择样本会话**(下面两项的前置) | 挑不出样本会话时,`读取路径一致` 与 `导出格式` 会**整段不跑**。没有会话时会报红;**有会话、却一条都拿不到 `username`**(字段长变了、列表是半截的)原来直接返回空 ⇒ 那两项静默跳过、报告照样写"全部通过",只是项数悄悄少了两个。现在这一支也报红并说明"这两项没跑,不代表通过" |
50
+ | **读取路径一致** | 同一会话,`export json` 走 NT 路径、`export html` 走 Python 路径。二者曾差 1114 条消息——json 只读到第一个分片。**它曾经会假红**:判据是"两边报的最新消息精确到分钟相同",而 json 先导、html 后导(中间一两分钟)⇒ 检查期间来一条新消息就必然不一致。放宽容差会把这一项唯一要抓的东西(分片半读,繁忙群里轮转就在分钟级)放过去,所以改成**不一致时再读一次 json 仲裁**:那一读能看到 html 那条 ⇒ 是"消息是新的"(判过并说明);看不到 ⇒ 两条路径确实不一致(判红)。仲裁只在本来就不一致时才多花一次导出 |
51
+ | **导出格式 json/txt/excel** | `excel` 曾**从未成功过**,报错只有「导出失败」四个字 |
52
+ | **计划任务** | 提醒脚本静默停跑,没有任何人会知道。**它还会假绿**:判据是从 `schtasks` 的文本输出里找 `Last Result` / `上次运行结果` 那一行,而系统语言或输出格式一变就找不到它 —— 那时两个清单都是空的,它会报"均在位且上次成功"。现在读不出来就报**"没有验证"**(红),与"取不到就说未知"是同一条纪律。**同一条纪律还修了另一处(2026-10-11)**:任务刚注册、还没到第一次触发时,`schtasks` 报的是 `SCHED_S_TASK_HAS_NOT_RUN`(`267011` / `0x41303`)—— 原来它落进"上次运行失败"那一支,提示还写着"脚本可能抛异常了",会把刚注册的人引去查一个并不存在的异常。现在它是**自己的状态**("还没跑过"),**仍然算不通过**:这一项要的是"跑过一次且成功",而"一直没跑过"正是它要防的。(这两个 watcher 任务的**注册命令**此前从没写下来过,只在 `RELEASING.md` 的「新动态邮件提醒」一节里有名字 —— 已补上。)|
53
+
54
+ ### 「读取路径一致」为什么用时间戳而不是条数
55
+
56
+ 条数会受分页、去重、日期过滤影响,两个路径本来就可能差一点。**最新一条消息的时间**
57
+ 是确定的:两条路径读同一个会话,如果连最新消息都不是同一条,那就是有一边没读到。
58
+
59
+ 这一项正是分片故障的探测器。把分片合并关掉后它立刻报:
60
+
61
+ ```
62
+ [FAIL] 读取路径一致 (47966561144@ch…) json 最新 2026-08-30 15:30 / html 最新 2026-09-17 23:02:23
63
+ ```
64
+
65
+ ### 「会话新鲜度」的阈值
66
+
67
+ 默认 7 天(脚本顶部 `STALE_SESSION_DAYS`)。不是每个人都天天有微信消息,所以故意
68
+ 放宽;但如果连最近 5 个会话都超过 7 天没动,基本可以断定读取出了问题,而不是没人聊天。
69
+
70
+ ## 怎么让它定期跑
71
+
72
+ 和 `WeFlow Issue Watch`、`WeFlow Mail Watch` 一样交给计划任务,不依赖任何编辑器或
73
+ Claude 会话开着:
74
+
75
+ ```powershell
76
+ schtasks /create /tn "WeFlow Health Check" ^
77
+ /tr "py \"<仓库路径>\scripts\health_check.py\"" ^
78
+ /sc daily /st 09:07
79
+ ```
80
+
81
+ - 查看:`Get-ScheduledTask -TaskName 'WeFlow Health Check'`
82
+ - 手动跑:`Start-ScheduledTask -TaskName 'WeFlow Health Check'`
83
+ - 上次结果:`schtasks /query /tn "WeFlow Health Check" /fo LIST /v`
84
+
85
+ > 体检脚本自身也在检查计划任务,所以它挂了会在下一次运行时报出来(前提是它还能被
86
+ > 触发——所以别把它的触发条件设成「上次成功才跑」)。
87
+
88
+ ## 目前已知、但**未修**的问题
89
+
90
+ 体检脚本覆盖不到这些;它们需要人判断,所以留在这里而不是塞进自动检查。
91
+ **修好的行留在表里并标"已修"** —— 这一节的价值一半在教训,其中一行正是因为没人回头核而多挂了些日子。
92
+
93
+ | 问题 | 现象 | 为什么没自动修 |
94
+ | --- | --- | --- |
95
+ | 判断层按**地区**不可用 | `decide.py` 与日报的 Jev 分类都拿到 `HTTP 451: {"title":"Typesafe is not available in your region."}` | **不能修**(服务端策略;本机 2026-10-10 实测)。功能不坏,是**逐篇/整轮退回老路径**:助手按设计回退(日志里那行 `判断层不可用: HTTP 451…`),日报每篇退回 LLM 解析。**已改**:同一条失败在日报日志里**折叠成一次**(`另有 N 篇因**同一条**失败被折叠`),此前上百篇会刷上百行同一句话;要连这一次尝试也省掉就用 `--classifier llm`(`OPERATIONS.md` 里已写明)。 |
96
+ | 未知 talker 的退出码不一致 | `messages <拼错的wxid>` 退出 0 且 `success:true`;同样输入 `export` 退出 1 | **退出码刻意不动**("没有消息"不是错误,脚本与 MCP 依赖它),但**歧义已经说出来**(2026-10-09):`messages` 遇到 `wxid_`/`@chatroom`/`@openim` 形状、而会话与联系人都不认识它时,人看的输出补一句「这个 ID 既不在会话里、也不在联系人里……先确认有没有拼错」,`--json` 里多一个可选的 `note` 字段(`success` 与退出码都不变)。真实命令跑过:`messages wxid_zzz_not_a_real_id --json` → `{"success":true,…,"note":"这个 ID 既不在会话里、也不在联系人里:…"}`,退出码 0。判定逻辑是纯函数 `emptyMessagesNote`(`src/services/messageQuery.ts`),接线处有守卫测试 |
97
+ | `whitelist list` / `blacklist list` 空列表 | 曾只输出一个换行,没有「为空」提示 | **已修**(2026-10-09 复核):不带参数时打印 `白名单为空` / `黑名单为空` 加一条「怎么添加」(`bin/weflow-cli.ts:2269`、`:2457`);`whitelist list --json` 与 `blacklist list --json` 都返回 `{"success":true,"entries":[]}` —— 三条都用真实命令跑过,不是读代码推断的 |
98
+ | `dashscopeApiKey` **曾**无法通过 `config set` 写入 | 脚本会读它,但它当时不在 `CliConfig` 里 ⇒ `config set` 拒绝、只能手改 config.json | **已修**(`favPassphrase` 是同一轮发现的):键已声明、加密存储、`config set` 可写;守卫见 `test/config_keys_declared_test.py` |
99
+ | 朋友圈/收藏密钥缺失 | `fav list` 曾把「没配密钥」报成「需 4.x NT 连接」——已修,现在会明确说缺密钥 | — |
100
+
101
+ ## 相关文档
102
+
103
+ - 发布流程与发布后自检:[RELEASING.md](RELEASING.md)
104
+ - 数据契约:[DATA_CONTRACT.md](DATA_CONTRACT.md)