weflow-cli 1.8.0 → 1.8.1
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/CHANGELOG.md +159 -1
- package/OPERATIONS.md +42 -6
- package/README.en.md +3 -3
- package/README.md +3 -3
- package/bin/weflow-cli.ts +3 -1
- package/dist/bin/weflow-cli.js +3 -1
- package/dist/bin/weflow-cli.js.map +1 -1
- package/dist/src/panel/server.js +1 -1
- package/dist/src/panel/server.js.map +1 -1
- package/dist/src/services/assistantPrivacy.d.ts.map +1 -1
- package/dist/src/services/assistantPrivacy.js +7 -2
- package/dist/src/services/assistantPrivacy.js.map +1 -1
- package/dist/src/services/assistantService.d.ts.map +1 -1
- package/dist/src/services/assistantService.js +10 -1
- package/dist/src/services/assistantService.js.map +1 -1
- package/dist/src/services/assistantTools.d.ts +12 -0
- package/dist/src/services/assistantTools.d.ts.map +1 -1
- package/dist/src/services/assistantTools.js +29 -3
- package/dist/src/services/assistantTools.js.map +1 -1
- package/dist/src/services/wereadService.d.ts +33 -6
- package/dist/src/services/wereadService.d.ts.map +1 -1
- package/dist/src/services/wereadService.js +27 -2
- package/dist/src/services/wereadService.js.map +1 -1
- package/docs/BRANCHES.md +13 -4
- package/docs/PROJECT_STATE.md +299 -299
- package/package.json +1 -1
- package/resources/panel/main.cjs +43 -7
- package/resources/panel/mascot-thinking.png +0 -0
- package/resources/panel/panel.css +415 -407
- package/resources/panel/preload.cjs +79 -72
- package/resources/panel/renderer.js +470 -441
- package/scripts/_utils.py +23 -1
- package/scripts/backfill_articles.py +438 -438
- package/scripts/compile_wiki.py +18 -17
- package/scripts/wiki_lint.py +429 -397
- package/src/panel/server.ts +424 -424
- package/src/services/assistantPrivacy.ts +7 -2
- package/src/services/assistantService.ts +11 -1
- package/src/services/assistantTools.ts +33 -3
- package/src/services/wereadService.ts +43 -7
- package/resources/panel/mascot-focus.png +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,164 @@ The npm package is published separately from GitHub. It may lag behind the `mast
|
|
|
4
4
|
|
|
5
5
|
All notable user-facing changes are recorded here. This project follows [Semantic Versioning](https://semver.org/).
|
|
6
6
|
|
|
7
|
+
## 1.8.1
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- **The floating ball's "busy" face is now a thinking face, not a contemplative one.** `busy` is
|
|
12
|
+
exactly "a request went out and we are waiting" (`renderer.js`'s `ask()` sets it on entry), so the
|
|
13
|
+
face is drawn as thought: eyes glancing up-left, level brows, a flat mouth line, a paw under the
|
|
14
|
+
chin. The file was renamed `mascot-focus.png` -> `mascot-thinking.png` rather than overwritten -
|
|
15
|
+
a file named `focus` holding a thinking face is the next misreading - and all four places that
|
|
16
|
+
name it were updated together (CSS, the static whitelist, the packaging list, the state-to-file
|
|
17
|
+
assertion). The two reconciliation tests in `panel-packaging.test.ts` went red when the wiring
|
|
18
|
+
landed before the image did, which is how we know they actually watch that gap.
|
|
19
|
+
|
|
20
|
+
It is generated with `gpt-image-2-ca` through `/images/edits`, using the existing mascot as the
|
|
21
|
+
base so only the expression changes - a text-only redraw takes the style and framing with it. The
|
|
22
|
+
first prompt asked for "thinking" and produced **worry** (downturned mouth, lowered brows), which
|
|
23
|
+
collided with the offline face; the second spells out "level brows, flat mouth line, not sad, not
|
|
24
|
+
worried". Geometry is checked rather than eyeballed, because the ball clips to a circle: content
|
|
25
|
+
box 171x212 (the existing faces are 170x214), farthest solid pixel 125.2 against a 125.4 limit,
|
|
26
|
+
and **0 solid pixels outside the inscribed circle**.
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- **The panel ball went blank after the assistant restarted, and it now repairs itself.** The
|
|
31
|
+
daemon generates a fresh token on every start, and the window's cookie is planted when it opens -
|
|
32
|
+
so a window that outlives a restart holds dead credentials. Every `/panel/*` request then answers
|
|
33
|
+
401, and because those responses carry `Cache-Control: no-store` the ball's face (`panel.css`
|
|
34
|
+
loads it as a background image) fails to load: **a blank ball, with the window otherwise looking
|
|
35
|
+
normal**. Measured: the window had been open 25 hours against a daemon 25 hours younger, which is
|
|
36
|
+
how this was found - the user reported "my agent icon is gone".
|
|
37
|
+
|
|
38
|
+
The window can now recover by itself. Its status poll already distinguishes the case, and on
|
|
39
|
+
`UNAUTHORIZED` it asks the main process to re-read the endpoint file, refresh the cookie and
|
|
40
|
+
reload. The credentials still never reach the renderer - the main process does the reading, which
|
|
41
|
+
is where they belong; the preload's exposed surface grows by exactly one method and
|
|
42
|
+
`test/panel-packaging.test.ts` pins that list, so widening it stays a deliberate act. Two guards
|
|
43
|
+
keep the cure from being worse than the disease: **the reload only happens when the file's token
|
|
44
|
+
actually differs** from the cookie (otherwise an unrelated 401 would reload forever), and there is
|
|
45
|
+
a five-second floor plus a three-attempt cap in the page, because **a reload storm is harder to
|
|
46
|
+
diagnose than a blank ball**. Verified end to end by restarting the daemon and watching the
|
|
47
|
+
window reload on its own: the log's load counter went 73 → 74 with nobody touching the window.
|
|
48
|
+
|
|
49
|
+
- **The assistant denied that unconfigured capabilities existed.** A tool whose prerequisite key is
|
|
50
|
+
missing is deliberately left out of the tool table - a tool that cannot run makes the model try it
|
|
51
|
+
and apologise with errors in the answer. But the model then has no way to know it exists, so
|
|
52
|
+
asking "what am I reading" produced **"I don't have a get_weread tool"**. That is true about the
|
|
53
|
+
tool table and false about the product: the feature was built, it just was not configured, and the
|
|
54
|
+
user reasonably concluded it had never been built. The system prompt now carries a
|
|
55
|
+
`[本机没启用的能力]` line naming each missing prerequisite and telling the model to answer "this
|
|
56
|
+
part is not configured" with the setting to change, **not** "I don't have that tool". The tools
|
|
57
|
+
stay unavailable - this only stops the model from denying the feature exists. Verified by asking:
|
|
58
|
+
the answer is now "can't do it, the only reason is dashscopeApiKey isn't configured".
|
|
59
|
+
|
|
60
|
+
- **`get_reading_stats`'s description claimed a question it cannot answer.** It said to use it for
|
|
61
|
+
"what have I been reading lately" - which is exactly the WeRead question, so with `get_weread`
|
|
62
|
+
hidden the model reached for this tool and returned public-account push counts ("the most active
|
|
63
|
+
account is 红星新闻"). The tool was right; the sentence had taken over another capability's
|
|
64
|
+
question space. It now says what it covers (public-account pushes and daily-report processing) and
|
|
65
|
+
that it carries no reading data.
|
|
66
|
+
|
|
67
|
+
- **`weflow-cli weread ...` read the key from a different place than the assistant did, so
|
|
68
|
+
configuring it satisfied one and not the other.** The CLI read `WEREAD_API_KEY` from the
|
|
69
|
+
environment (which is what WeRead's own setup page tells you to export); the assistant's
|
|
70
|
+
`get_weread` availability check reads the **config key** `wereadApiKey`. Configure the config key -
|
|
71
|
+
as the CLI's own error message invites you to - and `weread shelf` still answers "not configured".
|
|
72
|
+
Both are accepted now, environment variable first because the official guidance is not to hand the
|
|
73
|
+
key to an AI. The resolution is a pure exported function with a test, rather than a line inside the
|
|
74
|
+
CLI's closure where the last change to it could not be tested.
|
|
75
|
+
|
|
76
|
+
The same session turned up two smaller things. **A tool hidden for a missing key is invisible to
|
|
77
|
+
the model, so the user gets "I don't have that tool"** - which is what happened here: the answer
|
|
78
|
+
said the capability did not exist when it did, unconfigured. That is now written into
|
|
79
|
+
`OPERATIONS.md` next to the filtering rule it belongs to, because "no key" and "no such feature"
|
|
80
|
+
read the same from the outside. And **`wereadService`'s header pointed at
|
|
81
|
+
`~/.claude/skills/weread-skills/`, which does not exist on this machine** (checked, 2026-09-28);
|
|
82
|
+
it now points at `https://weread.qq.com/r/weread-skills`, the page that actually issues the key -
|
|
83
|
+
the key's origin had been recorded nowhere in the repo, which is why finding it took reading a
|
|
84
|
+
stored article from May. `OPERATIONS.md` gained the setup steps, including that **`configService`
|
|
85
|
+
reads the file once at construction, so a running assistant needs a restart** to see a new key.
|
|
86
|
+
|
|
87
|
+
- **Fixing the CLI was not enough, and only an end-to-end run showed that.** With the key configured
|
|
88
|
+
and the assistant restarted, asking "what am I reading" still produced "WEREAD_API_KEY is not set".
|
|
89
|
+
The assistant tool was reading the secret a **third** way: its availability check loads the config
|
|
90
|
+
key - which is why the tool appeared in the table at all - and then calls the module singleton
|
|
91
|
+
`new WereadService()`, whose constructor read only the environment variable. A tool that is visible
|
|
92
|
+
but cannot run is the worst of both designs. The no-argument constructor now resolves both sources
|
|
93
|
+
through the same `resolveWereadApiKey`, which fixes every user of the singleton at once.
|
|
94
|
+
|
|
95
|
+
- **`get_weread`'s notebooks mode printed `undefined` for every book title.** `/user/notebooks` nests
|
|
96
|
+
the title and author inside `item.book`; the item itself carries only `bookId`, `noteCount`,
|
|
97
|
+
`bookmarkCount` and friends. The code read `item.title`, so the output was still well-formed - it
|
|
98
|
+
just had no names in it, which is why nothing failed. Verified against the gateway's real response
|
|
99
|
+
and pinned with a test that stubs **that** shape: the previous test for this branch stubbed an
|
|
100
|
+
empty list, so it could not have caught it.
|
|
101
|
+
|
|
102
|
+
All three of these were found in one session by configuring the key and then actually asking the
|
|
103
|
+
assistant a question, not by reading the code. Two of the three were invisible from any single
|
|
104
|
+
file: the secret had three readers and they disagreed.
|
|
105
|
+
|
|
106
|
+
- **`wiki lint`'s duplicate-title report was rebuilt rather than re-tuned, and the two tiers now
|
|
107
|
+
differ by an order of magnitude in how much you should trust them.** The old rule - a common
|
|
108
|
+
substring of ≥5 characters covering ≥40% of the shorter title - was reasonable at 5,062 pages of
|
|
109
|
+
long Chinese headlines and had become useless at 22,374: it reported **424,697 groups**, starting
|
|
110
|
+
with coincidences like `AI Agent开发框架` against `生物信息学LLM Agent综述` (both contain "Agent").
|
|
111
|
+
A 20-pair sample showed the rule firing correctly on every pair, which is the point: the threshold
|
|
112
|
+
had stopped discriminating, so the implementation was never the problem.
|
|
113
|
+
|
|
114
|
+
Two directions were measured and rejected before settling. **Keeping the long-common-substring
|
|
115
|
+
rule** fails because `Claude Code 上下文窗口` and `Claude Code 联网能力` share six characters and are
|
|
116
|
+
nonetheless different concepts - sharing a product name is not the same as being the same thing,
|
|
117
|
+
and that class dominated the false positives, so no ratio value separates them. **Containment
|
|
118
|
+
without a guard** fails because `DeepSeek` is swallowed by `DeepSeek 融资`, `DeepSeek-V4 涨价` and so
|
|
119
|
+
on; that is a *hub*, not a duplicate (measured: `agent` is contained in 731 names, `模型` in 643).
|
|
120
|
+
|
|
121
|
+
What it reports now: **314 groups that differ only in spacing, hyphens, case or an English plural**
|
|
122
|
+
(`GLM 5.1` / `GLM-5.1`, `AI 编程` / `AI编程`), scored by hand at 24 of 24 being the same node - and
|
|
123
|
+
these use `_utils.normalize_concept_name`, the **same function** `wiki compile --merge-duplicates`
|
|
124
|
+
uses, so the list is directly executable. Measured on the real vault, every group the lint reports
|
|
125
|
+
is one that tool would merge (the extra 14 groups it would act on are same-filename collisions,
|
|
126
|
+
which the lint reports separately). Plus **379 groups where one name is the other plus a qualifier**,
|
|
127
|
+
explicitly labelled a lead rather than a conclusion because hand-sampling puts its precision near
|
|
128
|
+
half - the other half being "hub vs its own subtopic" (`国家自然科学基金` /
|
|
129
|
+
`国家自然科学基金申请书`), which should not be merged.
|
|
130
|
+
|
|
131
|
+
The normaliser moved to `_utils` so the two readers cannot drift apart, and a test now pins the
|
|
132
|
+
**function object** rather than "two copies that look alike". The old caveat that the rule could not
|
|
133
|
+
catch the case it was written for still stands and is still written down: `打虎!陈勇被查` and
|
|
134
|
+
`中建集团副总经理陈勇被查` are the same event with different headlines and share only four characters,
|
|
135
|
+
so no substring rule reaches them - the tier-1 rule replaces "wrong and noisy" with "narrow and
|
|
136
|
+
right", not with "complete".
|
|
137
|
+
|
|
138
|
+
Two silent-failure traps were caught by mutation testing rather than by reading. **The bucketing
|
|
139
|
+
width must stay at or below the shortest shared substring the rule can accept**, or the report
|
|
140
|
+
quietly loses pairs; the first version of the equivalence test read the module constant for both, so
|
|
141
|
+
changing the bucketing width moved the reference implementation with it and the test stayed green -
|
|
142
|
+
it now uses literal contract values. And **the hub filter's count is computed from the same 8-gram
|
|
143
|
+
index** rather than an O(n²) scan, which keeps the whole pass at 0.1s.
|
|
144
|
+
|
|
145
|
+
- **The two tiers compare within a directory, not across the whole vault.** The two concept
|
|
146
|
+
directories are two knowledge bases and `--merge-duplicates` runs per directory, so a group spanning
|
|
147
|
+
them can never be acted on by the tool the report points at. The first version compared across both
|
|
148
|
+
and, after the merge, was still listing `AI 工具` and `GLORIA` as "groups that tool will merge" -
|
|
149
|
+
which was simply false. Cross-line same names are a separate report (`duplicateTitles`).
|
|
150
|
+
|
|
151
|
+
- **`--merge-duplicates` was silently dropping card names from the surviving page's `sources:`.** It
|
|
152
|
+
carried that key over from the main page only, so every merged group lost the absorbed page's
|
|
153
|
+
entries - measured on the real vault, **all 315 groups** lost at least one. The body's source lines
|
|
154
|
+
were always correct (those were unioned); only the frontmatter side was short, and that key is what
|
|
155
|
+
`--relabel` feeds to `source_kinds_for`, so a page could lose a `来源/文章|聊天|收藏` tag. It now
|
|
156
|
+
unions. The 315 pages were repaired from a pre-merge backup, and the `output/` vault is not under
|
|
157
|
+
version control, which is why that backup existed. **The loss turned out to have changed no tag**:
|
|
158
|
+
0 of 22,033 pages carry sources from more than one line, so this was a latent defect rather than a
|
|
159
|
+
live one - recorded that way rather than as a rescue.
|
|
160
|
+
|
|
161
|
+
- **Merging was run on the 314 same-node groups**: 341 pages absorbed (338 article-line, 3 chat-line)
|
|
162
|
+
out of 22,374, leaving 0 groups in that tier. `wiki lint` still reports **0 broken links** - the
|
|
163
|
+
`aliases` written by the merge are what make that true, and it is why no other file had to change.
|
|
164
|
+
|
|
7
165
|
## 1.8.0
|
|
8
166
|
|
|
9
167
|
### Added
|
|
@@ -1974,7 +2132,7 @@ That is the useful form of this result: a decision model proposed 741 merges, a
|
|
|
1974
2132
|
|
|
1975
2133
|
### Fixed
|
|
1976
2134
|
|
|
1977
|
-
- Restored four pieces of matching logic in the HTML exporter that the `
|
|
2135
|
+
- Restored four pieces of matching logic in the HTML exporter that the `2d368c6` clone-consolidation merge had silently dropped, all of which lowered media coverage without failing loudly:
|
|
1978
2136
|
- the `unique:<local_id>` fallback, which matches an image when that id resolves to exactly one distinct picture in the conversation (content-deduped, so the shard-collision risk that rules out a bare `local_id` does not apply);
|
|
1979
2137
|
- `is_encoded_media_type`, needed because WeChat stores some forwards as high-bit variants of type 49 — the mask turns those into a plain 49, which is a registered type, so the branch guarding them had become unreachable;
|
|
1980
2138
|
- the guard that keeps a type-49 row carrying a title or url on the link-card path instead of hiding it behind a cached thumbnail;
|
package/OPERATIONS.md
CHANGED
|
@@ -519,12 +519,19 @@ weflow-cli wiki lint --json # 机器可读
|
|
|
519
519
|
- **同名 / 大小写同名**:同一个名字有多张页,或名字只差大小写——Windows 上后者是同一个文件;
|
|
520
520
|
- **退化字段**:整列几乎同一个值(实测 `topic: AI` 占 18,474/22,374 页)——那个字段等于没携带
|
|
521
521
|
信息,**别照着信**;
|
|
522
|
-
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
522
|
+
- **同一个节点的不同写法**(2026-09-28 起):规范化之后同名,也就是只差空格/连字符/大小写/
|
|
523
|
+
英文复数尾。判据与 `wiki compile --merge-duplicates` 是**同一份实现**(`_utils.normalize_concept_name`),
|
|
524
|
+
所以这份名单是**可以直接执行的**。22,374 张页时实测 314 组;同日按这份名单合并掉 **341 张页**
|
|
525
|
+
(文章线 338、聊天线 3),现在剩 **0 组**。合并后 `wiki lint` 的断链仍是 0——`aliases` 把指向
|
|
526
|
+
旧名字的链接全接住了。**按目录跑**(两个目录是两个知识库),跨线同名由下一节报;
|
|
527
|
+
- **一个名字是另一个加了限定**(同日新增):实测 378 组,**这条是线索不是结论**——人工抽样大约
|
|
528
|
+
一半是真重复(`Agent Harness` / `Agent Harness研讨会`),另一半是"主概念 vs 它的子话题"
|
|
529
|
+
(`国家自然科学基金` / `国家自然科学基金申请书`),那些**不该合并**。判据里专门挡了"枢纽"
|
|
530
|
+
(短名字已被 ≥5 个别名包含,如 `agent` 被 731 个名字包含),但挡不干净,删哪张由人定。
|
|
531
|
+
|
|
532
|
+
这两档取代了旧的"标题高度相似"判据:那条(公共子串 ≥5 字且占较短标题 ≥40%)在 5,062 张页
|
|
533
|
+
时合理,到 22,374 张页时报出 **424,697 组**、完全失去分辨力。换判据的实测记录在
|
|
534
|
+
`near_duplicate_titles` 的 docstring 里(包括被否掉的另外两个方向)。
|
|
528
535
|
|
|
529
536
|
**两条线都是默认增量**:`article-notes` 只处理还没卡的(原笔记改了才重做,`--refresh` 强制重做),
|
|
530
537
|
`chat-notes` 的卡是滚动快照(本来就该覆盖)。所以"补新的"不会把旧的再问一遍。
|
|
@@ -964,6 +971,35 @@ weflow-cli config set assistantFastRoute off # 关(默认)
|
|
|
964
971
|
缺了就不出现在工具表里——摆一个跑不了的工具,模型会去试、拿一个错回来(实测出现过答复里带着
|
|
965
972
|
"两个检索工具都跑不通")。这只挡"跑不了",不挡"暂时没数据":后者工具自己会说该运行什么。
|
|
966
973
|
|
|
974
|
+
**副作用要知道**:工具被藏起来之后,模型**看不见它存在**,所以问"你在读什么书"时它只会答
|
|
975
|
+
"我没有这个工具"。2026-09-28 实测就是这么一轮对话——用户以为功能没做,其实做了、只是没配 key。
|
|
976
|
+
所以缺 key 时它给的那句"没有"要按"没配",不是"没有这功能"来读。
|
|
977
|
+
|
|
978
|
+
### 微信读书的 key 从哪来
|
|
979
|
+
|
|
980
|
+
登录 **https://weread.qq.com/r/weread-skills**,点「快速配置」,页面上会给出你的 `api-key`
|
|
981
|
+
(形如 `wrk-…`)。它调的是官方网关 `https://i.weread.qq.com/api/agent/gateway`。
|
|
982
|
+
|
|
983
|
+
拿到之后两种存法**都认**:
|
|
984
|
+
|
|
985
|
+
```powershell
|
|
986
|
+
weflow-cli config set-env wereadApiKey WEREAD_API_KEY # 从环境变量读,秘密不进命令参数
|
|
987
|
+
weflow-cli config set wereadApiKey wrk-xxxx # 或者直接给值
|
|
988
|
+
```
|
|
989
|
+
|
|
990
|
+
- 本机的配置项是**密文落盘**(`lock:` 开头),与其它密钥一样;
|
|
991
|
+
- 环境变量 `WEREAD_API_KEY` **优先于**配置项——官方文档建议不要把 key 直接交给 AI;
|
|
992
|
+
- 两条路都认是有原因的:助手的 `get_weread` 判据读**配置项**,而 `weflow-cli weread …` 早先
|
|
993
|
+
只读**环境变量**。2026-09-28 之前只认一个,用户按 CLI 的提示配好配置项,助手能用了、
|
|
994
|
+
CLI 却回"未设置"。
|
|
995
|
+
|
|
996
|
+
**改了配置要重启守护进程**:`configService` 在构造时读一次盘,跑着的助手不会自己发现新 key。
|
|
997
|
+
|
|
998
|
+
```powershell
|
|
999
|
+
weflow-cli assistant stop
|
|
1000
|
+
weflow-cli assistant start
|
|
1001
|
+
```
|
|
1002
|
+
|
|
967
1003
|
### 看助手"刚才怎么想的"(决策轨迹)
|
|
968
1004
|
|
|
969
1005
|
助手对外只吐一句答复,中间的判断过程默认看不见。要看得两条路:
|
package/README.en.md
CHANGED
|
@@ -245,7 +245,7 @@ Then just talk to ClawBot on your phone. The assistant queries local chats and f
|
|
|
245
245
|
- "Draft a reply to Lao Wang" — first judges what the other side wants, the risk, and whether substance should be given, then offers a few candidates. **Text only, never sent for you**; when money or high risk is involved it withholds drafts and only says what to confirm first
|
|
246
246
|
- "Remember: my project is called weflow-cli" — writes to long-term memory
|
|
247
247
|
|
|
248
|
-
How it works: the daemon long-polls WeChat's official bot channel (iLink); the agent loop, three-tier memory (working window / rolling summary / long-term facts), and all database queries run on your machine. Only the final question and reply texts go to the configured LLM; phone numbers, emails, and links in tool output are redacted
|
|
248
|
+
How it works: the daemon long-polls WeChat's official bot channel (iLink); the agent loop, three-tier memory (working window / rolling summary / long-term facts), and all database queries run on your machine. Only the final question and reply texts go to the configured LLM; the shipped default is `assistantPrivacy=strict`: phone numbers, emails, and links in tool output are redacted, and third-party chat bodies never leave the machine (`balanced` lets bodies out but still masks PII, `open` masks nothing; a local `ollama` engine keeps everything offline). Sessions expire after 24h of inactivity, and proactive replies per window are capped by official limits.
|
|
249
249
|
|
|
250
250
|
Cost guardrails: a built-in daily cap of 100 processed messages (send "记忆" in WeChat to check usage). The assistant denies all incoming users by default; configure an explicit whitelist before AI calls are enabled:
|
|
251
251
|
|
|
@@ -279,7 +279,7 @@ Management: `weflow-cli assistant status` / `log` / `stop`; send "帮助" in WeC
|
|
|
279
279
|
| Digest & reader | `weflow-cli daily` · `weflow-cli daily-server` · `weflow-cli review` |
|
|
280
280
|
| Moments cache | `weflow-cli sns timeline` · `weflow-cli sns users` · `weflow-cli sns stats` |
|
|
281
281
|
| WeChat favorites | `weflow-cli fav list` · `weflow-cli fav export markdown` · `weflow-cli fav set-key` |
|
|
282
|
-
| WeRead | `weflow-cli weread shelf` · `notes` · `search` · `stats` |
|
|
282
|
+
| WeRead | `weflow-cli weread shelf` · `notes` · `search` · `stats` (get the key from https://weread.qq.com/r/weread-skills; see [OPERATIONS.md](./OPERATIONS.md)) |
|
|
283
283
|
| Knowledge base | `weflow-cli vault` · `weflow-cli wiki` · `weflow-cli search <query>` · `weflow-cli chat` (semantic search needs `config set dashscopeApiKey` first) |
|
|
284
284
|
| Reports & tasks | `weflow-cli report` · `annual-report` · `todos` |
|
|
285
285
|
| Second-brain assistant | `weflow-cli assistant start` · `status` · `log` · `stop` |
|
|
@@ -320,7 +320,7 @@ python scripts/fav_server.py --date YYYY-MM-DD
|
|
|
320
320
|
|
|
321
321
|

|
|
322
322
|
|
|
323
|
-
The project is split into
|
|
323
|
+
The project is split into five clearly bounded parts:
|
|
324
324
|
|
|
325
325
|
| Directory | Responsibility |
|
|
326
326
|
| --- | --- |
|
package/README.md
CHANGED
|
@@ -239,7 +239,7 @@ weflow-cli panel # 打开本机面板窗口 (不扫码也能用)
|
|
|
239
239
|
**只产出文本,不会替你发送**;涉钱或风险很高时不给草稿,只说明该先确认什么
|
|
240
240
|
- 「记住:我的项目叫 weflow-cli」— 写入长期记忆
|
|
241
241
|
|
|
242
|
-
运行机制:守护进程通过微信官方 Bot 通道(iLink)长轮询收发消息,Agent 循环、三层记忆(工作窗口 / 滚动摘要 / 长期事实)、数据库查询全部在本机执行;仅最终提问与回复文本会发送给所配置的 LLM
|
|
242
|
+
运行机制:守护进程通过微信官方 Bot 通道(iLink)长轮询收发消息,Agent 循环、三层记忆(工作窗口 / 滚动摘要 / 长期事实)、数据库查询全部在本机执行;仅最终提问与回复文本会发送给所配置的 LLM,新装默认就是 `assistantPrivacy=strict`:工具输出中的电话/邮箱/链接等 PII 自动脱敏,且第三方聊天正文不出境(`balanced` 放宽到正文可出境、只对 PII 打码,`open` 全不打码;`ollama` 本地引擎则完全不出网)。会话 24 小时未活跃需重新扫码,单窗口内主动回复有官方条数限制。
|
|
243
243
|
|
|
244
244
|
成本护栏:内置每日 100 条处理上限(防异常流量烧钱,微信内发「记忆」可查用量);助手默认拒绝所有来信,必须明确配置白名单后才会触发 AI 调用:
|
|
245
245
|
|
|
@@ -273,7 +273,7 @@ weflow-cli config set assistantGroupRequireMention true
|
|
|
273
273
|
| 公众号日报与阅读器 | `weflow-cli daily` · `weflow-cli daily-server` · `weflow-cli review` |
|
|
274
274
|
| 朋友圈缓存 | `weflow-cli sns timeline` · `weflow-cli sns users` · `weflow-cli sns stats` |
|
|
275
275
|
| 微信收藏 | `weflow-cli fav list` · `weflow-cli fav export markdown` · `weflow-cli fav set-key` |
|
|
276
|
-
| 微信读书 | `weflow-cli weread shelf` · `notes` · `search` · `stats
|
|
276
|
+
| 微信读书 | `weflow-cli weread shelf` · `notes` · `search` · `stats`(key 从 https://weread.qq.com/r/weread-skills 拿,见 [OPERATIONS.md](./OPERATIONS.md)) |
|
|
277
277
|
| 知识库 | `weflow-cli vault` · `weflow-cli wiki` · `weflow-cli search <query>` · `weflow-cli chat`(语义检索需先 `config set dashscopeApiKey`)|
|
|
278
278
|
| 总结与任务 | `weflow-cli report` · `annual-report` · `todos` |
|
|
279
279
|
| 第二大脑助手 | `weflow-cli assistant start` · `status` · `log` · `stop` |
|
|
@@ -314,7 +314,7 @@ python scripts/fav_server.py --date YYYY-MM-DD
|
|
|
314
314
|
|
|
315
315
|

|
|
316
316
|
|
|
317
|
-
|
|
317
|
+
项目分为五个边界清晰的部分:
|
|
318
318
|
|
|
319
319
|
| 目录 | 职责 |
|
|
320
320
|
| --- | --- |
|
package/bin/weflow-cli.ts
CHANGED
|
@@ -4781,8 +4781,10 @@ program
|
|
|
4781
4781
|
}
|
|
4782
4782
|
|
|
4783
4783
|
async function getWereadService() {
|
|
4784
|
-
|
|
4784
|
+
// key 的两个来源与优先级见 `resolveWereadApiKey`(抽出去是为了能被测到 ——
|
|
4785
|
+
// 只读环境变量那版害得用户配好配置项之后 `weread shelf` 仍然报"未设置")。
|
|
4785
4786
|
const mod = await import('../src/services/wereadService.js')
|
|
4787
|
+
const key = mod.resolveWereadApiKey(process.env.WEREAD_API_KEY, configService.get('wereadApiKey'))
|
|
4786
4788
|
return new mod.WereadService(key)
|
|
4787
4789
|
}
|
|
4788
4790
|
|
package/dist/bin/weflow-cli.js
CHANGED
|
@@ -5008,8 +5008,10 @@ async function runPythonCmd(script, args, apiKey, apiKeyVariable = 'DEEPSEEK_API
|
|
|
5008
5008
|
}
|
|
5009
5009
|
}
|
|
5010
5010
|
async function getWereadService() {
|
|
5011
|
-
|
|
5011
|
+
// key 的两个来源与优先级见 `resolveWereadApiKey`(抽出去是为了能被测到 ——
|
|
5012
|
+
// 只读环境变量那版害得用户配好配置项之后 `weread shelf` 仍然报"未设置")。
|
|
5012
5013
|
const mod = await import('../src/services/wereadService.js');
|
|
5014
|
+
const key = mod.resolveWereadApiKey(process.env.WEREAD_API_KEY, configService.get('wereadApiKey'));
|
|
5013
5015
|
return new mod.WereadService(key);
|
|
5014
5016
|
}
|
|
5015
5017
|
// semantic-search
|