weflow-cli 1.9.0 → 1.11.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/ARCHITECTURE.md +62 -26
- package/CHANGELOG.md +1051 -0
- package/OPERATIONS.md +99 -13
- package/README.en.md +14 -5
- package/README.md +23 -8
- package/bin/weflow-cli.ts +364 -40
- package/dist/bin/weflow-cli.js +381 -69
- package/dist/bin/weflow-cli.js.map +1 -1
- package/dist/mcp-server/index.d.ts.map +1 -1
- package/dist/mcp-server/index.js +19 -1
- package/dist/mcp-server/index.js.map +1 -1
- package/dist/src/core/dbPathService.d.ts +12 -0
- package/dist/src/core/dbPathService.d.ts.map +1 -1
- package/dist/src/core/dbPathService.js +20 -3
- package/dist/src/core/dbPathService.js.map +1 -1
- package/dist/src/panel/server.d.ts.map +1 -1
- package/dist/src/panel/server.js +35 -0
- package/dist/src/panel/server.js.map +1 -1
- package/dist/src/services/assistantService.d.ts +19 -0
- package/dist/src/services/assistantService.d.ts.map +1 -1
- package/dist/src/services/assistantService.js +20 -0
- package/dist/src/services/assistantService.js.map +1 -1
- package/dist/src/services/assistantTools.d.ts +27 -1
- package/dist/src/services/assistantTools.d.ts.map +1 -1
- package/dist/src/services/assistantTools.js +169 -35
- package/dist/src/services/assistantTools.js.map +1 -1
- package/dist/src/services/configService.d.ts +2 -0
- package/dist/src/services/configService.d.ts.map +1 -1
- package/dist/src/services/configService.js +3 -2
- package/dist/src/services/configService.js.map +1 -1
- package/dist/src/services/exportService.d.ts +43 -0
- package/dist/src/services/exportService.d.ts.map +1 -1
- package/dist/src/services/exportService.js +116 -11
- package/dist/src/services/exportService.js.map +1 -1
- package/dist/src/services/messageQuery.d.ts +18 -0
- package/dist/src/services/messageQuery.d.ts.map +1 -1
- package/dist/src/services/messageQuery.js +29 -0
- package/dist/src/services/messageQuery.js.map +1 -1
- package/dist/src/services/wechatClient.d.ts +125 -0
- package/dist/src/services/wechatClient.d.ts.map +1 -0
- package/dist/src/services/wechatClient.js +344 -0
- package/dist/src/services/wechatClient.js.map +1 -0
- package/dist/src/services/wechatMedia.d.ts +44 -0
- package/dist/src/services/wechatMedia.d.ts.map +1 -0
- package/dist/src/services/wechatMedia.js +155 -0
- package/dist/src/services/wechatMedia.js.map +1 -0
- package/dist/src/services/wechatMessageService.d.ts +11 -0
- package/dist/src/services/wechatMessageService.d.ts.map +1 -1
- package/dist/src/services/wechatMessageService.js +55 -11
- package/dist/src/services/wechatMessageService.js.map +1 -1
- package/dist/src/types.d.ts +4 -0
- package/dist/src/types.d.ts.map +1 -1
- package/docs/CONTACT_DB_SCHEMA.md +1085 -0
- package/docs/DECISIONS.md +1274 -0
- package/docs/EXTENDING.md +69 -7
- package/docs/FUNCTIONAL-IMPROVEMENT-SPEC.md +27 -0
- package/docs/HEALTH-CHECK.md +12 -7
- package/docs/JEV/345/272/224/347/224/250/346/226/275/345/267/245/346/226/207/346/241/243.md +2 -2
- package/docs/MCP.md +2 -2
- package/docs/PROJECT_STATE.md +64 -5
- package/docs/RELEASING.md +128 -1
- package/docs/images/weflow-architecture-gpt-image-2.png +0 -0
- package/logo.png +0 -0
- package/mcp-server/index.ts +18 -3
- package/package.json +5 -3
- package/resources/js/graph3d/NOTICE.txt +35 -0
- package/resources/js/graph3d/d3-binarytree.min.js +2 -0
- package/resources/js/graph3d/d3-dispatch.min.js +2 -0
- package/resources/js/graph3d/d3-force-3d.min.js +2 -0
- package/resources/js/graph3d/d3-octree.min.js +2 -0
- package/resources/js/graph3d/d3-quadtree.min.js +2 -0
- package/resources/js/graph3d/d3-timer.min.js +2 -0
- package/resources/js/graph3d/layout.mjs +63 -0
- package/resources/js/graph3d/three.min.js +6 -0
- package/resources/js/graph3d/viewer2d.js +448 -0
- package/resources/panel/index.html +12 -0
- package/resources/panel/mascot-blink-1.png +0 -0
- package/resources/panel/mascot-blink-2.png +0 -0
- package/resources/panel/mascot-lift-down-1.png +0 -0
- package/resources/panel/mascot-lift-down-2.png +0 -0
- package/resources/panel/mascot-lift-down-3.png +0 -0
- package/resources/panel/mascot-lift-down-4.png +0 -0
- package/resources/panel/mascot-lift-down-5.png +0 -0
- package/resources/panel/mascot-lift-down-6.png +0 -0
- package/resources/panel/mascot-lift-up-1.png +0 -0
- package/resources/panel/mascot-lift-up-2.png +0 -0
- package/resources/panel/mascot-lift-up-3.png +0 -0
- package/resources/panel/mascot-lift-up-4.png +0 -0
- package/resources/panel/mascot-lift-up-5.png +0 -0
- package/resources/panel/mascot-lift-up-6.png +0 -0
- package/resources/panel/mascot-tickle-1.png +0 -0
- package/resources/panel/mascot-tickle-2.png +0 -0
- package/resources/panel/mascot-tickle-3.png +0 -0
- package/resources/panel/mascot-tickle-4.png +0 -0
- package/resources/panel/panel.css +111 -0
- package/resources/panel/renderer.js +480 -8
- package/scripts/_utils.py +1203 -977
- package/scripts/biz_daily.py +25 -10
- package/scripts/chat_notes.py +15 -5
- package/scripts/check_readme_commands.py +426 -0
- package/scripts/compile_wiki.py +163 -57
- package/scripts/contact_schema.py +339 -0
- package/scripts/data/wechat_emoji.json +225 -0
- package/scripts/export_chat_html.py +346 -6
- package/scripts/fav_notes.py +4 -1
- package/scripts/graph_2d.py +151 -0
- package/scripts/graph_3d.py +646 -0
- package/scripts/health_check.py +163 -26
- package/scripts/nt_decrypt.py +3 -3
- package/scripts/panel_frames.py +683 -0
- package/scripts/pipeline.py +21 -10
- package/scripts/quality_eval.py +5 -0
- package/scripts/rag_chat.py +33 -16
- package/scripts/reply_debt.py +26 -6
- package/scripts/semantic_search.py +212 -58
- package/scripts/vault_rag.py +42 -16
- package/scripts/vault_search.py +44 -8
- package/scripts/wechat_emoticon.py +6 -0
- package/scripts/wiki_lint.py +94 -17
- package/src/core/dbPathService.ts +22 -4
- package/src/panel/server.ts +33 -0
- package/src/services/assistantService.ts +26 -0
- package/src/services/assistantTools.ts +2452 -2319
- package/src/services/configService.ts +5 -2
- package/src/services/exportService.ts +129 -12
- package/src/services/messageQuery.ts +29 -0
- package/src/services/wechatClient.ts +380 -0
- package/src/services/wechatMedia.ts +166 -0
- package/src/services/wechatMessageService.ts +62 -11
- package/src/types.ts +4 -0
- package/dist/src/utils/wechatEmoji.d.ts +0 -5
- package/dist/src/utils/wechatEmoji.d.ts.map +0 -1
- package/dist/src/utils/wechatEmoji.js +0 -35
- package/dist/src/utils/wechatEmoji.js.map +0 -1
package/OPERATIONS.md
CHANGED
|
@@ -39,14 +39,18 @@ weflow-cli init
|
|
|
39
39
|
weflow-cli init --refresh
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
数据目录不在常见位置时,`init` 按**可信度**递减来找 —— **先问在跑的客户端**(它的命令行上带着
|
|
43
|
+
`--wechat-files-path`,是唯一"来自客户端自己"的来源,其余都是按目录名猜),找到了会写明是哪种来源;
|
|
44
|
+
找不到再按成本递增试:
|
|
43
45
|
|
|
44
46
|
```powershell
|
|
45
|
-
weflow-cli init --path "D:\WeChatData"
|
|
46
|
-
weflow-cli init --search-drives
|
|
47
|
-
weflow-cli init --full-scan
|
|
47
|
+
weflow-cli init --path "D:\WeChatData" # 你直接告诉它
|
|
48
|
+
weflow-cli init --search-drives # 跨盘按目录名找
|
|
49
|
+
weflow-cli init --full-scan # 名字也没命中时按结构扫
|
|
48
50
|
```
|
|
49
51
|
|
|
52
|
+
(客户端没在跑就没有那条线索,`init` 照旧从常见位置开始 —— 不会因此失败。)
|
|
53
|
+
|
|
50
54
|
`--path` 可以指向微信数据根目录、账号目录或其 `db_storage` 目录。全盘结构搜索可能耗时较长,且会枚举更多本地目录,只有前两种方式找不到时再使用。
|
|
51
55
|
|
|
52
56
|
测试“密钥缺失但不破坏当前配置”的首次初始化流程:
|
|
@@ -68,6 +72,8 @@ weflow-cli init --refresh
|
|
|
68
72
|
weflow-cli config show
|
|
69
73
|
weflow-cli sessions -n 10
|
|
70
74
|
weflow-cli contacts -k "关键词"
|
|
75
|
+
weflow-cli contact-schema -n 3 # 读群 ext_buffer 里**已验证**的字段(成员/status/inviter)
|
|
76
|
+
weflow-cli contact-schema --contacts -n 5 # 改看联系人:地区码 / 服务类型 / 资料更新时间(#4/#9 是账号资料文本,不打印)
|
|
71
77
|
weflow-cli messages "联系人A" -n 10
|
|
72
78
|
```
|
|
73
79
|
|
|
@@ -80,7 +86,36 @@ weflow-cli export "联系人A" html --output ./output
|
|
|
80
86
|
weflow-cli export "联系人A" json --output ./output
|
|
81
87
|
```
|
|
82
88
|
|
|
83
|
-
支持 `json`、`txt`、`md
|
|
89
|
+
支持 `json`、`txt`、`html`、`md` 和 `excel` 五种。**媒体匹配只做一遍**:`md` 导出是那个"抽取者"——
|
|
90
|
+
图片落盘到 `<输出>/<会话>_assets/`、**文档本体按原名与扩展名拷进 `<会话>_assets/files/`**,同时写一份
|
|
91
|
+
`manifest.json`;随后在同一输出目录里导出 `json`/`txt`/`excel`,它们会**自动**带上同样的路径(`json`
|
|
92
|
+
每条多 `media`,文档还多 `mediaKind`/`mediaName`;`txt` 里是 `[图片: <相对路径>]` / `[文件: 名字 (路径)]`;
|
|
93
|
+
`excel` 多一列「媒体」)。**不想分两步就给 `--media`**:`json`/`txt`/`excel` 会先自己抽一次(同一份清单,
|
|
94
|
+
且**吃同一个 `--limit`/`--date`**),命令只有一条:
|
|
95
|
+
`weflow-cli export "某人" json --media`。没跑过 `md` 导出也没给 `--media` 时,这三种格式与从前一致
|
|
96
|
+
(图片位置是 `[图片]` 这样的占位)。清单的键是 `local_id:create_time` —— **`local_id` 会在分片之间重复**(同一会话
|
|
97
|
+
的表可能存在于多个分片、各片自己编号),只按它会引用到别的消息的图。清单 schema 是 `weflow-media-manifest/v2`
|
|
98
|
+
(值是带 `kind` 的对象);磁盘上留着的 v1(裸字符串)仍读得出来,升级不必重跑导出。
|
|
99
|
+
|
|
100
|
+
**文档本体是纯拷贝,不重编码、不改名**(只清洗文件名里的非法字符)。消息里只有名字与 md5,文件在账号目录的
|
|
101
|
+
`msg/file/YYYY-MM/` 下,按 `(归一化名, 字节数)` 对上,同名多份时用 md5 定。本机实测 1,855 条文件消息里
|
|
102
|
+
**1,643 条对得上(88.6%)**,其余 212 条本地确实没有那份文件(没下载过或已清理)—— 这些消息仍是
|
|
103
|
+
`[文件] 名字` 的标签,不清单里凑数、也不猜。导出的计数里 `exported` 是"这份文档在 assets 里",
|
|
104
|
+
`written` 才是"这次新拷了几个",别把后者当成前者的成绩。
|
|
105
|
+
|
|
106
|
+
**HTML 导出(含 `--full-images`)不写文件本体**:HTML 的用法是"单文件可分享",把几 MB 的 PDF 内嵌成
|
|
107
|
+
base64 既没人打得开、也把网页撑大。要在文件本体上要文档,用 `md` 或 `json|txt|excel --media`。
|
|
108
|
+
(`--media` 会把文档拷进输出目录,几百份的时代价几十到几百 MB,先看一眼 `msg/file` 的规模再按整段历史跑。)
|
|
109
|
+
|
|
110
|
+
**动图(GIF)会照原样带出来**:落盘的文件名按**字节**定扩展名(`.gif`/`.png`/`.jpg`/`.webp`),内容不动 ——
|
|
111
|
+
实测一段真实会话里 556 张图有 87 个是 GIF(带动画扩展的 84 个),markdown 里就是 `.gif`、HTML 里是
|
|
112
|
+
`data:image/gif`。`--full-images` 那档也**不会**把动画 GIF 压成静态图(`wechat_image.shrink` 对动画 GIF
|
|
113
|
+
直接原样穿过,理由写在它的注释里:PIL 只解第一帧,重编码会把"发的人看到在动"变成一张静止图)。
|
|
114
|
+
|
|
115
|
+
HTML 导出会尽力匹配本地图片、表情、公众号卡片和其他媒体(内嵌,单文件可分享,并给出一份媒体覆盖报告);
|
|
116
|
+
匹配不到时应显示类型或占位信息,不应从其他会话猜图。`.pdf`/`.docx` 这类文件消息在 HTML 里是一张标题卡片
|
|
117
|
+
(HTML 刻意不嵌文件本体,理由见上一段);文件本体走 `md` 或 `--media`。跨分片数据尤其要保留
|
|
118
|
+
原始导出和完整上下文,导出后请人工抽查发送者、时间和媒体对应关系。
|
|
84
119
|
|
|
85
120
|
### 导出耗时与远程媒体
|
|
86
121
|
|
|
@@ -89,7 +124,10 @@ HTML 导出的时间几乎全部花在远程媒体上(公众号封面、B 站
|
|
|
89
124
|
- 同一会话的**重复导出接近瞬时**(实测 1614 条约 2 秒);首次导出才是真正要付网络成本的。
|
|
90
125
|
- 首次导出会先做一遍**只记录 URL、不联网**的扫描,再用 24 线程并发取回,最后用热缓存正式生成。逐条串行取回会慢一个数量级。
|
|
91
126
|
- `.cover-cache/` 可以随时删除,删了只会退回「首次导出」的耗时,不会影响产出内容。
|
|
92
|
-
-
|
|
127
|
+
- 默认嵌入的是微信缓存里的**缩略图**;加 `--full-images` 会改用**原图作为来源**(原图常有 5–24MB、3000+px,
|
|
128
|
+
`wechat_image.shrink` 处理它们要数分钟)。**两档嵌入前都会按上限缩放**,所以导出物体积不会因为这一档变成几百 MB
|
|
129
|
+
——2026-10-13 实测同一会话两档:HTML 体积 2.0 MB vs 1.5 MB、图片像素分布基本一致(`--full-images` 让 4 张的来源
|
|
130
|
+
从缓存缩略图换成了原图 ⇒ 720px 的那批从 10 张变成 14 张)。它的价值在**那几张缩略图本来就小**的会话上。
|
|
93
131
|
|
|
94
132
|
### 图片显示为 `[图片]`、群聊看不出谁在说话
|
|
95
133
|
|
|
@@ -298,7 +336,7 @@ python scripts/quality_eval.py consistency ~/.weflow-cli/labels/labels-<时间
|
|
|
298
336
|
|
|
299
337
|
**清单是盲的**:`sample` 打印给你的那张表**不印 Jev 的答案**(只有日期与历史标注)。
|
|
300
338
|
先看见模型说了什么,人就会往它靠,测出来的"一致率"会偏高——而偏高的量无法估计。
|
|
301
|
-
`topicConfidence`/`relevanceScore`/`includeScore`
|
|
339
|
+
`topicConfidence`/`relevanceScore`/`includeScore` **只在被判断层判过的那篇文章上存在**(它们由 `_apply_decision` 从判断结果写进去)。走 LLM 回退路径的文章没有这几个分 ——所以判断层按地区不可用(见下面的 451)时,日报里整批都没有它们;标注时别翻它。
|
|
302
340
|
|
|
303
341
|
`score` 会给出四件事:
|
|
304
342
|
|
|
@@ -416,9 +454,11 @@ weflow-cli search-index --days 3650 --article-days 365 --yes # 要"整段历
|
|
|
416
454
|
| `weflow-cli user-notes --limit N --yes` | **你自己写的**笔记发给 DeepSeek(每篇一次) | 你的笔记**只读、绝不修改**;卡上标 `summary_by: model`(那是模型的理解,不是你的原话);**你笔记里的 `[[链接]]` 优先** |
|
|
417
455
|
| `weflow-cli wiki compile --source … --min-refs 2 --yes` | 概念发给 DeepSeek(每个概念一次) | `--min-refs 2` 滤掉只被一篇提到的一次性实体 |
|
|
418
456
|
| `weflow-cli wiki compile --refresh-sources --yes` | **不出境** | 只把**已有页**的「来源」段补齐成当前全部来源(本地重写)。**拉完新文章要跑这一条**,否则新文章提到老概念时,那一页不会多出这条边 |
|
|
457
|
+
| `weflow-cli wiki compile --qualify-links --dry-run` | **不出境** | 两条线同名(本机 36 个)时,把指向它们的链接改成带路径的 `[[Chat/Concepts/DeepSeek|DeepSeek]]` —— 否则 Obsidian 里那条裸链接会**命中另一条线**的那张。只改同名的、不碰「来源」段;幂等,重跑不改第二遍。本机实测 539 条 / 477 张页 |
|
|
419
458
|
| `weflow-cli wiki compile --merge-duplicates --dry-run` | **不出境** | 把「规范化后同名」的多张页合并成一张(`GPT 5.6`/`GPT-5.6`/`GPT5.6`)。留来源最多的那张,其余名字进 `aliases`——**指向旧名字的链接一条都不断**,不必改别的文件。**它会删页**,先跑 `--dry-run` 看名单 |
|
|
420
459
|
| `weflow-cli wiki compile --pages-from-cards --cards <线> --dry-run` | **不出境** | 给还没有页的概念建页:定义复用卡片里那句原话、相关概念取共现。**必须指定 `--cards`**(一条线一条线建,否则聊天线会被建进文章线) |
|
|
421
|
-
| `weflow-cli wiki lint` | **不出境** | 断链 / 孤儿 / 空页 /
|
|
460
|
+
| `weflow-cli wiki lint` | **不出境** | 断链 / 孤儿 / 空页 / **同一条线内**的同名 / **二义链接**(`ambiguousLinks`,修法见下一行的 `--qualify-links`)/ 近似重名 / 退化字段;两条线都有同一个概念名会**单列一节**报出来(`crossLineSameName` —— 设计如此,不是要修的东西)。不传 `--dir` 就体检清单里的全部线 |
|
|
461
|
+
| `weflow-cli wiki graph --open` | **不出境** | 把概念图谱导成一张**自包含**的 3D 页面(`output/knowledge-graph-3d.html`,本机 49,956 个概念约 9MB,**双击就能逛,不需要起服务器**)。库、数据、坐标全部内联进去,所以它不联网 —— `file://` 下 `fetch` 会被 CORS 挡死,而引 CDN 又会把"本地优先"变成"要有网"。坐标是构建期用 Node 算好缓存的(`output/.graph3d-cache/`),只改渲染不会重算;先看规模用 `--dry-run`。**`--min-degree N`** 只画**在原图里**连接数 ≥N 的概念(去掉细枝看骨架:本机 ≥10 只剩 **3,825 点 / 1.09MB**,全量是 5 万点 / 9MB —— 5 万点时那张图看不清,不是不好看,是布局本身就糊);**`--line wiki|chat`** 只画一条线(文章线 4.8 万 / 聊天线 1,527,两套概念口径不同,混在一起看不出结构)。两者都只改**给页面看的点集**;坐标按图内容分槽缓存(`graph-<hash>.json`),核心图与全量图来回切都不用重算。**`--flat`** 出 2D 版(canvas 平面图,更像 Obsidian 那种;默认写到 `output/knowledge-graph-2d.html`):布局同样是构建期算好,但**按 2D 重算**而不是把 3D 的 x/y 拍扁(z 那一维也承载结构,拍扁会把两团不相干的点叠在一起),而且它**一个库都不引**(渲染是裸 canvas)。2D 的快得多:3,825 点 250 tick 只要 2.4 秒,页面 0.71MB(3D 同图 1.34MB)。 |
|
|
422
462
|
|
|
423
463
|
四条卡片来源(文章 / 聊天 / 收藏 / 你自己的笔记)产出的东西是**同一种形状**(带 frontmatter +
|
|
424
464
|
`## AI 摘要` + `[[概念]] — 说明`),所以 `wiki compile` 一视同仁——再加一条来源时改的是产卡那一步,
|
|
@@ -442,6 +482,12 @@ weflow-cli wiki compile --source ./output/chat-notes --output ./output/wechat-va
|
|
|
442
482
|
- **`--output` 要指到 `Chat/Concepts`**:文章线与聊天线在库里是**两个目录**(`Wiki/` 与 `Chat/`,
|
|
443
483
|
同一个 Obsidian 库)。`wiki compile` 一次只产一条线的页,默认写文章线——用默认值跑聊天线,
|
|
444
484
|
两边的页会混进同一个目录,而图谱里就再也分不出"我读到的"和"我们聊过的"。
|
|
485
|
+
- **跨线同名不再跳过**(2026-10-10 起):两条线各留一张 `DeepSeek` 是设计,图谱里它们标着各自的
|
|
486
|
+
线。**代价**:Obsidian 里 `[[DeepSeek]]` 这条**裸链接未必命中你想要的那一张**(官方判据:有同名
|
|
487
|
+
文件时会 deterministic 地解析,但不保证是哪一张;自带路径的 `[[Chat/Concepts/DeepSeek]]` 才确定)。
|
|
488
|
+
这个代价**已经按"同库内消歧"修掉了**:`weflow-cli wiki compile --qualify-links` 把指向同名的链接
|
|
489
|
+
改成带路径的形式(本机 539 条 / 477 张页,幂等)。**新出现的同名要重跑它** —— 体检的
|
|
490
|
+
`ambiguousLinks` 那一节就是盯着这件事的(列出来并给出命令)。
|
|
445
491
|
- 三种形状自然落下来:**按会话的知识卡**就是第一步入库的那些卡;**主题汇总**与
|
|
446
492
|
**人物/时间线**是第二步把卡里的 `[[话题]]`/`[[人名]]` 聚出来的概念页。
|
|
447
493
|
- **文章线要先用一道提炼**(2026-09-26 实测后补上):
|
|
@@ -541,11 +587,20 @@ weflow-cli wiki lint --json # 机器可读
|
|
|
541
587
|
```powershell
|
|
542
588
|
weflow-cli search "PM2.5 对植物用水效率的影响"
|
|
543
589
|
weflow-cli search "..." --no-rerank # 只按向量/关键词相似度,不调决策模型
|
|
590
|
+
weflow-cli search "项目排期" --line chat # 只看聊天那条线
|
|
591
|
+
weflow-cli search "..." --line all # 两条线一起(默认只搜文章线)
|
|
544
592
|
```
|
|
545
593
|
|
|
594
|
+
**`--line wiki|chat|all` 四处都有**(`search` 语义检索、`chat` RAG、`vault search`、`vault rag`),
|
|
595
|
+
助手的 `search_semantic` / `search_knowledge` 也有同名参数。两条知识库分开之后,**默认只搜
|
|
596
|
+
文章线**,要把聊天那条也搜上就显式给 `all`。输出里每一处都会写明这一趟搜的是哪条线,空了
|
|
597
|
+
还会说清"是没命中还是这条线在索引里根本没有记录"——不写的话,"这条线里没有"会被读成
|
|
598
|
+
"整个知识库里没有"。
|
|
599
|
+
|
|
546
600
|
检索分两段:第一段算相似度取回 20 条候选,第二段用**一次**决策请求给每条候选问一个
|
|
547
601
|
"是否真的回答了这个问题",按概率重排后返回 `--top-k` 条(默认 10)。第二段约 1 秒,
|
|
548
|
-
|
|
602
|
+
与候选数基本无关。`--line` 的过滤发生在**取候选之前**(不是取完再筛),所以不会出现
|
|
603
|
+
"要 10 条只回 3 条"或者"另一条线的结果混进来还标着本线的名字"。
|
|
549
604
|
|
|
550
605
|
- 返回里 `score` 仍是相似度(含义没变),重排的分数在 `rerankScore`。
|
|
551
606
|
- 没配 `typesafeApiKey`、连接失败或服务过载(529)时,**原序返回并打一行 WARN**,
|
|
@@ -736,6 +791,7 @@ python scripts/generate_html.py --date 2026-09-05 --exclude-topics "新闻,投
|
|
|
736
791
|
- 相关度会写进 frontmatter 的 `relevance`(仍是「高/中/低」三个字),并额外写入
|
|
737
792
|
`relevanceScore`(原始分值)与 `topicConfidence`(主题的置信度)。那三档的切点是
|
|
738
793
|
暂定的,原始分留着,将来重新校准时不用重跑历史日报。
|
|
794
|
+
**前提**:这三个分只在判断层(Jev)判过的文章上才有(它们来自 `decision`)。判断层不可用、整轮走 LLM 回退路径时,日报里就没有它们 —— 2026-10-10 实测:回填日的 383 篇里 0 篇带 `relevanceScore`,而 `biz_daily.py` 的 `_article_entry` 本身是会写这几个键的。
|
|
739
795
|
- 同一批问题里还问了一个**「该不该收进今天的日报」**(`includeScore`,0~1)。
|
|
740
796
|
日报的收录门用它,而不是拿相关度顶替——相关度答的是"对读者的实用价值",
|
|
741
797
|
答不了"今天该不该收它"。切点默认 `0.5`,同样暂定;`generate_ai_report.py`
|
|
@@ -748,6 +804,9 @@ python scripts/generate_html.py --date 2026-09-05 --exclude-topics "新闻,投
|
|
|
748
804
|
- 分类要把文章标题与正文发往 `api.typesafe.ai`——和生成摘要发给 DeepSeek 是同一类动作,
|
|
749
805
|
想完全不出网就用 `weflow-cli daily --no-ai`。
|
|
750
806
|
- 排查用 `python scripts/biz_daily.py --date <日期> --classifier llm`(强制老路径)对比。
|
|
807
|
+
- 如果日志里出现 `HTTP 451 … not available in your region`:那是**判断层按地区不可用**(服务端策略,不是配置错)。
|
|
808
|
+
日报不会因此坏掉——每篇都会退回老的 LLM 解析路径,只是白试一次;想让这一天的日报**连试都不试**,
|
|
809
|
+
加 `--classifier llm` 就行。同一条失败在日志里已经折叠成一次(`另有 N 篇因…被折叠`),不会刷屏。
|
|
751
810
|
- 只要判断、不要生成(连 DeepSeek key 都不需要):`weflow-cli daily --no-summary`。摘要/标签/简报一律不生成,md 里不会有 `## AI 摘要` 段;主题与相关度仍由 Jev 判断。流水线里下游步骤(行动建议/概念编译/AI 报告)仍会用 LLM,要全关再加 `--skip-classify --skip-wiki --skip-ai-report`。
|
|
752
811
|
|
|
753
812
|
启动指定日期阅读器:
|
|
@@ -811,6 +870,23 @@ weflow-cli assistant start
|
|
|
811
870
|
weflow-cli assistant status
|
|
812
871
|
```
|
|
813
872
|
|
|
873
|
+
### 入站图片/文件要不要落地(默认不落)
|
|
874
|
+
|
|
875
|
+
别人发给助手一张图,助手默认只知道"有这么一张图",不知道图里是什么。打开这个开关后,通道会把图片、语音、文件、视频从 CDN 拉下来、在本地解密并写盘:
|
|
876
|
+
|
|
877
|
+
```powershell
|
|
878
|
+
weflow-cli config set wechatMediaDownload true
|
|
879
|
+
weflow-cli assistant stop
|
|
880
|
+
weflow-cli assistant start
|
|
881
|
+
```
|
|
882
|
+
|
|
883
|
+
- **这是显式的网络访问**,所以默认是关的(`false`)。不打开时,进程不会为入站媒体发任何请求。
|
|
884
|
+
- 文件落在 `output/wechat-media/` 下;换位置用环境变量 `WEFLOW_WECHAT_MEDIA_DIR`(目录会在首次落地时自动建)。
|
|
885
|
+
- **文件名由本地决定**:服务端给的名字只取最后一段并过滤字符,所以它写不到 `output/` 之外去。
|
|
886
|
+
- 单件超过 **25 MB**、下载失败、或解出来是空的,都**不会留下文件**:`filePath` 是空的,日志里有一行写明原因(`入站媒体未落地(image):…`)。看到这行就是没存下来,不是"存了但你没找到"。
|
|
887
|
+
- 关掉就回到原样:`weflow-cli config set wechatMediaDownload false`。
|
|
888
|
+
- ⚠️ **它是"谁发来的都下",不是"只下白名单的"**:下载发生在长轮询解析消息的那一步,比"助手要不要回答"的判断更早。所以只要有人能给这个机器人发消息,他发来的图片/文件就会落到你磁盘上;白名单管的是**助手回不回答**,管不到**下不下载**。介意这一点就别开这个开关(或把机器人只留给自己能联系)。
|
|
889
|
+
|
|
814
890
|
### 本机面板:不扫码也能跟助手说话
|
|
815
891
|
|
|
816
892
|
```powershell
|
|
@@ -864,10 +940,19 @@ npm i -g electron
|
|
|
864
940
|
球被拖到屏幕外时会回到右下角。展开后气泡这一整块**不置顶**——去点别的窗口时会到后面去,
|
|
865
941
|
从任务栏点回来即可。
|
|
866
942
|
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
943
|
+
**球有表情**(球是 96px,素材是 256px 的图,都在 `resources/panel/`):**按住**它像被拎住后颈一样
|
|
944
|
+
浮起来 —— 十二帧硬切(6 帧拎起来 + 6 帧落回去),松手接着播完落地那几帧回到原样,全程约 0.7 秒,按下那一帧
|
|
945
|
+
是同步出的(不留空档);助手**忙**、**离线**、**配额用完**时各有一张脸;空闲时球背后什么都没有
|
|
946
|
+
(那层光晕 2026-09-29 已整层删掉)。这些是"真状态",不是动画效果:状态脸由 `renderer.js` 的
|
|
947
|
+
`setBallFace()` 统一设置(加新状态时改那一个入口),动作帧由同一个文件里的 `showLift()` 统一切换。
|
|
948
|
+
系统开了"减少动态效果"时不播动作,只保留按住时那张笑脸 —— 那正是那张笑脸现在唯一的用处。
|
|
949
|
+
|
|
950
|
+
**鼠标从它身上划过时它会扭**(挠痒痒,2026-10-02):4 张姿势帧循环播放,停下约 0.3 秒收。
|
|
951
|
+
|
|
952
|
+
**划过只扭、不倾斜** —— 它早先还带一个按速度算的小倾斜(往哪边划就往反方向倒),2026-10-02 去掉了:
|
|
953
|
+
旋转现在只归"被拎起来"那条,因为两者共用 `#ball` 上的 transform,随手扫过看起来像一次小号起飞
|
|
954
|
+
(用户的原话:「为什么鼠标划动也会晃,而不是在起飞状态才会晃」)。系统开了"减少动态效果"时不扭;
|
|
955
|
+
它半隐在屏幕边时也不扭;按住时也让位给"被拎起来"那套。
|
|
871
956
|
|
|
872
957
|
**关掉窗口 ≠ 停止助手**:窗口没了,守护进程还在跑(微信那边可能还在用)。要停:
|
|
873
958
|
|
|
@@ -892,6 +977,7 @@ weflow-cli assistant stop
|
|
|
892
977
|
# 端口与 token 在 ~/.weflow-cli/assistant_endpoint.json 里;token 不要贴到别处
|
|
893
978
|
curl.exe -i http://127.0.0.1:8766/api/status # 401(没 token)
|
|
894
979
|
curl.exe -i -H "Authorization: Bearer <token>" http://127.0.0.1:8766/api/status # 200
|
|
980
|
+
curl.exe -i -H "Authorization: Bearer <token>" http://127.0.0.1:8766/api/memory # 200:它记住了什么(只读)
|
|
895
981
|
```
|
|
896
982
|
|
|
897
983
|
**中文别用 Git Bash 的 `curl -d '中文'`**:那条路径会把正文按控制台代码页编出去,
|
package/README.en.md
CHANGED
|
@@ -94,12 +94,12 @@ Automatic initialization on Linux depends on the WeChat distribution, the Python
|
|
|
94
94
|
| --- | --- |
|
|
95
95
|
| Chat history | Query sessions, contacts, and messages; export to JSON, TXT, HTML, Excel. An HTML export also writes a media coverage report saying which images and stickers could not be embedded, and why. |
|
|
96
96
|
| Official-account digest | Crawl articles, AI summarization and classification, generate a local reading page, keep favorites and read states. |
|
|
97
|
-
| Personal knowledge base | Sync WeRead notes, build an Obsidian vault, semantic search, RAG Q&A, and a
|
|
97
|
+
| Personal knowledge base | Sync WeRead notes, build an Obsidian vault, semantic search, RAG Q&A, a concept wiki, and a **self-contained graph page** you can open by double-clicking (`weflow-cli wiki graph --open` for 3D, `--flat` for 2D - no server, no network; `--min-degree N` keeps only the hubs, `--line wiki\|chat` draws one corpus). |
|
|
98
98
|
| AI collaboration | Expose article crawling, knowledge-base retrieval, digests, and selected local-data tools to MCP-compatible clients. The inventory follows the current code and `docs/MCP.md`. |
|
|
99
99
|
| Personal review | Monthly chat reports, annual reports, todo extraction, and local Moments cache queries. |
|
|
100
100
|
| WeChat favorites | Read WeChat "Favorites" (official-account articles, text, images, videos, chat records) with type filters, keyword search, and Markdown/JSON export. |
|
|
101
101
|
| Second-brain agent | Chat with a local AI assistant inside WeChat: natural-language queries over chats, favorites, Moments, digests, WeRead, todos, and the knowledge base; three-tier memory across sessions, daemonized background service. It can also **fetch an official-account article**, search public articles, format Markdown for the WeChat editor, list contacts, read your learning reviews, health-check the knowledge base and skill packages, and mark a todo done (**never delete one**). What it can reach, and what stays out of reach, is in `docs/PROJECT_STATE.md` and `docs/DECISIONS.md` (D-058). |
|
|
102
|
-
| On-device panel | A floating ball on your desktop: click to chat with **the same brain as the WeChat side** (same memory, same quota), and each reply expands into a **thinking process** - what tool it called, how many round trips, why it stopped. The ball itself is transparent with a face per state. |
|
|
102
|
+
| On-device panel | A floating ball on your desktop: click to chat with **the same brain as the WeChat side** (same memory, same quota), and each reply expands into a **thinking process** - what tool it called, how many round trips, why it stopped. The ball itself is transparent with a face per state, and a **Memory** button lists what it has stored about you long-term - each fact with the time it was written and the quote it came from (read-only). |
|
|
103
103
|
| Skill packages | The assistant reads the `SKILL.md` packages already on your machine (by default `~/.claude/skills` and `~/.weflow-cli/skills`): the prompt lists what exists, and a body is read on demand before following it. **A skill grants the assistant no new tools** - it is material: not executed, not installed, and unable to read configuration or databases. `weflow-cli skill check` reports unreadable frontmatter, cross-directory collisions, and non-conforming ids. |
|
|
104
104
|
| Conversation scenes | Give one conversation a fixed way of working: keywords plus an extra instruction, an output spec, and required skills. Each message picks one by **binding → keyword → last used**, and picks none when nothing matches, leaving the previous behaviour untouched. Manage with `weflow-cli scene`, or bind from the conversation with `场景 <id>`. **Scenes are not readable or writable by the model**, and which scene applied is recorded in the thinking process. |
|
|
105
105
|
|
|
@@ -232,11 +232,13 @@ weflow-cli panel # open the on-device panel window (usable without
|
|
|
232
232
|
|
|
233
233
|
`weflow-cli panel` opens a small always-on window that talks to **the same brain as the WeChat side** — the same memory, the same daily quota. **No WeChat login is required**: the messaging channel is optional. The window is only a client; its messages go to the daemon's entry point on `127.0.0.1`, so the two entry points never keep separate copies of memory.
|
|
234
234
|
|
|
235
|
-
The floating ball needs Electron (`npm i -g electron`); without it the panel degrades to an Edge/Chrome `--app` window — same UI, but no frameless always-on-top ball, no tray, no global shortcut. With the ball (a 96px mascot): **click it and the chat bubble opens beside it (the ball itself stays put; click again to collapse)**. The bubble opens to the left of the ball by default, flips to the right when there is no room on the left, and top-aligns when vertical space runs short; drag the ball to move it, and the position is remembered. **The ball is transparent - only the mascot shows through** - calm at rest, and switching to a *thinking* face for the seconds you are waiting on an answer (offline and quota-exhausted have faces of their own).
|
|
235
|
+
The floating ball needs Electron (`npm i -g electron`); without it the panel degrades to an Edge/Chrome `--app` window — same UI, but no frameless always-on-top ball, no tray, no global shortcut. With the ball (a 96px mascot): **click it and the chat bubble opens beside it (the ball itself stays put; click again to collapse)**. The bubble opens to the left of the ball by default, flips to the right when there is no room on the left, and top-aligns when vertical space runs short; drag the ball to move it, and the position is remembered. **The ball is transparent - only the mascot shows through** - calm at rest, and switching to a *thinking* face for the seconds you are waiting on an answer (offline and quota-exhausted have faces of their own). **Press and hold it and it is picked up by the scruff - a twelve-frame lift (six up, six back down) that settles on release** (skipped when the system asks for reduced motion). **Run the pointer across it and it squirms as if tickled** - four poses, with **no tilt** (the 4-degree rotation it
|
|
236
|
+
used to work out from how fast you move was removed on 2026-10-02, so that running the pointer across it no longer
|
|
237
|
+
looks like a small take-off: rotation belongs to the lift alone). **Carried around it swings left and right - the side you move towards swings further, and faster movement swings wider.** It **hops when a reply lands**, **blinks every 7-13 seconds**, its eyes follow the pointer, and dragged to a screen edge it hides half-way behind it.
|
|
236
238
|
|
|
237
239
|
**Every reply carries a collapsible "thinking process" (closed by default)**: how that turn actually went - the routing decision, which tool it called, its arguments, how many round trips, and why it stopped. It is the same record you get in WeChat by sending 轨迹 (or 思考过程), so the two cannot drift apart.
|
|
238
240
|
|
|
239
|
-
**Right-click anywhere in the panel** to draft a reply for someone on your list (`weflow-cli config set quickReplyContacts "Alice,Bob"` — a click sends that conversation to two cloud models and returns text only, never sending for you). The
|
|
241
|
+
**Right-click anywhere in the panel** to draft a reply for someone on your list (`weflow-cli config set quickReplyContacts "Alice,Bob"` — a click sends that conversation to two cloud models and returns text only, never sending for you). The menu also carries a row of one-click actions (who is waiting on a reply, todos, digests, stats, reading stats, sessions, Moments, WeRead), and its last item tucks the ball away; the tray icon brings it back. Running a tool **never pops up a console window**, and the window recovers by itself after the assistant restarts - you do not have to reopen it.
|
|
240
242
|
|
|
241
243
|
Then just talk to ClawBot on your phone. The assistant queries local chats and favorites to answer, with memory that survives across sessions:
|
|
242
244
|
|
|
@@ -279,7 +281,8 @@ Management: `weflow-cli assistant status` / `log` / `stop`; send "帮助" in WeC
|
|
|
279
281
|
| Initialize or specify paths | `weflow-cli init [--path <dir>]` |
|
|
280
282
|
| Browse chat data | `weflow-cli sessions` · `weflow-cli messages <contact>` · `weflow-cli contacts` |
|
|
281
283
|
| Who is waiting on a reply | `weflow-cli awaiting --dry-run` · `weflow-cli awaiting --yes` |
|
|
282
|
-
| Draft a reply (text
|
|
284
|
+
| Draft a reply (text unless you pick and send) | `weflow-cli draft <contact> --dry-run` · `--yes` (**only** `--pick N --send --yes` actually sends; both flags are required) |
|
|
285
|
+
| Relationship temperature | `weflow-cli bonds` (who is cooling, who is warming, who only has WeChat; read-only, local, no model) |
|
|
283
286
|
| Local judgement primitive | `weflow-cli decide --request <file> --dry-run` · `--yes` |
|
|
284
287
|
| Export chat history | `weflow-cli export <contact> <json\|txt\|html\|excel>` |
|
|
285
288
|
| Sync checkpoint | `weflow-cli sync run <contact> --since <date>` · `sync status` · `sync verify` |
|
|
@@ -317,6 +320,11 @@ Main Python workflows:
|
|
|
317
320
|
# Article crawling -> AI classification -> HTML reading page -> Wiki / learning digest
|
|
318
321
|
python scripts/pipeline.py --date YYYY-MM-DD --api-key "Your API Key" --engine deepseek
|
|
319
322
|
|
|
323
|
+
# Note: this does **not** write your Obsidian Vault by default (no Sources/WeChat copy, no concept pages).
|
|
324
|
+
# Obsidian's own graph view is live - it watches the vault's files and re-renders when one changes.
|
|
325
|
+
# To make the graph follow the content, ask for it explicitly (either flag works alone too):
|
|
326
|
+
python scripts/pipeline.py --date YYYY-MM-DD --api-key "Your API Key" --with-vault --with-wiki
|
|
327
|
+
|
|
320
328
|
# Run step by step
|
|
321
329
|
python scripts/biz_daily.py --date YYYY-MM-DD --api-key "Your API Key"
|
|
322
330
|
python scripts/generate_html.py --date YYYY-MM-DD
|
|
@@ -326,6 +334,7 @@ python scripts/fav_server.py --date YYYY-MM-DD
|
|
|
326
334
|
## Architecture
|
|
327
335
|
|
|
328
336
|

|
|
337
|
+
> Illustrative only: [`ARCHITECTURE.md`](./ARCHITECTURE.md) is authoritative for links, ports and authentication — this figure is model-generated, so its fine detail is not word-for-word reliable.
|
|
329
338
|
|
|
330
339
|
The project is split into five clearly bounded parts:
|
|
331
340
|
|
package/README.md
CHANGED
|
@@ -92,14 +92,14 @@ Linux 的自动初始化能力取决于微信发行版、Python 依赖和当前
|
|
|
92
92
|
|
|
93
93
|
| 场景 | 能力 |
|
|
94
94
|
| --- | --- |
|
|
95
|
-
| 聊天记录 | 查询会话、联系人和消息;导出 JSON
|
|
95
|
+
| 聊天记录 | 查询会话、联系人和消息;导出 **Markdown / JSON / TXT / HTML / Excel**。Markdown 导出把图片**落盘**到 `<会话>_assets/`、正文用相对路径引用(喂给编辑器或别的工具时这才是能用的形态);**文档本体**(微信里的 Word/Excel/PDF/PPT 等)按原名与扩展名拷进 `<会话>_assets/files/`,正文里按原名链接到 `files/` 下;HTML 导出内嵌图片并给出一份媒体覆盖报告(哪些没嵌上、为什么)。**匹配只做一遍**:Markdown 导出写下清单,之后 JSON/TXT/Excel 导出(或 `--media`)会自动带上同样的图片与文档路径。 |
|
|
96
96
|
| 公众号日报 | 抓取文章、AI 摘要与分类、生成本地阅读页,保留收藏和已读状态。 |
|
|
97
|
-
| 个人知识库 | 同步微信读书笔记、构建 Obsidian Vault、语义搜索、RAG 问答和概念 Wiki
|
|
97
|
+
| 个人知识库 | 同步微信读书笔记、构建 Obsidian Vault、语义搜索、RAG 问答和概念 Wiki,以及**双击就能打开**的概念图谱页面(`weflow-cli wiki graph --open` 出 3D、加 `--flat` 出 2D;自包含、不联网、不需要服务器;`--min-degree N` 只看枢纽、`--line wiki\|chat` 只看一条线)。 |
|
|
98
98
|
| AI 协作 | 通过 MCP 把文章、知识库、日报和受控的本地数据能力交给兼容客户端;工具清单以 `weflow-cli mcp-config` 和 `docs/MCP.md` 为准。 |
|
|
99
99
|
| 个人回顾 | 聊天月报、年度报告、待办提取与朋友圈本地缓存查询。 |
|
|
100
100
|
| 微信收藏 | 读取微信"收藏"内容(公众号文章、文字、图片、视频、聊天记录),支持类型过滤、关键词搜索与 Markdown/JSON 导出。 |
|
|
101
101
|
| 第二大脑 Agent | 在微信里和本地 AI 助手对话:自然语言查询聊天记录、收藏、朋友圈、日报、微信读书、待办与知识库;三层记忆跨会话延续,守护进程常驻后台。也能**抓一篇公众号正文**、在公开文章里搜、把 Markdown 排成公众号格式、列通讯录、读学习回顾、体检知识库与技能包、把待办标记完成(**不能删除**)。它调得到的工具与不可达的边界见 `docs/PROJECT_STATE.md` 与 `docs/DECISIONS.md`(D-058)。 |
|
|
102
|
-
| 本机面板 |
|
|
102
|
+
| 本机面板 | 桌面常驻的悬浮球:点开即对话(与微信里**同一个大脑**、同一份记忆与配额),每条回答下面可展开**「思考过程」**(它调了什么工具、几轮、为什么停),球本身有状态表情、透明底,面板里还有一个**「记忆」**按钮:能看它对你长期记下了什么(每条带写入时间和来源原话,只读)。 |
|
|
103
103
|
| 技能包 | 助手能读你机器上已有的 `SKILL.md` 技能包(默认扫 `~/.claude/skills` 与 `~/.weflow-cli/skills`):提示词里列出有哪些,要用时读正文再照着做。**技能不给助手增加任何工具**——它只是资料,不执行、不安装、读不到配置和数据库。`weflow-cli skill check` 报出读不出来、跨目录同名和 id 不合规的技能。 |
|
|
104
104
|
| 会话场景 | 给某个会话一套固定的做法:关键词 + 附加指令 + 输出规范 + 所需技能。消息进来按「绑定 → 关键词 → 上次用过的」挑一个,都没中就完全按原来的行为。用 `weflow-cli scene` 管理,或在对话里发「场景 <id>」绑定。**场景不让模型读写**,本次用了哪个场景会记在「思考过程」里。 |
|
|
105
105
|
|
|
@@ -158,7 +158,7 @@ weflow-cli messages "联系人" -n 10
|
|
|
158
158
|
weflow-cli export "联系人" html --output ./output
|
|
159
159
|
```
|
|
160
160
|
|
|
161
|
-
HTML 导出默认内嵌微信缓存里的缩略图,并尽力还原图片、表情包、系统消息和公众号卡片。远程媒体按 URL 缓存在输出目录的 `.cover-cache/`,所以**重复导出接近瞬时**(实测 1600+ 条约 2 秒),首次导出才需要联网。自定义表情包从本地缓存离线解密,seed
|
|
161
|
+
HTML 导出默认内嵌微信缓存里的缩略图,并尽力还原图片、表情包、系统消息和公众号卡片。远程媒体按 URL 缓存在输出目录的 `.cover-cache/`,所以**重复导出接近瞬时**(实测 1600+ 条约 2 秒),首次导出才需要联网。自定义表情包从本地缓存离线解密,seed 未配置时会自动扫描微信内存反推并提示固化命令。想改用**原图作为来源**时加 `--full-images`(原图常有 5–24MB/张,处理它们会慢数倍;**嵌入前仍按上限缩放**,所以导出物不会因此变大成几百 MB,实测两档体积相当)。细节见[操作与排障手册](./OPERATIONS.md#4-导出聊天记录)。
|
|
162
162
|
|
|
163
163
|
**生成当天公众号日报**
|
|
164
164
|
|
|
@@ -199,6 +199,14 @@ weflow-cli config set typesafeApiKey "..."
|
|
|
199
199
|
|
|
200
200
|
阅读器默认在 `http://localhost:8765/` 提供服务。
|
|
201
201
|
|
|
202
|
+
**约定版本的导出格式**
|
|
203
|
+
|
|
204
|
+
```powershell
|
|
205
|
+
weflow-cli export "联系人" json --contract weflow-v1 --output ./output
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
生成的信封里字段是稳定的,并带一份保守的 `coverage` 说明。增量读取用带重叠的 `--from` 时间窗自己按「会话 + `localId`/`serverId`」去重,或者交给 `sync` 记住检查点并报告覆盖范围。稳定游标还没对外:要等每个数据库后端都支持才敢承诺。旧的 JSON 导出仍是一个顶层数组。
|
|
209
|
+
|
|
202
210
|
**接入 AI 编辑器**
|
|
203
211
|
|
|
204
212
|
```powershell
|
|
@@ -207,7 +215,7 @@ weflow-cli mcp-config > .mcp.json
|
|
|
207
215
|
|
|
208
216
|
将生成的配置放到所用 MCP 客户端的配置位置后重启客户端即可。MCP 的工具列表与配置方式见 `weflow-cli mcp-config` 输出。
|
|
209
217
|
|
|
210
|
-
除知识库类工具外,MCP
|
|
218
|
+
除知识库类工具外,MCP 也暴露本机微信数据能力(会话、聊天记录、收藏、朋友圈、日报、微信读书、待办、知识库与助手记忆查询)。它的工具面**由助手的工具表派生**(少掉 `save_memory`、`look_at_image`、`set_todo_status` 三个),所以**不是纯只读**:写入类调用都要显式 `confirm`;而**发送消息、发布文章、改配置这三件事没有任何工具**——`weflow-cli capabilities --json` 里的 `safety.mcpDefaultReadOnly` 记着这条边界。工具清单以当前代码和 [MCP 集成指南](./docs/MCP.md) 为准,不固定写死数量。
|
|
211
219
|
|
|
212
220
|
**在微信里挂一个本地 AI 助手(第二大脑)**
|
|
213
221
|
|
|
@@ -226,13 +234,13 @@ weflow-cli panel # 打开本机面板窗口 (不扫码也能用)
|
|
|
226
234
|
界面一样,但没有无边框置顶、没有托盘与快捷键。有球时:**点一下它在旁边展开对话气泡
|
|
227
235
|
(球不动,再点一下收起)**;气泡默认开在球的左边,左边放不下会自己翻到右边,上方不够就
|
|
228
236
|
改成顶对齐;拖动球可以换位置(位置会记住)。**球是透明底的,只有吉祥物本身**——空闲时一脸
|
|
229
|
-
平静,**在你等它回答的那几秒换成"思考"
|
|
237
|
+
平静,**在你等它回答的那几秒换成"思考"的表情**(连不上、额度用完时各有各的脸)。**按住它会像被拎住后颈一样浮起来,松手落回**(十二帧硬切的动作;系统开了"减少动态效果"时不播)。**被拎着挪动时它会左右摆**——往哪边移哪边摆得更大、动得越快摆得越狠;**答复落地时它跳一下**;**平时每 7–13 秒眨一次眼**,眼睛还会跟着鼠标;拖到屏幕边会半隐起来。**鼠标从它身上划过,它会像被挠到一样扭一扭**——只有扭动、**不倾斜**(旋转只归"被拎起来"那条,2026-10-02 起)。
|
|
230
238
|
|
|
231
239
|
**每条回答下面可以展开「思考过程」(默认收起)**:里面是它这一轮怎么走的——路由判断、
|
|
232
240
|
调了哪个工具、参数摘要、往返几次、为什么结束。在微信里发「轨迹」(或「思考过程」)看的是
|
|
233
241
|
同一份记录,两处不会各说各话。
|
|
234
242
|
|
|
235
|
-
**在面板里点右键**可以给名单上的人快速起草回复(`weflow-cli config set quickReplyContacts "某人,另一人"
|
|
243
|
+
**在面板里点右键**可以给名单上的人快速起草回复(`weflow-cli config set quickReplyContacts "某人,另一人"`;点一下就是把那段对话发给两个云端模型,只产出文本、不会替你发送),菜单里还有一排一键功能(谁在等我回话 / 待办 / 日报 / 统计 / 阅读统计 / 会话 / 朋友圈 / 微信读书),最后一项能把球收起来(点托盘图标叫回来)。助手跑工具时**不会弹出黑色命令行窗口**;助手重启之后窗口也会自己恢复,不用重新打开。
|
|
236
244
|
|
|
237
245
|
之后在手机微信的 ClawBot 对话里直接说话,助手会自动查询本地聊天记录和收藏作答,并具备跨会话记忆:
|
|
238
246
|
|
|
@@ -276,7 +284,8 @@ weflow-cli config set assistantGroupRequireMention true
|
|
|
276
284
|
| 初始化或手动指定路径 | `weflow-cli init [--path <目录>]` |
|
|
277
285
|
| 浏览聊天数据 | `weflow-cli sessions` · `weflow-cli messages <联系人>` · `weflow-cli contacts` |
|
|
278
286
|
| 谁在等我回话 | `weflow-cli awaiting --dry-run` · `weflow-cli awaiting --yes` |
|
|
279
|
-
|
|
|
287
|
+
| 帮我起草回复(默认只出文字) | `weflow-cli draft <联系人> --dry-run` · `--yes`(**只有** `--pick N --send --yes` 会真的替你发出去;两步缺一不可)|
|
|
288
|
+
| 关系温度 | `weflow-cli bonds`(谁在冷却、谁在变热、谁只有微信这一条线;只读本地库,不联网、不调模型)|
|
|
280
289
|
| 本机判断层 | `weflow-cli decide --request <file> --dry-run` · `--yes` |
|
|
281
290
|
| 导出聊天记录 | `weflow-cli export <联系人> <json\|txt\|html\|excel>` |
|
|
282
291
|
| 同步检查点 | `weflow-cli sync run <联系人> --since <日期>` · `sync status` · `sync verify` |
|
|
@@ -314,6 +323,11 @@ npm run dev -- init
|
|
|
314
323
|
# 文章抓取 -> AI 分类 -> HTML 阅读页 -> Wiki / 学习日报
|
|
315
324
|
python scripts/pipeline.py --date YYYY-MM-DD --api-key "你的 API Key" --engine deepseek
|
|
316
325
|
|
|
326
|
+
# 注意:这条**默认不写 Obsidian Vault**(不拷 Sources/WeChat,也不编译概念页)。
|
|
327
|
+
# 原因:Obsidian 自带的图谱视图是**实时**的 —— 它盯着 vault 里的文件,文件一变就重画。
|
|
328
|
+
# 想让图谱跟着变,显式加上这两个开关(也可以分开用):
|
|
329
|
+
python scripts/pipeline.py --date YYYY-MM-DD --api-key "你的 API Key" --with-vault --with-wiki
|
|
330
|
+
|
|
317
331
|
# 分步运行
|
|
318
332
|
python scripts/biz_daily.py --date YYYY-MM-DD --api-key "你的 API Key"
|
|
319
333
|
python scripts/generate_html.py --date YYYY-MM-DD
|
|
@@ -323,6 +337,7 @@ python scripts/fav_server.py --date YYYY-MM-DD
|
|
|
323
337
|
## 架构
|
|
324
338
|
|
|
325
339
|

|
|
340
|
+
> 示意图:链路、端口与鉴权以 [`ARCHITECTURE.md`](./ARCHITECTURE.md) 为准 —— 这张图是生图模型画的,细节文字不逐字采信。
|
|
326
341
|
|
|
327
342
|
项目分为五个边界清晰的部分:
|
|
328
343
|
|