weflow-cli 1.16.0 → 1.17.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 (97) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/README.md +16 -4
  3. package/bin/weflow-cli.ts +348 -6
  4. package/dist/bin/weflow-cli.js +381 -8
  5. package/dist/bin/weflow-cli.js.map +1 -1
  6. package/dist/src/core/ntCore.d.ts +47 -0
  7. package/dist/src/core/ntCore.d.ts.map +1 -1
  8. package/dist/src/core/ntCore.js +24 -0
  9. package/dist/src/core/ntCore.js.map +1 -1
  10. package/dist/src/services/assistantService.d.ts +8 -1
  11. package/dist/src/services/assistantService.d.ts.map +1 -1
  12. package/dist/src/services/assistantService.js +47 -8
  13. package/dist/src/services/assistantService.js.map +1 -1
  14. package/dist/src/services/assistantTools.d.ts +8 -0
  15. package/dist/src/services/assistantTools.d.ts.map +1 -1
  16. package/dist/src/services/assistantTools.js +67 -11
  17. package/dist/src/services/assistantTools.js.map +1 -1
  18. package/dist/src/services/configService.d.ts.map +1 -1
  19. package/dist/src/services/configService.js +3 -2
  20. package/dist/src/services/configService.js.map +1 -1
  21. package/dist/src/services/cursorProbe.d.ts +44 -0
  22. package/dist/src/services/cursorProbe.d.ts.map +1 -0
  23. package/dist/src/services/cursorProbe.js +183 -0
  24. package/dist/src/services/cursorProbe.js.map +1 -0
  25. package/dist/src/services/qchatImport.d.ts +89 -0
  26. package/dist/src/services/qchatImport.d.ts.map +1 -0
  27. package/dist/src/services/qchatImport.js +273 -0
  28. package/dist/src/services/qchatImport.js.map +1 -0
  29. package/dist/src/services/setupVenv.d.ts +43 -0
  30. package/dist/src/services/setupVenv.d.ts.map +1 -0
  31. package/dist/src/services/setupVenv.js +198 -0
  32. package/dist/src/services/setupVenv.js.map +1 -0
  33. package/dist/src/utils/python.d.ts +10 -0
  34. package/dist/src/utils/python.d.ts.map +1 -1
  35. package/dist/src/utils/python.js +27 -4
  36. package/dist/src/utils/python.js.map +1 -1
  37. package/docs/DATA_CONTRACT.md +25 -0
  38. package/docs/DECISIONS.md +92 -30
  39. package/docs/FUNCTIONAL-IMPROVEMENT-SPEC.md +365 -365
  40. package/docs/HEALTH-CHECK.md +104 -104
  41. package/docs/JEV/345/272/224/347/224/250/346/226/275/345/267/245/346/226/207/346/241/243.md +310 -310
  42. package/docs/NEXT_ACTIONS.md +236 -236
  43. package/docs/NPM-PUBLISH.md +130 -130
  44. package/docs/POSITIONING.md +68 -68
  45. package/docs/PROJECT_STATE.md +6 -3
  46. package/docs/REPLAY.md +169 -0
  47. package/docs/SYNC_CONTRACT.md +197 -180
  48. package/package.json +89 -88
  49. package/requirements-3x.txt +4 -4
  50. package/requirements-voice.txt +15 -15
  51. package/resources/js/graph3d/NOTICE.txt +35 -35
  52. package/resources/js/graph3d/d3-binarytree.min.js +2 -2
  53. package/resources/js/graph3d/d3-dispatch.min.js +2 -2
  54. package/resources/js/graph3d/d3-force-3d.min.js +2 -2
  55. package/resources/js/graph3d/d3-octree.min.js +2 -2
  56. package/resources/js/graph3d/d3-quadtree.min.js +2 -2
  57. package/resources/js/graph3d/d3-timer.min.js +2 -2
  58. package/resources/js/graph3d/three.min.js +6 -6
  59. package/resources/js/graph3d/viewer2d.js +550 -448
  60. package/resources/panel/quick-menu.cjs +197 -197
  61. package/scripts/_utils.py +1338 -1338
  62. package/scripts/article_notes.py +423 -423
  63. package/scripts/chat_notes.py +86 -3
  64. package/scripts/check_readme_commands.py +427 -426
  65. package/scripts/contact_schema.py +339 -339
  66. package/scripts/create_reading_notes.py +11 -11
  67. package/scripts/daily_task.ps1 +213 -213
  68. package/scripts/fav_notes.py +321 -321
  69. package/scripts/graph_2d.py +156 -151
  70. package/scripts/graph_3d.py +672 -646
  71. package/scripts/health_check.py +473 -473
  72. package/scripts/imported_chats.py +68 -0
  73. package/scripts/install_tasks.ps1 +105 -105
  74. package/scripts/leads.py +179 -179
  75. package/scripts/network.py +206 -206
  76. package/scripts/nt_decrypt.py +135 -1
  77. package/scripts/on_this_day.py +178 -178
  78. package/scripts/opinion_timeline.py +138 -138
  79. package/scripts/promises.py +185 -185
  80. package/scripts/replay.py +803 -0
  81. package/scripts/run_hidden.vbs +25 -0
  82. package/scripts/semantic_search.py +73 -5
  83. package/scripts/user_notes.py +315 -315
  84. package/scripts/voice_transcribe.py +139 -139
  85. package/scripts/watch_issues.py +212 -212
  86. package/scripts/watch_mail.py +131 -131
  87. package/src/core/ntCore.ts +59 -0
  88. package/src/services/assistantService.ts +48 -8
  89. package/src/services/assistantTools.ts +73 -10
  90. package/src/services/configService.ts +3 -2
  91. package/src/services/cursorProbe.ts +222 -0
  92. package/src/services/qchatImport.ts +327 -0
  93. package/src/services/setupVenv.ts +238 -0
  94. package/src/services/syncService.ts +363 -363
  95. package/src/services/syncState.ts +275 -275
  96. package/src/services/wechatMedia.ts +166 -166
  97. package/src/utils/python.ts +33 -4
