weflow-cli 1.6.0 → 1.6.2
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 +30 -1
- package/README.md +2 -0
- package/bin/weflow-cli.ts +58 -11
- package/dist/bin/weflow-cli.js +59 -11
- package/dist/bin/weflow-cli.js.map +1 -1
- package/dist/src/core/ntCore.d.ts.map +1 -1
- package/dist/src/core/ntCore.js +17 -1
- package/dist/src/core/ntCore.js.map +1 -1
- package/dist/src/services/chatService.d.ts +7 -0
- package/dist/src/services/chatService.d.ts.map +1 -1
- package/dist/src/services/chatService.js +15 -5
- package/dist/src/services/chatService.js.map +1 -1
- package/dist/src/services/exportService.d.ts.map +1 -1
- package/dist/src/services/exportService.js +15 -3
- package/dist/src/services/exportService.js.map +1 -1
- package/dist/src/utils/pythonProcessEnv.d.ts.map +1 -1
- package/dist/src/utils/pythonProcessEnv.js +16 -1
- package/dist/src/utils/pythonProcessEnv.js.map +1 -1
- package/docs/HEALTH-CHECK.md +98 -0
- package/docs/RELEASING.md +177 -0
- package/package.json +1 -1
- package/scripts/biz_daily.py +3 -1
- package/scripts/export_chat_html.py +9 -0
- package/scripts/health_check.py +336 -0
- package/scripts/nt_decrypt.py +1352 -1207
- package/scripts/watch_issues.py +212 -0
- package/scripts/watch_mail.py +131 -0
- package/src/core/ntCore.ts +17 -1
- package/src/services/chatService.ts +14 -5
- package/src/services/exportService.ts +15 -3
- package/src/utils/pythonProcessEnv.ts +18 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,11 +4,40 @@ 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.6.2
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- Read every message shard, not just the configured one. WeChat rolls a conversation into a new `message_N.db` over time and encrypts each shard with its own PBKDF2-derived key. `sessions`, `messages`, `contacts`, `export json/txt/excel`, `evidence` and the MCP server opened only `message_0.db` with the single configured key, so anything written after the last shard roll was **invisible** - and the commands still reported success. On the machine this was found on, one conversation showed 31 messages ending 2026-08-30 instead of 1145 ending 2026-09-17. Only `export html` merged shards (its Python exporter always had), which is why the two read paths disagreed.
|
|
12
|
+
- `export <talker> html --limit N` now honours the limit. It reached only the fallback renderer; the primary path passed the flag nowhere, so a capped export of a busy chat silently produced the entire history.
|
|
13
|
+
- `export <talker> excel` works at all. `exceljs` is CJS-only, so `await import('exceljs')` yields a namespace whose only member is `default`; `new ExcelJS.Workbook()` on the namespace is a `TypeError`, which a bare `catch {}` turned into the uninformative "Excel 导出失败". The reason is now reported too.
|
|
14
|
+
- Group messages no longer show the sender's own `wxid_...:` prefix in the text (`波: [强]`, not `波: wxid_ogfiei1l1ye722: [强]`). Only `parsedContent` is normalised; `content`/`rawContent` keep the stored value.
|
|
15
|
+
- `contacts` no longer emits a blank row for `Name2Id`'s placeholder entry.
|
|
16
|
+
- `fav list` no longer blames the data channel when the actual blocker is a missing favorites key. Added `check --json` → `favoritesReady`, which distinguishes "database found" from "usable".
|
|
17
|
+
- Subprocess failures now include the last stderr line, redacted of key-shaped strings. A missing config key used to surface as `统计失败 (exit 1)` with no cause; it now names the cause and the command that fixes it.
|
|
18
|
+
- `daily-stats` / `daily` no longer tell users to run `config set bizKey`, which the CLI rejects as an unwritable key.
|
|
19
|
+
- `init --refresh` no longer fails with "密钥提取失败" when a perfectly good key is already configured. The hook only fires at the login moment, so a refresh run against an already-logged-in WeChat always times out; the fallback then consulted **only** `favPassphrase`, which `init` itself never writes (it writes `decryptKey`, and `favPassphrase` is set only when a usable `favorite.db` exists). Reads use `favPassphrase || decryptKey`, so the fallback rejected keys the rest of the tool was happily using. Reported as "最新版本的微信密钥解不开了" (Issue #9) after a WeChat upgrade, where `init --refresh` is exactly what the CLI tells users to run. The fallback now matches the read path, and the summary distinguishes a fresh capture ("密钥获取成功") from reusing what was configured ("已沿用配置中的密钥") instead of claiming success either way. Reaching that point also lets `enableFavorites` run, so favorites start working for users who previously died here.
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- `scripts/health_check.py` and `docs/HEALTH-CHECK.md`: a periodic, zero-token health check whose exit code is the verdict, covering version drift, shard read consistency, session freshness, export formats and the watcher tasks.
|
|
24
|
+
|
|
25
|
+
## 1.6.1
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
- Report the real version from `--version` and `capabilities`. The version was a literal in the CLI source and `npm version` only rewrites `package.json`, so the 1.6.0 package announced itself as `1.5.1` - which made a user's bug report impossible to tell apart from a stale install, and took a clean install to disprove.
|
|
30
|
+
- Keep the discovered database list when the NT scan cannot read WeChat's memory. `nt_decrypt.py scan` returned early on "Weixin.exe 未运行" *before* walking the filesystem, and the caller discarded the whole result on any error. The passphrase-derivation path - the correct one for current WeChat, and one that needs only the file list - therefore never ran, so a run that had already captured the passphrase still ended with no usable keys and `sessions` reported "WCDB 初始化失败: -1006".
|
|
31
|
+
|
|
32
|
+
### Documentation
|
|
33
|
+
|
|
34
|
+
- Added `docs/RELEASING.md`: versioning rules, the pre-publish check for local media and keys, npm credentials with 2FA, and the China-mirror sync step that otherwise leaves users unable to install a fresh release.
|
|
35
|
+
|
|
7
36
|
## 1.6.0
|
|
8
37
|
|
|
9
38
|
### Documentation
|
|
10
39
|
|
|
11
|
-
- Synchronized setup, operations, architecture, security, MCP, and maintenance guidance with the current `1.6.
|
|
40
|
+
- Synchronized setup, operations, architecture, security, MCP, and maintenance guidance with the current `1.6.1` source baseline.
|
|
12
41
|
- Clarified source-versus-npm version drift, no-AI daily runs, staged data-directory discovery, media-export limitations, and local-data privacy boundaries.
|
|
13
42
|
- Replaced the outdated architecture image with a GPT-image-2 diagram covering current CLI, MCP, service, workflow, data, and privacy boundaries.
|
|
14
43
|
|
package/README.md
CHANGED
|
@@ -321,6 +321,8 @@ python scripts/fav_server.py --date YYYY-MM-DD
|
|
|
321
321
|
- [项目维护状态](./docs/PROJECT_STATE.md):当前能力、限制、优先级与交接入口。
|
|
322
322
|
- [技术决策记录](./docs/DECISIONS.md):长期维护中的关键设计取舍。
|
|
323
323
|
- [分支与合并记录](./docs/BRANCHES.md):分支用途、合并时间线与并行开发的对齐约定。
|
|
324
|
+
- [发布清单](./docs/RELEASING.md):版本号、打包敏感内容检查、npm 凭据、国内镜像同步。
|
|
325
|
+
- [定期体检](./docs/HEALTH-CHECK.md):一条命令查出版本漂移、分片漏读、会话不更新与导出失败。
|
|
324
326
|
- [电子数据证据指南](./docs/EVIDENCE_GUIDE.md):证据保全、法律边界与使用注意事项。
|
|
325
327
|
- [贡献指南](./CONTRIBUTING.md) 与 [安全策略](./SECURITY.md):开发、反馈和敏感问题处理。
|
|
326
328
|
- [变更记录](./CHANGELOG.md):版本更新摘要。
|
package/bin/weflow-cli.ts
CHANGED
|
@@ -28,6 +28,26 @@ function resolvePackageRoot(): string {
|
|
|
28
28
|
return resolvePackageRootFrom(import.meta.url)
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Version reported by `--version` and `capabilities`.
|
|
33
|
+
*
|
|
34
|
+
* Read from package.json instead of written here. A literal has to be updated
|
|
35
|
+
* by hand on every release, and when that is forgotten `--version` lies about
|
|
36
|
+
* what is installed - which is exactly what happened: the 1.6.0 package
|
|
37
|
+
* shipped a hardcoded `1.5.1`, so a user's bug report could not be told apart
|
|
38
|
+
* from a stale install, and diagnosing it needed a clean install to disprove.
|
|
39
|
+
*/
|
|
40
|
+
function resolveCliVersion(): string {
|
|
41
|
+
try {
|
|
42
|
+
const pkg = JSON.parse(readFileSync(join(resolvePackageRoot(), 'package.json'), 'utf8'))
|
|
43
|
+
return String(pkg.version || '0.0.0')
|
|
44
|
+
} catch {
|
|
45
|
+
return '0.0.0'
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const CLI_VERSION = resolveCliVersion()
|
|
50
|
+
|
|
31
51
|
function pythonProcessEnv(apiKey?: string, variable = 'DEEPSEEK_API_KEY'): NodeJS.ProcessEnv {
|
|
32
52
|
return createPythonProcessEnv(apiKey ? { [variable]: apiKey } : {})
|
|
33
53
|
}
|
|
@@ -247,7 +267,7 @@ async function resolveTalker(input: string, quiet = false, nonInteractive = fals
|
|
|
247
267
|
program
|
|
248
268
|
.name('weflow-cli')
|
|
249
269
|
.description('WeFlow CLI - 微信聊天记录命令行查询与导出工具')
|
|
250
|
-
.version(
|
|
270
|
+
.version(CLI_VERSION)
|
|
251
271
|
|
|
252
272
|
program
|
|
253
273
|
.command('capabilities')
|
|
@@ -256,7 +276,7 @@ program
|
|
|
256
276
|
.action((opts) => {
|
|
257
277
|
const data = {
|
|
258
278
|
schema: 'weflow-capabilities/v1',
|
|
259
|
-
version:
|
|
279
|
+
version: CLI_VERSION,
|
|
260
280
|
read: {
|
|
261
281
|
sessions: { cli: 'sessions --json', mcp: 'wechat.list_sessions' },
|
|
262
282
|
messages: { cli: 'messages <talker> --json', mcp: 'wechat.export_messages' },
|
|
@@ -665,6 +685,8 @@ program
|
|
|
665
685
|
console.log(chalk.gray(' 尝试从 WeFlow 桌面版配置读取...'))
|
|
666
686
|
let extractedKey = opts.testMissingKeys ? '' : tryReadWeFlowKey()
|
|
667
687
|
let linuxNtKey = ''
|
|
688
|
+
/** 密钥是本次从 hook 捕获的, 还是沿用已有的 - 摘要要说准, 不能一律报"获取成功" */
|
|
689
|
+
let keyCaptured = false
|
|
668
690
|
|
|
669
691
|
if (extractedKey) {
|
|
670
692
|
console.log(chalk.green(' ✓ 从 WeFlow 配置读取到密钥'))
|
|
@@ -750,11 +772,17 @@ program
|
|
|
750
772
|
|
|
751
773
|
if (keyResult.success && keyResult.key) {
|
|
752
774
|
extractedKey = keyResult.key
|
|
775
|
+
keyCaptured = true
|
|
753
776
|
} else {
|
|
754
|
-
// hook 只在登录瞬间触发; 微信已登录时捕获不到 →
|
|
755
|
-
|
|
777
|
+
// hook 只在登录瞬间触发; 微信已登录时捕获不到 → 回退到已有密钥。
|
|
778
|
+
// decryptKey 也必须算数: init 成功时写入的就是它, 而 favPassphrase
|
|
779
|
+
// 仅在收藏库存在且验证通过时才会被设置。只看 favPassphrase 会让
|
|
780
|
+
// `init --refresh` 在一把完全可用的密钥面前报「密钥提取失败」——
|
|
781
|
+
// 而那正是 CLI 自己在微信迁移后建议用户执行的命令。
|
|
782
|
+
const fallback = configService.get('favPassphrase') || configService.get('decryptKey') || ''
|
|
756
783
|
if (fallback) {
|
|
757
|
-
console.log(chalk.gray(' Hook 未捕获到密钥 (微信已登录时不再触发密钥函数)
|
|
784
|
+
console.log(chalk.gray(' Hook 未捕获到密钥 (微信已登录时不再触发密钥函数)'))
|
|
785
|
+
console.log(chalk.gray(' 检测到已配置的密钥, 沿用它并重新验证各库...'))
|
|
758
786
|
extractedKey = fallback
|
|
759
787
|
} else {
|
|
760
788
|
console.log(chalk.red(`\n✗ 密钥提取失败: ${keyResult.error}`))
|
|
@@ -769,7 +797,8 @@ program
|
|
|
769
797
|
|
|
770
798
|
if (extractedKey) {
|
|
771
799
|
configService.set('decryptKey', extractedKey)
|
|
772
|
-
console.log(chalk.green('\n✓ 密钥获取成功!'))
|
|
800
|
+
if (keyCaptured) console.log(chalk.green('\n✓ 密钥获取成功!'))
|
|
801
|
+
else console.log(chalk.green('\n✓ 已沿用配置中的密钥 (本次未重新捕获)'))
|
|
773
802
|
} else {
|
|
774
803
|
console.log(chalk.green('\n✓ NT 密钥配置完成!'))
|
|
775
804
|
}
|
|
@@ -2499,14 +2528,26 @@ favCmd
|
|
|
2499
2528
|
else console.log(chalk.red(`\n❌ 数据库连接失败: ${conn.error}\n`))
|
|
2500
2529
|
process.exit(1)
|
|
2501
2530
|
}
|
|
2502
|
-
|
|
2531
|
+
const favReason = chatService.favUnavailableReason()
|
|
2532
|
+
if (favReason) {
|
|
2533
|
+
const detail = {
|
|
2534
|
+
channel: '当前数据通道不支持收藏查询 (需 4.x NT 连接)',
|
|
2535
|
+
path: '未找到收藏数据库 (favorite.db),请确认微信已登录并产生过收藏',
|
|
2536
|
+
key: '收藏数据库已找到,但缺少密钥',
|
|
2537
|
+
}[favReason]
|
|
2503
2538
|
if (opts.json) {
|
|
2504
|
-
console.log(JSON.stringify({ success: false, code: 'FAVORITES_UNAVAILABLE', error:
|
|
2539
|
+
console.log(JSON.stringify({ success: false, code: 'FAVORITES_UNAVAILABLE', reason: favReason, error: detail }))
|
|
2505
2540
|
process.exit(1)
|
|
2506
2541
|
}
|
|
2507
|
-
console.log(chalk.red(
|
|
2508
|
-
|
|
2509
|
-
|
|
2542
|
+
console.log(chalk.red(`\n❌ ${detail}`))
|
|
2543
|
+
if (favReason === 'key') {
|
|
2544
|
+
console.log(chalk.gray(' 请先配置收藏密钥: weflow-cli fav set-key <64位hex密钥>'))
|
|
2545
|
+
console.log(chalk.gray(' 或设置全库 passphrase: weflow-cli fav set-key --passphrase <64位hex>'))
|
|
2546
|
+
}
|
|
2547
|
+
if (favReason === 'path') {
|
|
2548
|
+
console.log(chalk.gray(' 可手动指定: weflow-cli config set favDbPath <favorite.db 路径>'))
|
|
2549
|
+
}
|
|
2550
|
+
console.log('')
|
|
2510
2551
|
process.exit(1)
|
|
2511
2552
|
}
|
|
2512
2553
|
|
|
@@ -5342,6 +5383,12 @@ program
|
|
|
5342
5383
|
messageDatabase: !!configService.get('ntDbPath') && existsSync(configService.get('ntDbPath')),
|
|
5343
5384
|
momentsDatabase: !!configService.get('snsDbPath') && existsSync(configService.get('snsDbPath')),
|
|
5344
5385
|
favoritesDatabase: !!configService.get('favDbPath') && existsSync(configService.get('favDbPath')),
|
|
5386
|
+
// `favoritesDatabase` only says the file is there. Reading it also
|
|
5387
|
+
// needs a key, and a caller that took the former for "usable" would
|
|
5388
|
+
// attempt favorites and always fail.
|
|
5389
|
+
favoritesReady: !!configService.get('favDbPath')
|
|
5390
|
+
&& existsSync(configService.get('favDbPath'))
|
|
5391
|
+
&& (!!configService.get('favKey') || !!configService.get('favPassphrase')),
|
|
5345
5392
|
},
|
|
5346
5393
|
assistant: {
|
|
5347
5394
|
engine,
|
package/dist/bin/weflow-cli.js
CHANGED
|
@@ -24,6 +24,25 @@ const program = new Command();
|
|
|
24
24
|
function resolvePackageRoot() {
|
|
25
25
|
return resolvePackageRootFrom(import.meta.url);
|
|
26
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Version reported by `--version` and `capabilities`.
|
|
29
|
+
*
|
|
30
|
+
* Read from package.json instead of written here. A literal has to be updated
|
|
31
|
+
* by hand on every release, and when that is forgotten `--version` lies about
|
|
32
|
+
* what is installed - which is exactly what happened: the 1.6.0 package
|
|
33
|
+
* shipped a hardcoded `1.5.1`, so a user's bug report could not be told apart
|
|
34
|
+
* from a stale install, and diagnosing it needed a clean install to disprove.
|
|
35
|
+
*/
|
|
36
|
+
function resolveCliVersion() {
|
|
37
|
+
try {
|
|
38
|
+
const pkg = JSON.parse(readFileSync(join(resolvePackageRoot(), 'package.json'), 'utf8'));
|
|
39
|
+
return String(pkg.version || '0.0.0');
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return '0.0.0';
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const CLI_VERSION = resolveCliVersion();
|
|
27
46
|
function pythonProcessEnv(apiKey, variable = 'DEEPSEEK_API_KEY') {
|
|
28
47
|
return createPythonProcessEnv(apiKey ? { [variable]: apiKey } : {});
|
|
29
48
|
}
|
|
@@ -231,7 +250,7 @@ async function resolveTalker(input, quiet = false, nonInteractive = false) {
|
|
|
231
250
|
program
|
|
232
251
|
.name('weflow-cli')
|
|
233
252
|
.description('WeFlow CLI - 微信聊天记录命令行查询与导出工具')
|
|
234
|
-
.version(
|
|
253
|
+
.version(CLI_VERSION);
|
|
235
254
|
program
|
|
236
255
|
.command('capabilities')
|
|
237
256
|
.description('输出 AI 可调用的功能能力清单')
|
|
@@ -239,7 +258,7 @@ program
|
|
|
239
258
|
.action((opts) => {
|
|
240
259
|
const data = {
|
|
241
260
|
schema: 'weflow-capabilities/v1',
|
|
242
|
-
version:
|
|
261
|
+
version: CLI_VERSION,
|
|
243
262
|
read: {
|
|
244
263
|
sessions: { cli: 'sessions --json', mcp: 'wechat.list_sessions' },
|
|
245
264
|
messages: { cli: 'messages <talker> --json', mcp: 'wechat.export_messages' },
|
|
@@ -639,6 +658,8 @@ program
|
|
|
639
658
|
console.log(chalk.gray(' 尝试从 WeFlow 桌面版配置读取...'));
|
|
640
659
|
let extractedKey = opts.testMissingKeys ? '' : tryReadWeFlowKey();
|
|
641
660
|
let linuxNtKey = '';
|
|
661
|
+
/** 密钥是本次从 hook 捕获的, 还是沿用已有的 - 摘要要说准, 不能一律报"获取成功" */
|
|
662
|
+
let keyCaptured = false;
|
|
642
663
|
if (extractedKey) {
|
|
643
664
|
console.log(chalk.green(' ✓ 从 WeFlow 配置读取到密钥'));
|
|
644
665
|
}
|
|
@@ -725,12 +746,18 @@ program
|
|
|
725
746
|
});
|
|
726
747
|
if (keyResult.success && keyResult.key) {
|
|
727
748
|
extractedKey = keyResult.key;
|
|
749
|
+
keyCaptured = true;
|
|
728
750
|
}
|
|
729
751
|
else {
|
|
730
|
-
// hook 只在登录瞬间触发; 微信已登录时捕获不到 →
|
|
731
|
-
|
|
752
|
+
// hook 只在登录瞬间触发; 微信已登录时捕获不到 → 回退到已有密钥。
|
|
753
|
+
// decryptKey 也必须算数: init 成功时写入的就是它, 而 favPassphrase
|
|
754
|
+
// 仅在收藏库存在且验证通过时才会被设置。只看 favPassphrase 会让
|
|
755
|
+
// `init --refresh` 在一把完全可用的密钥面前报「密钥提取失败」——
|
|
756
|
+
// 而那正是 CLI 自己在微信迁移后建议用户执行的命令。
|
|
757
|
+
const fallback = configService.get('favPassphrase') || configService.get('decryptKey') || '';
|
|
732
758
|
if (fallback) {
|
|
733
|
-
console.log(chalk.gray(' Hook 未捕获到密钥 (微信已登录时不再触发密钥函数)
|
|
759
|
+
console.log(chalk.gray(' Hook 未捕获到密钥 (微信已登录时不再触发密钥函数)'));
|
|
760
|
+
console.log(chalk.gray(' 检测到已配置的密钥, 沿用它并重新验证各库...'));
|
|
734
761
|
extractedKey = fallback;
|
|
735
762
|
}
|
|
736
763
|
else {
|
|
@@ -745,7 +772,10 @@ program
|
|
|
745
772
|
}
|
|
746
773
|
if (extractedKey) {
|
|
747
774
|
configService.set('decryptKey', extractedKey);
|
|
748
|
-
|
|
775
|
+
if (keyCaptured)
|
|
776
|
+
console.log(chalk.green('\n✓ 密钥获取成功!'));
|
|
777
|
+
else
|
|
778
|
+
console.log(chalk.green('\n✓ 已沿用配置中的密钥 (本次未重新捕获)'));
|
|
749
779
|
}
|
|
750
780
|
else {
|
|
751
781
|
console.log(chalk.green('\n✓ NT 密钥配置完成!'));
|
|
@@ -2569,14 +2599,26 @@ favCmd
|
|
|
2569
2599
|
console.log(chalk.red(`\n❌ 数据库连接失败: ${conn.error}\n`));
|
|
2570
2600
|
process.exit(1);
|
|
2571
2601
|
}
|
|
2572
|
-
|
|
2602
|
+
const favReason = chatService.favUnavailableReason();
|
|
2603
|
+
if (favReason) {
|
|
2604
|
+
const detail = {
|
|
2605
|
+
channel: '当前数据通道不支持收藏查询 (需 4.x NT 连接)',
|
|
2606
|
+
path: '未找到收藏数据库 (favorite.db),请确认微信已登录并产生过收藏',
|
|
2607
|
+
key: '收藏数据库已找到,但缺少密钥',
|
|
2608
|
+
}[favReason];
|
|
2573
2609
|
if (opts.json) {
|
|
2574
|
-
console.log(JSON.stringify({ success: false, code: 'FAVORITES_UNAVAILABLE', error:
|
|
2610
|
+
console.log(JSON.stringify({ success: false, code: 'FAVORITES_UNAVAILABLE', reason: favReason, error: detail }));
|
|
2575
2611
|
process.exit(1);
|
|
2576
2612
|
}
|
|
2577
|
-
console.log(chalk.red(
|
|
2578
|
-
|
|
2579
|
-
|
|
2613
|
+
console.log(chalk.red(`\n❌ ${detail}`));
|
|
2614
|
+
if (favReason === 'key') {
|
|
2615
|
+
console.log(chalk.gray(' 请先配置收藏密钥: weflow-cli fav set-key <64位hex密钥>'));
|
|
2616
|
+
console.log(chalk.gray(' 或设置全库 passphrase: weflow-cli fav set-key --passphrase <64位hex>'));
|
|
2617
|
+
}
|
|
2618
|
+
if (favReason === 'path') {
|
|
2619
|
+
console.log(chalk.gray(' 可手动指定: weflow-cli config set favDbPath <favorite.db 路径>'));
|
|
2620
|
+
}
|
|
2621
|
+
console.log('');
|
|
2580
2622
|
process.exit(1);
|
|
2581
2623
|
}
|
|
2582
2624
|
let favType;
|
|
@@ -5544,6 +5586,12 @@ program
|
|
|
5544
5586
|
messageDatabase: !!configService.get('ntDbPath') && existsSync(configService.get('ntDbPath')),
|
|
5545
5587
|
momentsDatabase: !!configService.get('snsDbPath') && existsSync(configService.get('snsDbPath')),
|
|
5546
5588
|
favoritesDatabase: !!configService.get('favDbPath') && existsSync(configService.get('favDbPath')),
|
|
5589
|
+
// `favoritesDatabase` only says the file is there. Reading it also
|
|
5590
|
+
// needs a key, and a caller that took the former for "usable" would
|
|
5591
|
+
// attempt favorites and always fail.
|
|
5592
|
+
favoritesReady: !!configService.get('favDbPath')
|
|
5593
|
+
&& existsSync(configService.get('favDbPath'))
|
|
5594
|
+
&& (!!configService.get('favKey') || !!configService.get('favPassphrase')),
|
|
5547
5595
|
},
|
|
5548
5596
|
assistant: {
|
|
5549
5597
|
engine,
|