@@ -1,236 +1,236 @@
1
- # WeFlow CLI 下一阶段行动建议
2
-
3
- > 编写日期:2026-10-14
4
- > 依据:本地仓库 `package.json` 的 1.11.1 版本、截至本次梳理的提交与工作区状态。
5
- > 用途:把近期改进方向拆成可以独立评审、实现和验收的任务。项目现状以 [PROJECT_STATE.md](PROJECT_STATE.md)、技术取舍以 [DECISIONS.md](DECISIONS.md) 为准。
6
-
7
- ## 建议结论
8
-
9
- 下一阶段应先完成三个“收口”任务:
10
-
11
- 1. 让历史文章回填与日报共用缓存的行为可控、可验证,尤其补上强制重新抓取的入口。
12
- 2. 统一不同导出格式的媒体状态语义,并补上导出失败和跨环境的验证证据。
13
- 3. 分批补齐 CLI 在 `--json` 模式下的运行时错误结构,保持机器调用结果稳定。
14
-
15
- 这三项都能建立在现有实现上,不需要引入新的数据处理架构。同步游标、MCP 扩面、资料包和更复杂的 AI 功能可在上述边界稳定后,根据实际集成需求推进。
16
-
17
- ## 当前基线
18
-
19
- - 本地代码版本为 `1.11.1`。最近一批提交完成了 Markdown 连图、文档本体导出和文档导出的多项边界修复。
20
- - 本次读取时,本地 `master` 比 `origin/master` 多 11 个提交;工作区中 `scripts/backfill_articles.py` 和 `test/backfill_articles_test.py` 有未提交改动。它们正在让历史回填复用日报正文缓存,本文件将这部分视为进行中的工作,不把它描述为已发布功能。
21
- - HTML 导出已有媒体覆盖报告;Markdown 和 JSON/TXT/Excel 的媒体导出复用同一份清单。文件本体导出目前只有本机实测记录,Issue #11 尚待报告者确认及其他环境验证。
22
- - `sync run/status/verify` 和本地同步状态契约已经存在,但稳定游标尚未作为对外能力承诺。
23
- - 项目已记录扩展边界:代码扩展在仓库内完成;外部程序通过 CLI、JSON 或 MCP 接入。近期不建议增加进程内插件加载器。
24
-
25
- ## P0:完成正在进行的缓存衔接
26
-
27
- **已完成(2026-10-14)**,验收的六类行为各有测试(命中不联网 / 未命中去抓 / 成功写缓存 / 失败不写 /
28
- 强制重抓刷新旧缓存 / 重抓失败不动旧缓存 / 缓存不可写不影响这一篇 / 并发下标不错位),关键两条做过变异检查。
29
- 落地的几处与本节设想不同的地方:回填与日报**共用同一条缓存**(`fetch_article_cached`,成功才写);
30
- `--no-fetch-cache` 两边同名同义;`--refresh` 的帮助写明它只管"做哪些天"。另外**多做了一个标记**:
31
- 抓取失败与"正文本来就短"从此分开记(`.articles.json` 的 `fetchFailed`,那天判为没做完、重跑只重试失败的篇)——
32
- 它直接对应本节验收里"失败后重跑可继续补齐,不会将部分日期或部分文章误标为完整"那一条。
33
- 判据与代价写在 D-108;顺带量到一件事:**接力是部分的**——日报对每篇有 url 的都抓正文,回填只抓"正文过短"的,
34
- 2026-10-13 那天 485 篇里只有 145 篇进了缓存(详见 D-108)。
35
-
36
- > **2026-10-16 补完:显式预取开关做了,但不在回填侧。** `daily --prefetch-bodies [n]`(默认关)在抓取阶段
37
- > **之前**并发预热这份缓存,于是抓取阶段全是缓存命中、故意的 8–12 秒/篇节流不再触发(D-119)。
38
- > 写过一个 `backfill_articles --prefetch-all`,**撤掉了**——它会产出同一天的文件、与 `daily` 抢同名。
39
- > 同时量到一件反直觉的事并据此否掉了自己的提议:**让索引吃完整正文没有增益**(D-118),
40
- > 所以这份缓存只服务展示路径(`search --with-text`)与日报耗时,**不服务检索**。
41
-
42
- ### 目标
43
-
44
- 使回填和日报共享正文缓存后,用户仍能明确选择复用缓存或重新抓取;重跑行为有测试保护,不会因旧缓存而悄悄使用过期正文。
45
-
46
- ### 建议工作
47
-
48
- - 为历史回填增加显式的缓存控制选项,例如允许用户绕过已有缓存重新抓取;参数名称和交互方式应与日报已有的 `--no-fetch-cache` 保持一致或清楚说明差别。
49
- - 明确 `--refresh` 的语义:它目前用于重做已回填日期,不应让用户误以为它必定重新请求文章正文。
50
- - 覆盖缓存命中、缓存未命中、抓取成功、抓取失败、强制重抓及并发抓取的行为。
51
- - 继续只缓存非空成功正文;缓存不可写时回填仍应按现有约定完成,不因缓存辅助功能导致整批失败。
52
- - 确认文档中所述的缓存目录、请求节流和“日报生成可复用历史正文”与代码一致。
53
-
54
- ### 验收标准
55
-
56
- - 默认回填会复用有效缓存,缓存命中时不访问网络。
57
- - 用户显式选择重抓时,即使已有缓存也会访问正文来源,并以成功结果更新缓存。
58
- - 抓取失败不会覆盖已有的有效缓存;没有旧缓存时,失败也不会生成空缓存文件。
59
- - 失败后重跑可继续补齐,不会将部分日期或部分文章误标为完整。
60
- - `test/backfill_articles_test.py` 和日报缓存相关测试覆盖以上行为;Python 脚本的参数帮助与实际行为一致。
61
-
62
- ### 需要注意
63
-
64
- 缓存只代表“曾成功抓到的正文”,不代表正文永远是最新版本。刷新入口应明确,而不应通过改变默认行为造成额外请求。
65
-
66
- ## P1:统一导出媒体状态与验证口径
67
-
68
- **基本完成(2026-10-14)**,**只差本节最后那条"第二台设备/另一个账号的验收记录"**(依赖外部环境,做不了)。
69
- 已落地的:统一词汇(报告答"源数据里能不能定位"→ `found`/`missing`;清单与 CLI JSON 答"有没有落进导出目录"
70
- → `written`/`copied`/`unavailable`,此后没有哪个词承担两种意思);`manifest.documents` 的 `exported` 改名为
71
- `written`(此前与报告的 `exported` 同形不同义,拷贝失败时会让"已导出"变成假话);三种格式(html / md /
72
- `--media`)的机器可读摘要收成**一个函数** `media_json_summary`,因此不会再各说各话,且报告文件名三处都有
73
- (此前只有 HTML 那条给);回归测试覆盖"拷贝失败"(报告说 `found`、清单说 `unavailable`)、"重复运行"
74
- (`written` 与 `copied` 分开,第二遍不误报 0)、"局部范围不吃掉宽范围的清单"(合并式写入),并断言摘要
75
- **不含本机绝对路径**。仍未做:`ranges`(窄/宽)之外的状态读取兼容性只按现有 v1/v2 读取路径验过。
76
-
77
- ### 目标
78
-
79
- 让 HTML 报告、Markdown 清单及其他格式引用的媒体状态表达同一事实;用户可以区分“本地未找到”“已找到但未成功写出”和“已写入导出目录”。
80
-
81
- ### 建议工作
82
-
83
- - 盘点 `weflow-media-report/v1` 与 `weflow-media-manifest/v2` 中的状态、计数和含义,尤其核对文档文件的 `exported`、`found` 与实际写入结果。
84
- - 选定统一语义:媒体是否可在源数据中定位、是否成功写入资产目录、是否仅在 HTML 内嵌,分别用清楚且不互相覆盖的字段表达。
85
- - 保持已有 manifest 的读取兼容;如需更改 schema,采用增量字段或明确的版本升级策略,不悄悄改变旧字段含义。
86
- - 为文件复制失败、重复导出、已有资产、窄日期范围覆盖已有宽范围清单等场景添加回归检查。
87
- - 在不输出完整本地路径、聊天正文或密钥的前提下,让 JSON 操作结果能给出各状态计数及报告文件名。
88
- - 补充第二台设备或另一个账号的文档导出验证记录,以区分匹配逻辑遗漏和源设备没有相应文件这两种情况;继续等待 Issue #11 报告者反馈。
89
-
90
- ### 验收标准
91
-
92
- - 所有格式对同一条消息给出的状态含义一致;复制失败不会仍显示“已导出”。
93
- - 重复运行不会把“本次新写入数”误报为“最终可用数”。
94
- - 局部范围导出不会删除其他范围已记录的媒体条目。
95
- - 自动化测试覆盖故障写入和重复运行;至少一份真实环境验收记录注明平台、客户端版本、成功数量和缺失数量,不包含真实聊天内容或个人路径。
96
-
97
- ### 可选扩展:离线资料包
98
-
99
- 统一清单后,可将现有消息导出、媒体资产、版本信息和覆盖摘要封装为可迁移目录或压缩包。第一版应只包含用户选定范围的数据,提供清单校验与离线打开说明;默认不加密格式变更、不上传、不自动同步。该任务应以现有导出能力为基础,避免再实现一套媒体匹配逻辑。
100
-
101
- ## P1:分批完善 `--json` 运行时错误
102
-
103
- ### 目标
104
-
105
- 机器调用时,无论成功还是失败,都能得到稳定的 JSON 结果和可判断的错误码;人类交互模式保持现有行为。
106
-
107
- ### 建议工作
108
-
109
- - 先按命令整理运行时失败场景:未初始化、找不到客户端、数据库不可读、权限不足、外部服务失败、输出文件不可写及用户取消。
110
- - 优先选取无真实账号、密钥和网络依赖的失败场景,补自动化回归;需要本机资源的场景记录为手工验收,不把开发机状态写入 CI 测试。
111
- - 对每个 `--json` 失败分支确认 stdout 只有一个机器可读 JSON 对象;日志和诊断文字进入 stderr,退出码与 `success` 状态一致。
112
- - 复用已有错误码,不为同类问题建立多个同义码;错误消息应可读,但不含数据库路径、密钥、账号标识和正文。
113
- - 逐项处理,不先用全局拦截器改造整个 Commander 出口;`--help`、`--version` 和提示信息必须保持兼容。
114
-
115
- ### 验收标准
116
-
117
- - 被纳入范围的命令在成功、预览和失败三种路径下都有明确 JSON 结构。
118
- - JSON 模式 stdout 不混入进度、彩色文本或普通错误行。
119
- - 每个修复场景至少有一个能够触发该失败的测试;测试不依赖真实本地数据库或个人配置。
120
- - README、操作手册和能力发现输出中的命令说明仍通过仓库的命令面检查。
121
-
122
- ## P2:提高搜索结果的可解释性
123
-
124
- **实测补充(2026-10-15)**:这台机器上按默认窗口建了索引(16,027 条)并跑了真实检索,本节要的几件事因此有了具体读数:
125
-
126
- - 重排在这台机器上是**一直不生效**的(Typesafe 返 `HTTP 451: not available in your region`)。这正是本节"执行元信息"
127
- 要解决的问题本身:现在 JSON 里**看不出**降级(没有 `reranked` / `degraded` 字段),终端上也看不见——CLI 不转发
128
- 子进程的 stderr,那行 WARN 只有直接跑 Python 时才有,于是"没报错"会被读成"重排过了"。
129
- - **引用定位已经有了**:`id` 是 `article:<相对路径>` 或聊天消息的 `id` + `time`,能回到本地原记录,且不含绝对路径
130
- (与本节"不要把完整绝对路径变成默认机器接口"一致)。
131
- - 另量到两件本节没写、但同属可解释性的事:**一次检索约 20 秒**,几乎全花在把 62 MB 的 `vectors.npy` 读进内存
132
- (没有 mmap);以及**同一篇文章会因为几个公众号都转载而在结果里重复出现**。两项都还没做。
133
- - **找到一个真洞,已修**:那 10,759 篇日报 md 里含 `## 正文` 的有 **0 篇** —— 取正文的判据从来没匹配上,于是送进
134
- embedding 的全是 YAML 头(抽样 300 篇:汉字占比中位 0.16)。"文章线只能靠标题排序"的原因在这里,不是截断。
135
- 已按真实结构改(0.16 → 0.80),并留了一条会因"退回老写法"而变红的测试;**索引要 `--full` 重建才生效**
136
- (增量只嵌新 id —— 这是本轮最容易误判成"已经修好了"的一处)。素材厚度另算:日报 md 只有 259 个汉字,
137
- 正文缓存 2,063、Vault 笔记 422,换不换是个独立取舍。
138
- - **建索引这条路也修了两处**(同一天实测踩出来的):`--full` 原来只给子进程 5 分钟超时,而全量重建要 20 分钟以上
139
- —— 那个开关在真实索引上**从来没跑完过**;而且原先是"攒到最后才写",超时/被杀等于把已经花掉的钱和时间一起丢。
140
- 现在每 100 批落一次盘(先向量后 meta、各走临时文件 + replace),被杀只留一个**有效**的半成品,重跑
141
- `search-index`(不加 `--full`)从断点续;失败批次(实测有 `IncompleteRead`)不再以全零向量入库(那会让那些 id
142
- 永久占位、再也不会被重嵌),改为在 `embedFailed` 里报数。顺带补了"meta 与向量行数不一致时按少的截断"——
143
- 不补的话越界会被 `search()` 的 `except` 吞成"静默退回关键词",一次真检索看起来像没命中。
144
-
145
- - 本节第 3 条那个**合成评估集已经有了**(2026-10-15):`scripts/recall_eval.py` 在运行时从记录自己的文本造题(碎片 / 标题两式,唯一性校验),指标走标准口径 + 覆盖判据;手写问句走仓库外的 TSV。但它**还不覆盖引用定位**(答案有没有落到具体段落),那一条仍缺。
146
-
147
- ### 目标
148
-
149
- 当语义搜索的重排服务不可用或被降级时,调用者能看出本次结果采用了哪条路径;检索结果能定位回原始消息或文章。
150
-
151
- ### 建议工作
152
-
153
- - 为搜索结果的机器输出增加简洁的执行元信息,例如向量检索是否执行、重排是否执行、是否降级及稳定错误原因。
154
- - 保持现有结果字段兼容;执行元信息作为可选字段增加,避免将服务暂时不可用伪装成成功重排。
155
- - 建立不含真实聊天内容的合成评估集,分别检查关键词命中、语义召回、重排和引用定位。
156
- - 在评估集证明收益前,不改变默认重排策略,也不为了得到一个完整索引而默认增加云端调用和费用。
157
- - 当返回引用时,提供足以回到本地原记录的稳定标识和时间信息;不要把完整绝对路径变成默认机器接口。
158
-
159
- ### 验收标准
160
-
161
- - 重排成功与降级时的 JSON 可以区分;终端输出也会说明降级原因。
162
- - 同一合成查询能验证命中、排序和引用对象,不依赖个人语料。
163
- - 额外云端发送仍需遵循现有预览、确认和隐私边界。
164
-
165
- ## P2:按真实消费者需求扩展只读 MCP
166
-
167
- ### 目标
168
-
169
- 让外部本地 Agent 能检查同步覆盖和任务结果,而无需解析 CLI 文本或直接读取状态文件。
170
-
171
- ### 建议工作
172
-
173
- - 先确认至少一个真实下游需要此能力,再将 `sync status`、任务结果或媒体覆盖摘要整理为只读 MCP 资源/工具。
174
- - MCP 与 CLI 共用现有服务层和校验,不另写一套同步状态解析器。
175
- - 为每个请求限制会话范围、时间范围、返回数量及字段;返回中不含密钥、绝对路径和聊天正文,除非具体工具明确提供且受相应确认协议保护。
176
- - 对不完整状态保留 `complete`、`unverified`、`partial` 的区别,不能将“未验证”显示成“完整”。
177
- - 增量游标只有在各相关后端都能验证正确性后,才作为稳定接口开放。当前可继续使用重叠时间窗与本地去重。
178
-
179
- ### 验收标准
180
-
181
- - MCP 与 CLI 对同一同步状态返回一致的覆盖信息。
182
- - 请求上限、未知会话、部分完成、未知 schema 和损坏状态文件均有明确结果。
183
- - 使用合成状态文件完成集成测试;默认能力边界与 `capabilities --json` 一致。
184
-
185
- ## P3:再评估的平台与 AI 扩展
186
-
187
- 这些方向需要先有明确用户需求或验证证据,暂不作为近期主线:
188
-
189
- - **本地模型:** 先通过能力检测和小规模体验验证基础检索/摘要质量,再考虑统一模型执行层;云端仍是显式配置和显式选择。
190
- - **日报阅读状态:** 如果用户确实需要跨日报恢复进度,再增加本地阅读标记、收藏和笔记关联;先定义可迁移的数据格式和备份方式。
191
- - **客户端兼容矩阵:** 将真实反馈沉淀为版本、平台、数据库类型和媒体覆盖的脱敏验收记录,优先修复高频兼容问题。
192
- - **公开开发接口:** 只有当外部项目确实需要在同一进程内复用能力时,再讨论稳定公共 API。现阶段 CLI/JSON/MCP 已是明确集成面,插件加载器会扩大代码权限范围。
193
-
194
- ## 明确不作为近期目标
195
-
196
- - 未验证的个人微信界面自动化、个人账号自动发信、拉群或群管理。
197
- - 默认云端同步、默认上传聊天数据或无人确认的云端分析。
198
- - 为了“插件生态”直接开放任意进程内代码加载。
199
- - 在各后端未提供可靠依据时承诺稳定消息游标或无遗漏同步。
200
- - 对找不到的图片、文档、语音或视频做猜测性匹配。
201
-
202
- ## 建议的拆分顺序
203
-
204
- | 顺序 | 可独立评审的工作项 | 主要依赖 | 完成信号 |
205
- | --- | --- | --- | --- |
206
- | 1 | 历史回填缓存语义与强制重抓选项 | 当前未提交的缓存改动 | 缓存命中、失败、刷新及日报复用均有测试 |
207
- | 2 | 媒体状态语义统一与复制失败回归 | 现有 manifest 与媒体报告 | 同一文件在报告、清单和导出结果中的状态一致 |
208
- | 3 | 第二环境的文件导出验收 | 可获得的第二账号/设备与授权 | 有可复核的脱敏计数和缺失分类 |
209
- | 4 | JSON 运行时错误分批审计 | 错误码和各命令现有分支 | 每批命令的失败 stdout、stderr、退出码均有测试 |
210
- | 5 | 搜索降级元信息和引用 | 现有搜索结果结构 | 调用者能识别重排未执行并定位来源 |
211
- | 6 | 只读 MCP 同步状态扩展 | 已存在的 sync 状态服务;明确下游需求 | CLI/MCP 一致性与权限测试通过 |
212
- | 7 | 资料包、阅读状态或本地模型试点 | 前序任务的真实使用反馈 | 有可量化需求、预算、边界和回滚方案 |
213
-
214
- 前三项是建议的下一轮范围。第 3 项依赖外部环境,若暂时没有第二设备,可先完成前两项与 JSON 错误审计,不应将“没有第二台设备”误报成代码验证通过。
215
-
216
- ## 每项任务的交付清单
217
-
218
- 每个实现任务在合并前应留下:
219
-
220
- - 一个明确的问题描述和用户可见行为变化;
221
- - 数据范围、网络请求、写入位置及权限边界;
222
- - 对应的回归测试或明确标记的人工验收记录;
223
- - 失败、部分完成、重试和重复运行的行为说明;
224
- - 同步更新必要的 `PROJECT_STATE.md`、`DECISIONS.md`、用户文档及发布说明;
225
- - 可通过恢复旧版本或重跑任务完成的回滚路径。
226
-
227
- ## 相关资料
228
-
229
- - [整体路线图](ROADMAP.md)
230
- - [项目当前状态](PROJECT_STATE.md)
231
- - [功能增强方案](FUNCTIONAL-IMPROVEMENT-SPEC.md)
232
- - [同步与任务状态契约](SYNC_CONTRACT.md)
233
- - [消息数据契约](DATA_CONTRACT.md)
234
- - [AI 接口与确认协议](AI_INTERFACE.md)
235
- - [扩展检查清单](EXTENDING.md)
236
- - [安全说明](../SECURITY.md)
1
+ # WeFlow CLI 下一阶段行动建议
2
+
3
+ > 编写日期:2026-10-14
4
+ > 依据:本地仓库 `package.json` 的 1.11.1 版本、截至本次梳理的提交与工作区状态。
5
+ > 用途:把近期改进方向拆成可以独立评审、实现和验收的任务。项目现状以 [PROJECT_STATE.md](PROJECT_STATE.md)、技术取舍以 [DECISIONS.md](DECISIONS.md) 为准。
6
+
7
+ ## 建议结论
8
+
9
+ 下一阶段应先完成三个“收口”任务:
10
+
11
+ 1. 让历史文章回填与日报共用缓存的行为可控、可验证,尤其补上强制重新抓取的入口。
12
+ 2. 统一不同导出格式的媒体状态语义,并补上导出失败和跨环境的验证证据。
13
+ 3. 分批补齐 CLI 在 `--json` 模式下的运行时错误结构,保持机器调用结果稳定。
14
+
15
+ 这三项都能建立在现有实现上,不需要引入新的数据处理架构。同步游标、MCP 扩面、资料包和更复杂的 AI 功能可在上述边界稳定后,根据实际集成需求推进。
16
+
17
+ ## 当前基线
18
+
19
+ - 本地代码版本为 `1.11.1`。最近一批提交完成了 Markdown 连图、文档本体导出和文档导出的多项边界修复。
20
+ - 本次读取时,本地 `master` 比 `origin/master` 多 11 个提交;工作区中 `scripts/backfill_articles.py` 和 `test/backfill_articles_test.py` 有未提交改动。它们正在让历史回填复用日报正文缓存,本文件将这部分视为进行中的工作,不把它描述为已发布功能。
21
+ - HTML 导出已有媒体覆盖报告;Markdown 和 JSON/TXT/Excel 的媒体导出复用同一份清单。文件本体导出目前只有本机实测记录,Issue #11 尚待报告者确认及其他环境验证。
22
+ - `sync run/status/verify` 和本地同步状态契约已经存在,但稳定游标尚未作为对外能力承诺。
23
+ - 项目已记录扩展边界:代码扩展在仓库内完成;外部程序通过 CLI、JSON 或 MCP 接入。近期不建议增加进程内插件加载器。
24
+
25
+ ## P0:完成正在进行的缓存衔接
26
+
27
+ **已完成(2026-10-14)**,验收的六类行为各有测试(命中不联网 / 未命中去抓 / 成功写缓存 / 失败不写 /
28
+ 强制重抓刷新旧缓存 / 重抓失败不动旧缓存 / 缓存不可写不影响这一篇 / 并发下标不错位),关键两条做过变异检查。
29
+ 落地的几处与本节设想不同的地方:回填与日报**共用同一条缓存**(`fetch_article_cached`,成功才写);
30
+ `--no-fetch-cache` 两边同名同义;`--refresh` 的帮助写明它只管"做哪些天"。另外**多做了一个标记**:
31
+ 抓取失败与"正文本来就短"从此分开记(`.articles.json` 的 `fetchFailed`,那天判为没做完、重跑只重试失败的篇)——
32
+ 它直接对应本节验收里"失败后重跑可继续补齐,不会将部分日期或部分文章误标为完整"那一条。
33
+ 判据与代价写在 D-108;顺带量到一件事:**接力是部分的**——日报对每篇有 url 的都抓正文,回填只抓"正文过短"的,
34
+ 2026-10-13 那天 485 篇里只有 145 篇进了缓存(详见 D-108)。
35
+
36
+ > **2026-10-16 补完:显式预取开关做了,但不在回填侧。** `daily --prefetch-bodies [n]`(默认关)在抓取阶段
37
+ > **之前**并发预热这份缓存,于是抓取阶段全是缓存命中、故意的 8–12 秒/篇节流不再触发(D-119)。
38
+ > 写过一个 `backfill_articles --prefetch-all`,**撤掉了**——它会产出同一天的文件、与 `daily` 抢同名。
39
+ > 同时量到一件反直觉的事并据此否掉了自己的提议:**让索引吃完整正文没有增益**(D-118),
40
+ > 所以这份缓存只服务展示路径(`search --with-text`)与日报耗时,**不服务检索**。
41
+
42
+ ### 目标
43
+
44
+ 使回填和日报共享正文缓存后,用户仍能明确选择复用缓存或重新抓取;重跑行为有测试保护,不会因旧缓存而悄悄使用过期正文。
45
+
46
+ ### 建议工作
47
+
48
+ - 为历史回填增加显式的缓存控制选项,例如允许用户绕过已有缓存重新抓取;参数名称和交互方式应与日报已有的 `--no-fetch-cache` 保持一致或清楚说明差别。
49
+ - 明确 `--refresh` 的语义:它目前用于重做已回填日期,不应让用户误以为它必定重新请求文章正文。
50
+ - 覆盖缓存命中、缓存未命中、抓取成功、抓取失败、强制重抓及并发抓取的行为。
51
+ - 继续只缓存非空成功正文;缓存不可写时回填仍应按现有约定完成,不因缓存辅助功能导致整批失败。
52
+ - 确认文档中所述的缓存目录、请求节流和“日报生成可复用历史正文”与代码一致。
53
+
54
+ ### 验收标准
55
+
56
+ - 默认回填会复用有效缓存,缓存命中时不访问网络。
57
+ - 用户显式选择重抓时,即使已有缓存也会访问正文来源,并以成功结果更新缓存。
58
+ - 抓取失败不会覆盖已有的有效缓存;没有旧缓存时,失败也不会生成空缓存文件。
59
+ - 失败后重跑可继续补齐,不会将部分日期或部分文章误标为完整。
60
+ - `test/backfill_articles_test.py` 和日报缓存相关测试覆盖以上行为;Python 脚本的参数帮助与实际行为一致。
61
+
62
+ ### 需要注意
63
+
64
+ 缓存只代表“曾成功抓到的正文”,不代表正文永远是最新版本。刷新入口应明确,而不应通过改变默认行为造成额外请求。
65
+
66
+ ## P1:统一导出媒体状态与验证口径
67
+
68
+ **基本完成(2026-10-14)**,**只差本节最后那条"第二台设备/另一个账号的验收记录"**(依赖外部环境,做不了)。
69
+ 已落地的:统一词汇(报告答"源数据里能不能定位"→ `found`/`missing`;清单与 CLI JSON 答"有没有落进导出目录"
70
+ → `written`/`copied`/`unavailable`,此后没有哪个词承担两种意思);`manifest.documents` 的 `exported` 改名为
71
+ `written`(此前与报告的 `exported` 同形不同义,拷贝失败时会让"已导出"变成假话);三种格式(html / md /
72
+ `--media`)的机器可读摘要收成**一个函数** `media_json_summary`,因此不会再各说各话,且报告文件名三处都有
73
+ (此前只有 HTML 那条给);回归测试覆盖"拷贝失败"(报告说 `found`、清单说 `unavailable`)、"重复运行"
74
+ (`written` 与 `copied` 分开,第二遍不误报 0)、"局部范围不吃掉宽范围的清单"(合并式写入),并断言摘要
75
+ **不含本机绝对路径**。仍未做:`ranges`(窄/宽)之外的状态读取兼容性只按现有 v1/v2 读取路径验过。
76
+
77
+ ### 目标
78
+
79
+ 让 HTML 报告、Markdown 清单及其他格式引用的媒体状态表达同一事实;用户可以区分“本地未找到”“已找到但未成功写出”和“已写入导出目录”。
80
+
81
+ ### 建议工作
82
+
83
+ - 盘点 `weflow-media-report/v1` 与 `weflow-media-manifest/v2` 中的状态、计数和含义,尤其核对文档文件的 `exported`、`found` 与实际写入结果。
84
+ - 选定统一语义:媒体是否可在源数据中定位、是否成功写入资产目录、是否仅在 HTML 内嵌,分别用清楚且不互相覆盖的字段表达。
85
+ - 保持已有 manifest 的读取兼容;如需更改 schema,采用增量字段或明确的版本升级策略,不悄悄改变旧字段含义。
86
+ - 为文件复制失败、重复导出、已有资产、窄日期范围覆盖已有宽范围清单等场景添加回归检查。
87
+ - 在不输出完整本地路径、聊天正文或密钥的前提下,让 JSON 操作结果能给出各状态计数及报告文件名。
88
+ - 补充第二台设备或另一个账号的文档导出验证记录,以区分匹配逻辑遗漏和源设备没有相应文件这两种情况;继续等待 Issue #11 报告者反馈。
89
+
90
+ ### 验收标准
91
+
92
+ - 所有格式对同一条消息给出的状态含义一致;复制失败不会仍显示“已导出”。
93
+ - 重复运行不会把“本次新写入数”误报为“最终可用数”。
94
+ - 局部范围导出不会删除其他范围已记录的媒体条目。
95
+ - 自动化测试覆盖故障写入和重复运行;至少一份真实环境验收记录注明平台、客户端版本、成功数量和缺失数量,不包含真实聊天内容或个人路径。
96
+
97
+ ### 可选扩展:离线资料包
98
+
99
+ 统一清单后,可将现有消息导出、媒体资产、版本信息和覆盖摘要封装为可迁移目录或压缩包。第一版应只包含用户选定范围的数据,提供清单校验与离线打开说明;默认不加密格式变更、不上传、不自动同步。该任务应以现有导出能力为基础,避免再实现一套媒体匹配逻辑。
100
+
101
+ ## P1:分批完善 `--json` 运行时错误
102
+
103
+ ### 目标
104
+
105
+ 机器调用时,无论成功还是失败,都能得到稳定的 JSON 结果和可判断的错误码;人类交互模式保持现有行为。
106
+
107
+ ### 建议工作
108
+
109
+ - 先按命令整理运行时失败场景:未初始化、找不到客户端、数据库不可读、权限不足、外部服务失败、输出文件不可写及用户取消。
110
+ - 优先选取无真实账号、密钥和网络依赖的失败场景,补自动化回归;需要本机资源的场景记录为手工验收,不把开发机状态写入 CI 测试。
111
+ - 对每个 `--json` 失败分支确认 stdout 只有一个机器可读 JSON 对象;日志和诊断文字进入 stderr,退出码与 `success` 状态一致。
112
+ - 复用已有错误码,不为同类问题建立多个同义码;错误消息应可读,但不含数据库路径、密钥、账号标识和正文。
113
+ - 逐项处理,不先用全局拦截器改造整个 Commander 出口;`--help`、`--version` 和提示信息必须保持兼容。
114
+
115
+ ### 验收标准
116
+
117
+ - 被纳入范围的命令在成功、预览和失败三种路径下都有明确 JSON 结构。
118
+ - JSON 模式 stdout 不混入进度、彩色文本或普通错误行。
119
+ - 每个修复场景至少有一个能够触发该失败的测试;测试不依赖真实本地数据库或个人配置。
120
+ - README、操作手册和能力发现输出中的命令说明仍通过仓库的命令面检查。
121
+
122
+ ## P2:提高搜索结果的可解释性
123
+
124
+ **实测补充(2026-10-15)**:这台机器上按默认窗口建了索引(16,027 条)并跑了真实检索,本节要的几件事因此有了具体读数:
125
+
126
+ - 重排在这台机器上是**一直不生效**的(Typesafe 返 `HTTP 451: not available in your region`)。这正是本节"执行元信息"
127
+ 要解决的问题本身:现在 JSON 里**看不出**降级(没有 `reranked` / `degraded` 字段),终端上也看不见——CLI 不转发
128
+ 子进程的 stderr,那行 WARN 只有直接跑 Python 时才有,于是"没报错"会被读成"重排过了"。
129
+ - **引用定位已经有了**:`id` 是 `article:<相对路径>` 或聊天消息的 `id` + `time`,能回到本地原记录,且不含绝对路径
130
+ (与本节"不要把完整绝对路径变成默认机器接口"一致)。
131
+ - 另量到两件本节没写、但同属可解释性的事:**一次检索约 20 秒**,几乎全花在把 62 MB 的 `vectors.npy` 读进内存
132
+ (没有 mmap);以及**同一篇文章会因为几个公众号都转载而在结果里重复出现**。两项都还没做。
133
+ - **找到一个真洞,已修**:那 10,759 篇日报 md 里含 `## 正文` 的有 **0 篇** —— 取正文的判据从来没匹配上,于是送进
134
+ embedding 的全是 YAML 头(抽样 300 篇:汉字占比中位 0.16)。"文章线只能靠标题排序"的原因在这里,不是截断。
135
+ 已按真实结构改(0.16 → 0.80),并留了一条会因"退回老写法"而变红的测试;**索引要 `--full` 重建才生效**
136
+ (增量只嵌新 id —— 这是本轮最容易误判成"已经修好了"的一处)。素材厚度另算:日报 md 只有 259 个汉字,
137
+ 正文缓存 2,063、Vault 笔记 422,换不换是个独立取舍。
138
+ - **建索引这条路也修了两处**(同一天实测踩出来的):`--full` 原来只给子进程 5 分钟超时,而全量重建要 20 分钟以上
139
+ —— 那个开关在真实索引上**从来没跑完过**;而且原先是"攒到最后才写",超时/被杀等于把已经花掉的钱和时间一起丢。
140
+ 现在每 100 批落一次盘(先向量后 meta、各走临时文件 + replace),被杀只留一个**有效**的半成品,重跑
141
+ `search-index`(不加 `--full`)从断点续;失败批次(实测有 `IncompleteRead`)不再以全零向量入库(那会让那些 id
142
+ 永久占位、再也不会被重嵌),改为在 `embedFailed` 里报数。顺带补了"meta 与向量行数不一致时按少的截断"——
143
+ 不补的话越界会被 `search()` 的 `except` 吞成"静默退回关键词",一次真检索看起来像没命中。
144
+
145
+ - 本节第 3 条那个**合成评估集已经有了**(2026-10-15):`scripts/recall_eval.py` 在运行时从记录自己的文本造题(碎片 / 标题两式,唯一性校验),指标走标准口径 + 覆盖判据;手写问句走仓库外的 TSV。但它**还不覆盖引用定位**(答案有没有落到具体段落),那一条仍缺。
146
+
147
+ ### 目标
148
+
149
+ 当语义搜索的重排服务不可用或被降级时,调用者能看出本次结果采用了哪条路径;检索结果能定位回原始消息或文章。
150
+
151
+ ### 建议工作
152
+
153
+ - 为搜索结果的机器输出增加简洁的执行元信息,例如向量检索是否执行、重排是否执行、是否降级及稳定错误原因。
154
+ - 保持现有结果字段兼容;执行元信息作为可选字段增加,避免将服务暂时不可用伪装成成功重排。
155
+ - 建立不含真实聊天内容的合成评估集,分别检查关键词命中、语义召回、重排和引用定位。
156
+ - 在评估集证明收益前,不改变默认重排策略,也不为了得到一个完整索引而默认增加云端调用和费用。
157
+ - 当返回引用时,提供足以回到本地原记录的稳定标识和时间信息;不要把完整绝对路径变成默认机器接口。
158
+
159
+ ### 验收标准
160
+
161
+ - 重排成功与降级时的 JSON 可以区分;终端输出也会说明降级原因。
162
+ - 同一合成查询能验证命中、排序和引用对象,不依赖个人语料。
163
+ - 额外云端发送仍需遵循现有预览、确认和隐私边界。
164
+
165
+ ## P2:按真实消费者需求扩展只读 MCP
166
+
167
+ ### 目标
168
+
169
+ 让外部本地 Agent 能检查同步覆盖和任务结果,而无需解析 CLI 文本或直接读取状态文件。
170
+
171
+ ### 建议工作
172
+
173
+ - 先确认至少一个真实下游需要此能力,再将 `sync status`、任务结果或媒体覆盖摘要整理为只读 MCP 资源/工具。
174
+ - MCP 与 CLI 共用现有服务层和校验,不另写一套同步状态解析器。
175
+ - 为每个请求限制会话范围、时间范围、返回数量及字段;返回中不含密钥、绝对路径和聊天正文,除非具体工具明确提供且受相应确认协议保护。
176
+ - 对不完整状态保留 `complete`、`unverified`、`partial` 的区别,不能将“未验证”显示成“完整”。
177
+ - 增量游标只有在各相关后端都能验证正确性后,才作为稳定接口开放。当前可继续使用重叠时间窗与本地去重。
178
+
179
+ ### 验收标准
180
+
181
+ - MCP 与 CLI 对同一同步状态返回一致的覆盖信息。
182
+ - 请求上限、未知会话、部分完成、未知 schema 和损坏状态文件均有明确结果。
183
+ - 使用合成状态文件完成集成测试;默认能力边界与 `capabilities --json` 一致。
184
+
185
+ ## P3:再评估的平台与 AI 扩展
186
+
187
+ 这些方向需要先有明确用户需求或验证证据,暂不作为近期主线:
188
+
189
+ - **本地模型:** 先通过能力检测和小规模体验验证基础检索/摘要质量,再考虑统一模型执行层;云端仍是显式配置和显式选择。
190
+ - **日报阅读状态:** 如果用户确实需要跨日报恢复进度,再增加本地阅读标记、收藏和笔记关联;先定义可迁移的数据格式和备份方式。
191
+ - **客户端兼容矩阵:** 将真实反馈沉淀为版本、平台、数据库类型和媒体覆盖的脱敏验收记录,优先修复高频兼容问题。
192
+ - **公开开发接口:** 只有当外部项目确实需要在同一进程内复用能力时,再讨论稳定公共 API。现阶段 CLI/JSON/MCP 已是明确集成面,插件加载器会扩大代码权限范围。
193
+
194
+ ## 明确不作为近期目标
195
+
196
+ - 未验证的个人微信界面自动化、个人账号自动发信、拉群或群管理。
197
+ - 默认云端同步、默认上传聊天数据或无人确认的云端分析。
198
+ - 为了“插件生态”直接开放任意进程内代码加载。
199
+ - 在各后端未提供可靠依据时承诺稳定消息游标或无遗漏同步。
200
+ - 对找不到的图片、文档、语音或视频做猜测性匹配。
201
+
202
+ ## 建议的拆分顺序
203
+
204
+ | 顺序 | 可独立评审的工作项 | 主要依赖 | 完成信号 |
205
+ | --- | --- | --- | --- |
206
+ | 1 | 历史回填缓存语义与强制重抓选项 | 当前未提交的缓存改动 | 缓存命中、失败、刷新及日报复用均有测试 |
207
+ | 2 | 媒体状态语义统一与复制失败回归 | 现有 manifest 与媒体报告 | 同一文件在报告、清单和导出结果中的状态一致 |
208
+ | 3 | 第二环境的文件导出验收 | 可获得的第二账号/设备与授权 | 有可复核的脱敏计数和缺失分类 |
209
+ | 4 | JSON 运行时错误分批审计 | 错误码和各命令现有分支 | 每批命令的失败 stdout、stderr、退出码均有测试 |
210
+ | 5 | 搜索降级元信息和引用 | 现有搜索结果结构 | 调用者能识别重排未执行并定位来源 |
211
+ | 6 | 只读 MCP 同步状态扩展 | 已存在的 sync 状态服务;明确下游需求 | CLI/MCP 一致性与权限测试通过 |
212
+ | 7 | 资料包、阅读状态或本地模型试点 | 前序任务的真实使用反馈 | 有可量化需求、预算、边界和回滚方案 |
213
+
214
+ 前三项是建议的下一轮范围。第 3 项依赖外部环境,若暂时没有第二设备,可先完成前两项与 JSON 错误审计,不应将“没有第二台设备”误报成代码验证通过。
215
+
216
+ ## 每项任务的交付清单
217
+
218
+ 每个实现任务在合并前应留下:
219
+
220
+ - 一个明确的问题描述和用户可见行为变化;
221
+ - 数据范围、网络请求、写入位置及权限边界;
222
+ - 对应的回归测试或明确标记的人工验收记录;
223
+ - 失败、部分完成、重试和重复运行的行为说明;
224
+ - 同步更新必要的 `PROJECT_STATE.md`、`DECISIONS.md`、用户文档及发布说明;
225
+ - 可通过恢复旧版本或重跑任务完成的回滚路径。
226
+
227
+ ## 相关资料
228
+
229
+ - [整体路线图](ROADMAP.md)
230
+ - [项目当前状态](PROJECT_STATE.md)
231
+ - [功能增强方案](FUNCTIONAL-IMPROVEMENT-SPEC.md)
232
+ - [同步与任务状态契约](SYNC_CONTRACT.md)
233
+ - [消息数据契约](DATA_CONTRACT.md)
234
+ - [AI 接口与确认协议](AI_INTERFACE.md)
235
+ - [扩展检查清单](EXTENDING.md)
236
+ - [安全说明](../SECURITY.md)