weflow-cli 1.5.0 → 1.6.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.
Files changed (332) hide show
  1. package/ARCHITECTURE.md +105 -0
  2. package/CHANGELOG.md +121 -0
  3. package/CONTRIBUTING.md +45 -0
  4. package/LICENSE +21 -21
  5. package/OPERATIONS.md +272 -0
  6. package/README.en.md +281 -0
  7. package/README.md +334 -149
  8. package/SECURITY.md +47 -0
  9. package/bin/weflow-cli.ts +4050 -581
  10. package/dist/bin/weflow-cli.js +4310 -588
  11. package/dist/bin/weflow-cli.js.map +1 -1
  12. package/dist/mcp-server/index.js +178 -236
  13. package/dist/mcp-server/index.js.map +1 -1
  14. package/dist/src/core/dbPathService.d.ts +15 -1
  15. package/dist/src/core/dbPathService.d.ts.map +1 -1
  16. package/dist/src/core/dbPathService.js +177 -19
  17. package/dist/src/core/dbPathService.js.map +1 -1
  18. package/dist/src/core/keyService.d.ts +8 -0
  19. package/dist/src/core/keyService.d.ts.map +1 -1
  20. package/dist/src/core/keyService.js +127 -22
  21. package/dist/src/core/keyService.js.map +1 -1
  22. package/dist/src/core/ntCore.d.ts +59 -1
  23. package/dist/src/core/ntCore.d.ts.map +1 -1
  24. package/dist/src/core/ntCore.js +201 -65
  25. package/dist/src/core/ntCore.js.map +1 -1
  26. package/dist/src/core/sqlcipherCore.d.ts.map +1 -1
  27. package/dist/src/core/sqlcipherCore.js +18 -1
  28. package/dist/src/core/sqlcipherCore.js.map +1 -1
  29. package/dist/src/core/wcdbCore.d.ts.map +1 -1
  30. package/dist/src/core/wcdbCore.js +3 -6
  31. package/dist/src/core/wcdbCore.js.map +1 -1
  32. package/dist/src/services/assistantDaemon.d.ts +19 -0
  33. package/dist/src/services/assistantDaemon.d.ts.map +1 -0
  34. package/dist/src/services/assistantDaemon.js +117 -0
  35. package/dist/src/services/assistantDaemon.js.map +1 -0
  36. package/dist/src/services/assistantMemory.d.ts +36 -0
  37. package/dist/src/services/assistantMemory.d.ts.map +1 -0
  38. package/dist/src/services/assistantMemory.js +182 -0
  39. package/dist/src/services/assistantMemory.js.map +1 -0
  40. package/dist/src/services/assistantPrivacy.d.ts +25 -0
  41. package/dist/src/services/assistantPrivacy.d.ts.map +1 -0
  42. package/dist/src/services/assistantPrivacy.js +77 -0
  43. package/dist/src/services/assistantPrivacy.js.map +1 -0
  44. package/dist/src/services/assistantRouting.d.ts +18 -0
  45. package/dist/src/services/assistantRouting.d.ts.map +1 -0
  46. package/dist/src/services/assistantRouting.js +68 -0
  47. package/dist/src/services/assistantRouting.js.map +1 -0
  48. package/dist/src/services/assistantService.d.ts +37 -0
  49. package/dist/src/services/assistantService.d.ts.map +1 -0
  50. package/dist/src/services/assistantService.js +284 -0
  51. package/dist/src/services/assistantService.js.map +1 -0
  52. package/dist/src/services/assistantTools.d.ts +24 -0
  53. package/dist/src/services/assistantTools.d.ts.map +1 -0
  54. package/dist/src/services/assistantTools.js +582 -0
  55. package/dist/src/services/assistantTools.js.map +1 -0
  56. package/dist/src/services/chatService.d.ts +44 -0
  57. package/dist/src/services/chatService.d.ts.map +1 -1
  58. package/dist/src/services/chatService.js +105 -4
  59. package/dist/src/services/chatService.js.map +1 -1
  60. package/dist/src/services/configService.d.ts +55 -0
  61. package/dist/src/services/configService.d.ts.map +1 -1
  62. package/dist/src/services/configService.js +147 -6
  63. package/dist/src/services/configService.js.map +1 -1
  64. package/dist/src/services/evidenceService.d.ts +30 -0
  65. package/dist/src/services/evidenceService.d.ts.map +1 -0
  66. package/dist/src/services/evidenceService.js +98 -0
  67. package/dist/src/services/evidenceService.js.map +1 -0
  68. package/dist/src/services/exportService.d.ts +13 -20
  69. package/dist/src/services/exportService.d.ts.map +1 -1
  70. package/dist/src/services/exportService.js +113 -47
  71. package/dist/src/services/exportService.js.map +1 -1
  72. package/dist/src/services/initKeyService.d.ts +19 -0
  73. package/dist/src/services/initKeyService.d.ts.map +1 -0
  74. package/dist/src/services/initKeyService.js +80 -0
  75. package/dist/src/services/initKeyService.js.map +1 -0
  76. package/dist/src/services/messageContract.d.ts +23 -0
  77. package/dist/src/services/messageContract.d.ts.map +1 -0
  78. package/dist/src/services/messageContract.js +49 -0
  79. package/dist/src/services/messageContract.js.map +1 -0
  80. package/dist/src/services/messageQuery.d.ts +7 -0
  81. package/dist/src/services/messageQuery.d.ts.map +1 -0
  82. package/dist/src/services/messageQuery.js +30 -0
  83. package/dist/src/services/messageQuery.js.map +1 -0
  84. package/dist/src/services/wechat-formatter.js +14 -14
  85. package/dist/src/services/wechatMessageService.d.ts.map +1 -1
  86. package/dist/src/services/wechatMessageService.js +31 -3
  87. package/dist/src/services/wechatMessageService.js.map +1 -1
  88. package/dist/src/services/whitelistService.d.ts +52 -4
  89. package/dist/src/services/whitelistService.d.ts.map +1 -1
  90. package/dist/src/services/whitelistService.js +183 -17
  91. package/dist/src/services/whitelistService.js.map +1 -1
  92. package/dist/src/types.d.ts +20 -0
  93. package/dist/src/types.d.ts.map +1 -1
  94. package/dist/src/utils/dateRange.d.ts +15 -0
  95. package/dist/src/utils/dateRange.d.ts.map +1 -0
  96. package/dist/src/utils/dateRange.js +48 -0
  97. package/dist/src/utils/dateRange.js.map +1 -0
  98. package/dist/src/utils/mcpSecurity.d.ts +5 -0
  99. package/dist/src/utils/mcpSecurity.d.ts.map +1 -0
  100. package/dist/src/utils/mcpSecurity.js +39 -0
  101. package/dist/src/utils/mcpSecurity.js.map +1 -0
  102. package/dist/src/utils/packageRoot.d.ts +2 -0
  103. package/dist/src/utils/packageRoot.d.ts.map +1 -0
  104. package/dist/src/utils/packageRoot.js +16 -0
  105. package/dist/src/utils/packageRoot.js.map +1 -0
  106. package/dist/src/utils/python.d.ts +2 -0
  107. package/dist/src/utils/python.d.ts.map +1 -0
  108. package/dist/src/utils/python.js +72 -0
  109. package/dist/src/utils/python.js.map +1 -0
  110. package/dist/src/utils/pythonProcessEnv.d.ts +3 -0
  111. package/dist/src/utils/pythonProcessEnv.d.ts.map +1 -0
  112. package/dist/src/utils/pythonProcessEnv.js +46 -0
  113. package/dist/src/utils/pythonProcessEnv.js.map +1 -0
  114. package/dist/src/utils/talkerUtils.d.ts +4 -1
  115. package/dist/src/utils/talkerUtils.d.ts.map +1 -1
  116. package/dist/src/utils/talkerUtils.js +9 -9
  117. package/dist/src/utils/talkerUtils.js.map +1 -1
  118. package/dist/src/utils/wechatEmoji.d.ts +5 -0
  119. package/dist/src/utils/wechatEmoji.d.ts.map +1 -0
  120. package/dist/src/utils/wechatEmoji.js +35 -0
  121. package/dist/src/utils/wechatEmoji.js.map +1 -0
  122. package/docs/AI_INTERFACE.md +189 -0
  123. package/docs/BRANCHES.md +87 -0
  124. package/docs/DATA_CONTRACT.md +74 -0
  125. package/docs/DECISIONS.md +270 -0
  126. package/docs/DEEPSEEK_V4_FLASH/346/226/275/345/267/245/346/226/207/346/241/243.md +234 -0
  127. package/docs/EVIDENCE_GUIDE.md +96 -0
  128. package/docs/MCP.md +95 -0
  129. package/docs/PARTNERS.md +41 -0
  130. package/docs/PROJECT_STATE.md +96 -0
  131. package/docs/RELEASING.md +124 -0
  132. package/docs/ROADMAP.md +191 -0
  133. package/docs/SETUP.md +103 -0
  134. package/docs/images/weflow-architecture-gpt-image-2.png +0 -0
  135. package/docs/images/weflow-architecture.png +0 -0
  136. package/docs/images/weflow-architecture.svg +65 -0
  137. package/mcp-server/index.ts +169 -269
  138. package/package.json +81 -72
  139. package/requirements-3x.txt +4 -0
  140. package/requirements-voice.txt +15 -0
  141. package/requirements.txt +9 -0
  142. package/resources/js/marked.min.js +69 -0
  143. package/resources/wechat-emoji/666.png +0 -0
  144. package/resources/wechat-emoji/Awesome.png +0 -0
  145. package/resources/wechat-emoji/Concerned.png +0 -0
  146. package/resources/wechat-emoji/Cry.png +0 -0
  147. package/resources/wechat-emoji/Emm.png +0 -0
  148. package/resources/wechat-emoji/Facepalm.png +0 -0
  149. package/resources/wechat-emoji/Grin.png +0 -0
  150. package/resources/wechat-emoji/OK.png +0 -0
  151. package/resources/wechat-emoji/Respect.png +0 -0
  152. package/resources/wechat-emoji/Sick.png +0 -0
  153. package/resources/wechat-emoji/Sleep.png +0 -0
  154. package/resources/wechat-emoji/Smile.png +0 -0
  155. package/resources/wechat-emoji//344/272/262/344/272/262.png +0 -0
  156. package/resources/wechat-emoji//344/276/277/344/276/277.png +0 -0
  157. package/resources/wechat-emoji//345/201/267/347/254/221.png +0 -0
  158. package/resources/wechat-emoji//345/202/262/346/205/242.png +0 -0
  159. package/resources/wechat-emoji//345/206/215/350/247/201.png +0 -0
  160. package/resources/wechat-emoji//345/207/213/350/260/242.png +0 -0
  161. package/resources/wechat-emoji//345/212/240/346/262/271.png +0 -0
  162. package/resources/wechat-emoji//345/213/276/345/274/225.png +0 -0
  163. package/resources/wechat-emoji//345/217/221/345/221/206.png +0 -0
  164. package/resources/wechat-emoji//345/217/221/346/200/222.png +0 -0
  165. package/resources/wechat-emoji//345/217/221/346/212/226.png +0 -0
  166. package/resources/wechat-emoji//345/217/257/346/200/234.png +0 -0
  167. package/resources/wechat-emoji//345/217/263/345/223/274/345/223/274.png +0 -0
  168. package/resources/wechat-emoji//345/217/271/346/260/224.png +0 -0
  169. package/resources/wechat-emoji//345/220/203/347/223/234.png +0 -0
  170. package/resources/wechat-emoji//345/220/210/345/215/201.png +0 -0
  171. package/resources/wechat-emoji//345/220/220.png +0 -0
  172. package/resources/wechat-emoji//345/221/262/347/211/231.png +0 -0
  173. package/resources/wechat-emoji//345/222/222/351/252/202.png +0 -0
  174. package/resources/wechat-emoji//345/222/226/345/225/241.png +0 -0
  175. package/resources/wechat-emoji//345/223/207.png +0 -0
  176. package/resources/wechat-emoji//345/225/244/351/205/222.png +0 -0
  177. package/resources/wechat-emoji//345/230/230.png +0 -0
  178. package/resources/wechat-emoji//345/230/264/345/224/207.png +0 -0
  179. package/resources/wechat-emoji//345/230/277/345/223/210.png +0 -0
  180. package/resources/wechat-emoji//345/233/247.png +0 -0
  181. package/resources/wechat-emoji//345/233/260.png +0 -0
  182. package/resources/wechat-emoji//345/235/217/347/254/221.png +0 -0
  183. package/resources/wechat-emoji//345/244/247/345/223/255.png +0 -0
  184. package/resources/wechat-emoji//345/244/251/345/225/212.png +0 -0
  185. package/resources/wechat-emoji//345/244/252/351/230/263.png +0 -0
  186. package/resources/wechat-emoji//345/244/261/346/234/233.png +0 -0
  187. package/resources/wechat-emoji//345/245/270/347/254/221.png +0 -0
  188. package/resources/wechat-emoji//345/245/275/347/232/204.png +0 -0
  189. package/resources/wechat-emoji//345/247/224/345/261/210.png +0 -0
  190. package/resources/wechat-emoji//345/256/263/347/276/236.png +0 -0
  191. package/resources/wechat-emoji//345/260/264/345/260/254.png +0 -0
  192. package/resources/wechat-emoji//345/272/206/347/245/235.png +0 -0
  193. package/resources/wechat-emoji//345/274/261.png +0 -0
  194. package/resources/wechat-emoji//345/274/272.png +0 -0
  195. package/resources/wechat-emoji//345/276/227/346/204/217.png +0 -0
  196. package/resources/wechat-emoji//345/276/256/347/254/221.png +0 -0
  197. package/resources/wechat-emoji//345/277/203/347/242/216.png +0 -0
  198. package/resources/wechat-emoji//345/277/253/345/223/255/344/272/206.png +0 -0
  199. package/resources/wechat-emoji//346/201/220/346/203/247.png +0 -0
  200. package/resources/wechat-emoji//346/202/240/351/227/262.png +0 -0
  201. package/resources/wechat-emoji//346/203/212/346/201/220.png +0 -0
  202. package/resources/wechat-emoji//346/203/212/350/256/266.png +0 -0
  203. package/resources/wechat-emoji//346/204/211/345/277/253.png +0 -0
  204. package/resources/wechat-emoji//346/206/250/347/254/221.png +0 -0
  205. package/resources/wechat-emoji//346/211/223/350/204/270.png +0 -0
  206. package/resources/wechat-emoji//346/212/223/347/213/202.png +0 -0
  207. package/resources/wechat-emoji//346/212/240/351/274/273.png +0 -0
  208. package/resources/wechat-emoji//346/212/261/346/213/263.png +0 -0
  209. package/resources/wechat-emoji//346/213/245/346/212/261.png +0 -0
  210. package/resources/wechat-emoji//346/213/263/345/244/264.png +0 -0
  211. package/resources/wechat-emoji//346/215/202/350/204/270.png +0 -0
  212. package/resources/wechat-emoji//346/217/241/346/211/213.png +0 -0
  213. package/resources/wechat-emoji//346/222/207/345/230/264.png +0 -0
  214. package/resources/wechat-emoji//346/223/246/346/261/227.png +0 -0
  215. package/resources/wechat-emoji//346/225/262/346/211/223.png +0 -0
  216. package/resources/wechat-emoji//346/227/240/350/257/255.png +0 -0
  217. package/resources/wechat-emoji//346/227/272/346/237/264.png +0 -0
  218. package/resources/wechat-emoji//346/231/225.png +0 -0
  219. package/resources/wechat-emoji//346/234/210/344/272/256.png +0 -0
  220. package/resources/wechat-emoji//346/234/272/346/231/272.png +0 -0
  221. package/resources/wechat-emoji//346/261/227.png +0 -0
  222. package/resources/wechat-emoji//346/265/201/346/263/252.png +0 -0
  223. package/resources/wechat-emoji//347/202/270/345/274/271.png +0 -0
  224. package/resources/wechat-emoji//347/203/237/350/212/261.png +0 -0
  225. package/resources/wechat-emoji//347/210/206/347/253/271.png +0 -0
  226. package/resources/wechat-emoji//347/210/261/345/277/203.png +0 -0
  227. package/resources/wechat-emoji//347/214/252/345/244/264.png +0 -0
  228. package/resources/wechat-emoji//347/216/253/347/221/260.png +0 -0
  229. package/resources/wechat-emoji//347/224/237/347/227/205.png +0 -0
  230. package/resources/wechat-emoji//347/226/221/351/227/256.png +0 -0
  231. package/resources/wechat-emoji//347/231/274.png +0 -0
  232. package/resources/wechat-emoji//347/231/275/347/234/274.png +0 -0
  233. package/resources/wechat-emoji//347/232/261/347/234/211.png +0 -0
  234. package/resources/wechat-emoji//347/235/241.png +0 -0
  235. package/resources/wechat-emoji//347/240/264/346/266/225/344/270/272/347/254/221.png +0 -0
  236. package/resources/wechat-emoji//347/244/274/347/211/251.png +0 -0
  237. package/resources/wechat-emoji//347/244/276/344/274/232/347/244/276/344/274/232.png +0 -0
  238. package/resources/wechat-emoji//347/246/217.png +0 -0
  239. package/resources/wechat-emoji//347/254/221/350/204/270.png +0 -0
  240. package/resources/wechat-emoji//347/272/242/345/214/205.png +0 -0
  241. package/resources/wechat-emoji//347/277/273/347/231/275/347/234/274.png +0 -0
  242. package/resources/wechat-emoji//350/200/266.png +0 -0
  243. package/resources/wechat-emoji//350/203/234/345/210/251.png +0 -0
  244. package/resources/wechat-emoji//350/204/270/347/272/242.png +0 -0
  245. package/resources/wechat-emoji//350/211/262.png +0 -0
  246. package/resources/wechat-emoji//350/213/246/346/266/251.png +0 -0
  247. package/resources/wechat-emoji//350/217/234/345/210/200.png +0 -0
  248. package/resources/wechat-emoji//350/233/213/347/263/225.png +0 -0
  249. package/resources/wechat-emoji//350/241/260.png +0 -0
  250. package/resources/wechat-emoji//350/243/202/345/274/200.png +0 -0
  251. package/resources/wechat-emoji//350/256/251/346/210/221/347/234/213/347/234/213.png +0 -0
  252. package/resources/wechat-emoji//350/260/203/347/232/256.png +0 -0
  253. package/resources/wechat-emoji//350/267/263/350/267/263.png +0 -0
  254. package/resources/wechat-emoji//350/275/254/345/234/210.png +0 -0
  255. package/resources/wechat-emoji//351/204/231/350/247/206.png +0 -0
  256. package/resources/wechat-emoji//351/227/255/345/230/264.png +0 -0
  257. package/resources/wechat-emoji//351/230/264/351/231/251.png +0 -0
  258. package/resources/wechat-emoji//351/232/276/350/277/207.png +0 -0
  259. package/resources/wechat-emoji//351/252/267/351/253/205.png +0 -0
  260. package/resources/wechat-emoji//351/274/223/346/216/214.png +0 -0
  261. package/scripts/_batch_link_sources.py +73 -73
  262. package/scripts/_utils.py +29 -0
  263. package/scripts/annual_report.py +796 -796
  264. package/scripts/auto_tag.py +128 -128
  265. package/scripts/biz_daily.py +210 -53
  266. package/scripts/chat_report.py +10 -0
  267. package/scripts/chat_stats.py +702 -702
  268. package/scripts/classify_daily.py +17 -11
  269. package/scripts/create_reading_notes.py +370 -370
  270. package/scripts/daily_stats.py +132 -0
  271. package/scripts/enrich_backlinks.py +163 -163
  272. package/scripts/export_chat_html.py +1704 -107
  273. package/scripts/extract_todos.py +445 -404
  274. package/scripts/fav_server.py +119 -12
  275. package/scripts/fix_topics.py +111 -111
  276. package/scripts/generate_ai_report.py +1 -1
  277. package/scripts/generate_html.py +597 -277
  278. package/scripts/inspection_records.py +354 -0
  279. package/scripts/mcp_bridge.py +398 -398
  280. package/scripts/nt_decrypt.py +702 -48
  281. package/scripts/pipeline.py +27 -19
  282. package/scripts/promote_all.py +312 -310
  283. package/scripts/promote_ideas.py +299 -297
  284. package/scripts/rag_chat.py +194 -191
  285. package/scripts/semantic_search.py +435 -431
  286. package/scripts/sync_fav.py +201 -146
  287. package/scripts/sync_weread.py +192 -192
  288. package/scripts/vault_rag.py +140 -139
  289. package/scripts/vault_search.py +141 -141
  290. package/scripts/wechat_emoji.py +132 -0
  291. package/scripts/wechat_emoticon.py +433 -0
  292. package/scripts/wechat_image.py +258 -0
  293. package/scripts/wechat_voice.py +327 -0
  294. package/src/core/dbPathService.ts +163 -18
  295. package/src/core/keyService.ts +137 -25
  296. package/src/core/ntCore.ts +215 -62
  297. package/src/core/sqlcipherCore.ts +17 -1
  298. package/src/core/wcdbCore.ts +3 -7
  299. package/src/services/assistantDaemon.ts +111 -0
  300. package/src/services/assistantMemory.ts +193 -0
  301. package/src/services/assistantPrivacy.ts +87 -0
  302. package/src/services/assistantRouting.ts +92 -0
  303. package/src/services/assistantService.ts +295 -0
  304. package/src/services/assistantTools.ts +549 -0
  305. package/src/services/chatService.ts +133 -4
  306. package/src/services/configService.ts +194 -6
  307. package/src/services/evidenceService.ts +129 -0
  308. package/src/services/exportService.ts +113 -48
  309. package/src/services/initKeyService.ts +83 -0
  310. package/src/services/messageContract.ts +77 -0
  311. package/src/services/messageQuery.ts +38 -0
  312. package/src/services/wechat-formatter.ts +348 -348
  313. package/src/services/wechatMessageService.ts +25 -3
  314. package/src/services/wereadService.ts +308 -308
  315. package/src/services/whitelistService.ts +209 -22
  316. package/src/types.ts +20 -0
  317. package/src/utils/dateRange.ts +58 -0
  318. package/src/utils/mcpSecurity.ts +39 -0
  319. package/src/utils/packageRoot.ts +14 -0
  320. package/src/utils/python.ts +73 -0
  321. package/src/utils/pythonProcessEnv.ts +45 -0
  322. package/src/utils/talkerUtils.ts +14 -2
  323. package/dist/src/utils/errors.d.ts +0 -25
  324. package/dist/src/utils/errors.d.ts.map +0 -1
  325. package/dist/src/utils/errors.js +0 -43
  326. package/dist/src/utils/errors.js.map +0 -1
  327. package/dist/src/utils/pythonRunner.d.ts +0 -27
  328. package/dist/src/utils/pythonRunner.d.ts.map +0 -1
  329. package/dist/src/utils/pythonRunner.js +0 -62
  330. package/dist/src/utils/pythonRunner.js.map +0 -1
  331. package/src/utils/errors.ts +0 -42
  332. package/src/utils/pythonRunner.ts +0 -81
@@ -0,0 +1,189 @@
1
+ # AI 接口
2
+
3
+ WeFlow CLI 的 AI 接入分为三层:
4
+
5
+ 1. **能力探测**:先运行 `weflow-cli capabilities --json`,确认当前版本支持的读取、导出和分析入口。
6
+ 2. **结构化 CLI**:读取型命令优先使用 `--json`,避免解析表格、颜色和自然语言日志。
7
+ 3. **MCP**:本地 Agent 可使用 stdio MCP;消息数据优先使用 `wechat.export_messages`,返回 `weflow-message/v1`。
8
+
9
+ 默认 MCP 仅提供有界读取和本地转换能力,不提供消息发送、公众号发布、长期记忆写入、待办修改、配置变更或删除。需要副作用的自动化必须改用具备项目自身预览和确认协议的显式 CLI 工作流。
10
+ Agent 可先调用 `capabilities --json`,并检查 `safety.mcpDefaultReadOnly`,再决定是否使用 MCP。
11
+
12
+ ## 推荐调用顺序
13
+
14
+ ```powershell
15
+ weflow-cli capabilities --json
16
+ weflow-cli config show --json
17
+ weflow-cli whitelist list --json
18
+ weflow-cli blacklist list --json
19
+ weflow-cli sessions --json --limit 30
20
+ weflow-cli messages "<session-id>" --json --limit 100
21
+ weflow-cli check --json
22
+ weflow-cli daily-stats --json
23
+ weflow-cli daily --no-ai --dry-run --json
24
+ weflow-cli daily --no-ai --yes --json
25
+ weflow-cli sns timeline --json --limit 20
26
+ weflow-cli sns users --json
27
+ weflow-cli sns stats --json
28
+ weflow-cli daily-server --status --json
29
+ weflow-cli evidence "<session-id>" --json --non-interactive --limit 100
30
+ weflow-cli evidence-review "<session-id>" --dry-run --json --limit 100
31
+ weflow-cli export "<session-id>" json --contract weflow-v1 --output "<local-output>"
32
+ ```
33
+
34
+ Add `--json` to an export command when the caller needs a machine-readable operation result. This changes only stdout status reporting, not the selected export file format. The result contains `success`, `format`, `contract`, `path`, and `count`. The `weflow-v1` file additionally includes conservative `coverage` metadata (`requestedFrom`, `requestedTo`, `requestedLimit`, `returned`, `mayHaveMore`, and returned time bounds); it does not expose a stable incremental cursor yet. `--date` applies to every export format using the machine's local calendar day; `--date` cannot be combined with `--from` or `--to`.
35
+
36
+ Favorite exports use `--json-result` because `json` is already a positional file format: `fav export json --json-result --output <local-file>`. The result reports only status, path, format, and count; exported favorite content remains in the local file.
37
+
38
+ ## Two-phase todo mutations
39
+
40
+ Agents must preview a todo mutation before asking the user to approve it. The preview is read-only. Execution requires the explicit `--yes` flag; JSON mode without it returns `CONFIRMATION_REQUIRED` and leaves the todo file unchanged.
41
+
42
+ ```powershell
43
+ weflow-cli todos done <id> --dry-run --json
44
+ weflow-cli todos done <id> --yes --json
45
+ weflow-cli todos undone <id> --dry-run --json
46
+ weflow-cli todos rm <id> --dry-run --json
47
+ ```
48
+
49
+ These todo commands authorize only the previewed todo mutation. Messaging, access control, configuration, assistant lifecycle, publishing, and other side effects require their own explicit protocol.
50
+
51
+ Access-control changes use the same preview/confirm pattern and return local sensitive identifiers:
52
+
53
+ ```powershell
54
+ weflow-cli whitelist add <target> --dry-run --json
55
+ weflow-cli whitelist add <target> --yes --json
56
+ weflow-cli whitelist rm <session-id> --dry-run --json
57
+ weflow-cli blacklist add <target> --dry-run --json
58
+ weflow-cli blacklist rm <session-id> --yes --json
59
+ ```
60
+
61
+ Message sending is available only through the existing official Bot channel and also requires two phases:
62
+
63
+ ```powershell
64
+ weflow-cli send <session-id> <message> --dry-run --json
65
+ weflow-cli send <session-id> <message> --yes --json
66
+ ```
67
+
68
+ The preview contains message content and local identifiers, so it must remain local. This command cannot initiate a personal-account message or send into an ordinary personal WeChat group.
69
+ Image and file previews contain only the base file name and byte size, not the full local path. The selected media must be a readable, non-empty regular file, and `--image` cannot be combined with `--file`.
70
+
71
+ Starting the assistant may create a background process, handle incoming Bot-channel messages, and consume AI quota. Agents must use `assistant start --dry-run --json` before a user-approved `assistant start --yes --json`. Stopping follows the same protocol. Status remains read-only through `assistant status --json`.
72
+
73
+ The local daily reader follows the same lifecycle pattern. `daily-server --status --json` only checks loopback status. Starting it requires `daily-server --dry-run --json` followed by user-approved `daily-server --yes --json`; the confirmed JSON startup waits for the loopback service to report the requested date and returns a failure code if the date output is missing or the process does not become ready. Add `--open` only when the user also wants a browser window opened. Human-oriented non-JSON startup remains compatible. The older `fav-server` command is a compatibility entry and applies the same machine-mode confirmation rule.
74
+
75
+ Message-channel authentication is human-gated. Agents may inspect `login-wechat --dry-run --json`, but actual login uses `login-wechat --yes` in an interactive terminal because the user must scan a QR code. `login-wechat --yes --json` returns `INTERACTIVE_REQUIRED` without starting login. Logout uses `logout-wechat --dry-run --json` followed by user-approved `logout-wechat --yes --json`.
76
+
77
+ Initialization is also human-gated because it may verify private databases, search local disks, capture keys, and update encrypted configuration. Agents may call `init --dry-run --json`; `init --json` returns `INTERACTIVE_REQUIRED` without scanning or writing. Actual initialization remains the interactive `init` command.
78
+
79
+ 朋友圈密钥捕获同样需要用户在微信客户端中触发。Agent 只能调用 `sns capture-key --dry-run --json` 查看要求;实际捕获使用交互终端中的 `sns capture-key --yes`,JSON 执行会返回 `INTERACTIVE_REQUIRED`,不会扫描进程。
80
+
81
+ `listen` 和 `assistant run` 会在当前终端持续运行并处理消息内容,因此也属于人工前台流程。Agent 可调用对应的 `--dry-run --json` 预览,但实际启动必须使用非 JSON 的 `--yes`,常驻自动化应优先使用已确认的 `assistant start --yes --json`。
82
+
83
+ Vault Git synchronization also uses two phases because it commits local files and pushes them to a remote repository:
84
+
85
+ ```powershell
86
+ weflow-cli vault sync --dry-run --json
87
+ weflow-cli vault sync --yes --json
88
+ ```
89
+
90
+ The preview reports only the number of changed file states and whether the Vault is already a Git repository. It does not return file names or the remote URL.
91
+
92
+ Vault initialization can create directories and overwrite its four managed template files. Agents must inspect the overwrite count before execution:
93
+
94
+ ```powershell
95
+ weflow-cli vault init --path <local-directory> --dry-run --json
96
+ weflow-cli vault init --path <local-directory> --yes --json
97
+ ```
98
+
99
+ Knowledge indexing, pipelines, and generated reports also use two phases. Their previews do not read chat data, call AI services, or write files:
100
+
101
+ ```powershell
102
+ weflow-cli search-index --dry-run --json
103
+ weflow-cli search-index --yes --json
104
+ weflow-cli pipeline run --no-ai --source <source-name> --dry-run --json
105
+ weflow-cli pipeline run --no-ai --source <source-name> --yes --json
106
+ weflow-cli report --no-ai --dry-run --json
107
+ weflow-cli annual-report YYYY --skip-ai --dry-run --json
108
+ weflow-cli review --dry-run --json
109
+ weflow-cli evidence-review "<session-id>" --dry-run --json
110
+ ```
111
+
112
+ Remove `--no-ai` or `--skip-ai` only after the user approves sending the described content to the configured provider. `search-index` always sends collected text to the configured embedding provider. After approval, `evidence-review` uses `--yes --json`; cloud processing additionally requires `--allow-cloud`. JSON results omit selected conversation names, report content, and local output paths.
113
+
114
+ Vault enrichment, reading-note creation, AI tagging, WeRead synchronization, promotion workflows, consumption statistics, and daily-favorite changes follow the same rule:
115
+
116
+ ```powershell
117
+ weflow-cli vault enrich --date YYYY-MM-DD --dry-run --json
118
+ weflow-cli vault notes --date YYYY-MM-DD --dry-run --json
119
+ weflow-cli vault tag --date YYYY-MM-DD --dry-run --json
120
+ weflow-cli vault sync-weread --dry-run --json
121
+ weflow-cli vault promote ideas --dry-run --json
122
+ weflow-cli wiki compile --dry-run --json
123
+ weflow-cli chat-stats --dry-run --json
124
+ weflow-cli todos extract --days 7 --dry-run --json
125
+ weflow-cli daily favorites add <article> --dry-run --json
126
+ ```
127
+
128
+ After approval, replace `--dry-run` with `--yes`. Multiple daily-favorite articles use repeated `--article <path>`. Preview and result JSON report counts and behavior only, not article names, book names, report data, or paths.
129
+
130
+ Writing an MCP client configuration follows the same protocol. Reading the generated configuration needs no confirmation; writing a file does:
131
+
132
+ ```powershell
133
+ weflow-cli mcp-config
134
+ weflow-cli mcp-config --output .mcp.json --dry-run --json-result
135
+ weflow-cli mcp-config --output .mcp.json --yes --json-result
136
+ ```
137
+
138
+ Secrets should be persisted from an existing environment variable so their values do not appear in command arguments:
139
+
140
+ ```powershell
141
+ weflow-cli config set-env deepseekApiKey DEEPSEEK_API_KEY --dry-run --json
142
+ weflow-cli config set-env deepseekApiKey DEEPSEEK_API_KEY --yes --json
143
+ weflow-cli fav set-key --from-env WEFLOW_FAV_KEY --dry-run --json
144
+ weflow-cli fav set-key --from-env WEFLOW_FAV_KEY --yes --json
145
+ ```
146
+
147
+ Human-oriented configuration commands keep their direct behavior. JSON configuration writes require explicit `--yes`; their preview and result contain the key and environment-variable name but never the value.
148
+
149
+ Bulk deletion is destructive and follows the same two-phase protocol: preview `config clear`, `whitelist clear`, `blacklist clear`, or `audit clear` with `--dry-run --json`, then execute the approved command with `--yes --json`. Previews return only counts or impact flags, never entries or log content. A JSON-mode call without confirmation returns `CONFIRMATION_REQUIRED`. Individual whitelist and blacklist additions or removals also require `--yes` in JSON mode.
150
+
151
+ Database-key reset follows the same rule: preview with `config forget-keys --dry-run --json`; `config forget-keys --json` returns `CONFIRMATION_REQUIRED`; only a user-approved `config forget-keys --yes --json` clears saved database access keys. `config show --json` is intentionally redacted and reports status flags and counts rather than paths, account identifiers, or secret values. Access-list JSON contains local identifiers and must remain local.
152
+
153
+ Process-memory key capture is human-gated. An Agent may inspect `dbkey --force --dry-run --json`, but JSON execution returns `INTERACTIVE_REQUIRED`; actual capture requires `dbkey --force --yes` in an interactive terminal. `scan --json` reports only whether candidates exist and their count. `assistant log --json` reports log availability and line counts without returning log text.
154
+
155
+ Vault RAG can send selected local knowledge to the configured AI provider, so it also uses two phases:
156
+
157
+ ```powershell
158
+ weflow-cli vault rag "<question>" --dry-run --json
159
+ weflow-cli vault rag "<question>" --yes --json
160
+ ```
161
+
162
+ The preview does not read the Vault or call AI and does not echo the question. Execution passes the question to the bundled worker without placing it in child-process arguments. `todos remind --json` is the structured read form of local todo reminders.
163
+
164
+ Semantic search and chat-backed RAG also require explicit approval because they may send a query or selected local context to cloud services:
165
+
166
+ ```powershell
167
+ weflow-cli search "<query>" --dry-run --json
168
+ weflow-cli search "<query>" --yes --json
169
+ weflow-cli chat "<question>" --talker "<session-id>" --dry-run --json
170
+ weflow-cli chat "<question>" --talker "<session-id>" --yes --json
171
+ ```
172
+
173
+ Previews omit the query, question, and conversation restriction. These values are inherited by the Python worker rather than placed in process arguments. `chat --yes --json` without a question returns `INTERACTIVE_REQUIRED`; interactive chat must be started by a person in a terminal.
174
+
175
+ AI 应优先使用会话 ID,不应依赖昵称猜测。`messages --json` 默认采用非交互解析;`messages`、`export` 和 `evidence` 也支持显式 `--non-interactive`,名称匹配不唯一时会返回错误而不是等待人工选择。
176
+ `messages --start` and `--end` accept Unix timestamps in seconds and are applied before offset and limit. Core read pagination rejects negative, fractional, nonnumeric, or excessive values with `INVALID_ARGUMENT`.
177
+
178
+ ## 数据与权限
179
+
180
+ - 读取和导出默认在本地完成,不自动调用 AI。
181
+ - `daily --no-ai` 可生成不含 AI 处理的日报。
182
+ - `daily --json` 需要用户批准后的 `--yes`,将流水线日志写到 stderr,只在 stdout 输出最终状态,并逐项报告日报、文章索引和 HTML 阅读器产物是否完整。
183
+ - `evidence-review`、`report`、`review`、`annual-report`、`search-index`、`pipeline`、`chat` 和其他分析任务需要显式选择 AI,并遵守隐私设置。报告、索引和流水线的 JSON 写操作还需要 `--yes`;预览不会读取本地内容或调用 AI。
184
+ - `send`、配置修改、密钥捕获、发布和删除属于副作用操作,AI 不应在没有用户确认时执行。
185
+ - 任何下游项目都不得接收数据库路径、解密密钥、完整配置或无限制文件系统权限。
186
+
187
+ ## 当前边界
188
+
189
+ 并非所有命令都已经提供 JSON 输出。目前已结构化的基础入口包括能力探测、脱敏配置状态、访问控制列表、环境检查、会话、消息、联系人、朋友圈时间线与统计、阅读器状态、证据包、收藏、待办、日报频率、Vault 初始化和同步、语义索引、知识流水线及报告生成。尚未结构化的命令应通过 MCP 或现有文本接口临时调用,并将其列为兼容性限制,而不是猜测文本格式。未知消息类型必须保留原始类型码并安全降级为 `other`。
@@ -0,0 +1,87 @@
1
+ # 分支与合并记录
2
+
3
+ 本文件记录分支的用途、合并时间与合并内容,以及并行开发时的对齐约定。
4
+ 每次把工作分支并入 `master` 后,请在「合并记录」中追加一行。
5
+
6
+ ## 分支一览
7
+
8
+ | 分支 | 用途 | 状态 |
9
+ | --- | --- | --- |
10
+ | `master` | 主线,随时可发布 | 受保护 |
11
+ | `trae/*` | 早期 AI 协作产生的分支 | 部分已合并,部分搁置 |
12
+ | `draft/*` | 探索性草稿,允许与主线脱节 | 按需清理 |
13
+ | `feat/*`、`fix/*` | 从**当前** `master` 切出的工作分支 | 合并后删除 |
14
+
15
+ > **约定**:`feat/*` 与 `fix/*` 必须从最新的 `master` 切出。`draft/*` 无此要求,
16
+ > 但**合并前必须先把 `master` 合进来**(见下方「并行开发」)。
17
+
18
+ ## 合并记录
19
+
20
+ | 日期 | 来源分支 | 目标 | 方式 | 说明 |
21
+ | --- | --- | --- | --- | --- |
22
+ | 2026-06-30 | `trae/solo-agent-Xl3Lhb` | `master` | 合并提交 `bc44e93` | 优化消息与朋友圈功能 |
23
+ | 2026-09-01 | `Mandark6/master` | `master` | PR #6,合并提交 `2d3005c` | 外部贡献 |
24
+ | 2026-09-10 | `feat/export-enhancements` | `master` | 快进至 `64dcf2f` | 表情原版图、`--per-page` 分页、表情包本地解密、图片缩放;并修复跨分片未生效 |
25
+ | 2026-09-10 | `draft/weflow-cli-improvements` | — | **未合并,已作废** | 基于过期 master;独有功能已移植,见下方「2026-09-10」条目 |
26
+
27
+ ### 2026-09-10 · `draft/weflow-cli-improvements`
28
+
29
+ 该分支产出了导出链路的若干增强,但**基于过期的 `master`**(共同祖先 `cbec736`),
30
+ 当时 `master` 已领先 78 个提交。因此**没有直接合并**,改为把其中的独有功能移植到
31
+ 从最新 `master` 切出的 `feat/export-enhancements`。
32
+
33
+ 分支仍保留在本地与远端,标签 `backup/my-export-work` 指向其顶端 `c181afb`。
34
+
35
+ 移植与放弃的清单:
36
+
37
+ | 项 | 处理 | 原因 |
38
+ | --- | --- | --- |
39
+ | 跨分片读取 | **改修为接线修复** | `master` 有 `fetch_messages_from_shards`,但见下方「附带修复」 |
40
+ | 主密钥派生 | **放弃** | `master` 已有 `derive_database_key`,算法与草稿一致 |
41
+ | 图片按 `(local_id, create_time)` 配对 | **放弃** | `master` 已有 |
42
+ | `.dat` 图片解密与资源映射 | **放弃** | `master` 已有 `decode_wechat_v2`、`load_resource_media_map` |
43
+ | zstd 解压、CDATA 解析、名片渲染 | **放弃** | `master` 已有 |
44
+ | 会话列表改读 `session.db` | 待定 | 需与 `master` 现有实现比对 |
45
+ | **微信原版表情图(109 张)** | **移植** | `master` 仅 9 张 |
46
+ | **表情按 CSS 类去重** | **移植** | `master` 每个出现都重复内嵌 base64 |
47
+ | **`--per-page` 按条数分页** | **移植** | `master` 只有 `--parts`(按份数) |
48
+ | **表情包本地解密** | **移植** | `master` 走 CDN,需联网 |
49
+ | **图片缩放管线** | **移植** | `master` 按原始尺寸内嵌 |
50
+
51
+ ### 附带修复:跨分片合并默认未生效
52
+
53
+ 移植过程中发现 `master` 的跨分片能力实际处于休眠状态:`derive_database_key()` 需要
54
+ `passphrase` 才会派生分片密钥,而 `exportService.ts` 只从配置的 `favPassphrase` 读取,
55
+ `init` 写入的却是 `decryptKey`。两者本是同一个值,但字段名不同,于是口令为空、派生
56
+ 退回单库密钥,导出静默地停在第一个分片的最后一条消息。
57
+
58
+ 实测:某会话只导出 10 条(止于 2026-04-23),而该会话实际有 20 条(到 2026-09-10)。
59
+ 已在 `exportService.ts` 增加 `favPassphrase || decryptKey` 回退。
60
+
61
+ ## 并行开发
62
+
63
+ 本次出现的问题:本地克隆停在 `cbec736`,之后主线积累了 78 个提交,导致在旧基线上
64
+ 从零实现了主线已有的功能,白做一遍。
65
+
66
+ **动手前先对齐:**
67
+
68
+ ```bash
69
+ git fetch origin
70
+ git status -sb # 看 ahead / behind
71
+ git log --oneline HEAD..origin/master | wc -l # 主线领先多少
72
+ ```
73
+
74
+ 若 `behind` 不为 0,先 `git checkout master && git pull --ff-only`,再切工作分支。
75
+
76
+ **合并前自检:**
77
+
78
+ ```bash
79
+ git fetch origin
80
+ git log --oneline HEAD..origin/master # 应尽量为空
81
+ git merge-tree --write-tree origin/master HEAD # 预看冲突
82
+ ```
83
+
84
+ ## 强推与清理
85
+
86
+ - **禁止对 `master` 强推。** 若推送被拒,一律先 `git fetch` 查明主线新增内容。
87
+ - 工作分支合并后应删除本地与远端副本;`draft/*` 保留至内容确认无用为止。
@@ -0,0 +1,74 @@
1
+ # Data Contract
2
+
3
+ This document defines the stable, local export boundary for downstream tools such as `she-love-me`.
4
+
5
+ ## First Integration
6
+
7
+ The first downstream consumer is `she-love-me`. It should continue to invoke the existing command:
8
+
9
+ ```powershell
10
+ weflow-cli export "<contact>" json --output "<local-output>"
11
+ ```
12
+
13
+ The command remains a local, user-authorized export. It does not upload messages or grant another application direct access to the WeChat database.
14
+
15
+ ## JSON Contract
16
+
17
+ The JSON output is a message array. A downstream consumer must tolerate both a top-level array and an object containing a `messages` array.
18
+
19
+ For new integrations, request the versioned envelope:
20
+
21
+ ```powershell
22
+ weflow-cli export "<contact>" json --contract weflow-v1 --output "<local-output>"
23
+ ```
24
+
25
+ The envelope contains `schema: "weflow-message/v1"`, `source`, `generatedAt`, and `messages`. Versioned exports also include optional `coverage` metadata: `requestedFrom`, `requestedTo`, `requestedLimit`, `returned`, `mayHaveMore`, and the oldest/newest returned `createTime`. `mayHaveMore` is deliberately conservative: it is true when the result reaches the requested positive limit, and false only when it does not. The default `raw` contract remains unchanged for existing consumers.
26
+
27
+ The currently supported message fields are:
28
+
29
+ | Field | Meaning | Consumer guidance |
30
+ | --- | --- | --- |
31
+ | `localId` | Local database message identifier | Display or trace only; it is not globally unique. |
32
+ | `isSend` | Whether the message was sent by the local account | Prefer this field for `me`/`them` mapping when present. |
33
+ | `createTime` | Unix timestamp in seconds | Normalize and validate before analysis. |
34
+ | `localType` | WeChat message type code | Map unknown values to `other`; do not discard the message. |
35
+ | `messageType` | Stable type name in `weflow-v1` | One of `text`, `image`, `voice`, `card`, `video`, `emoji`, `location`, `link`, `call`, `system`, `quote`, or `other`. |
36
+ | `senderUsername` | Sender identifier when available | Treat as sensitive and do not expose in public reports. |
37
+ | `parsedContent` | Parsed, human-readable content | Prefer over `rawContent` for analysis. |
38
+ | `rawContent` | Original or fallback content | Preserve locally for traceability; do not assume it is display-safe. |
39
+ | `transcript` / `voiceTranscript` | Optional voice transcription | Treat as user content and keep local. |
40
+
41
+ Downstream tools must not assume that local IDs are unique across conversations or database shards. Ordering should use `createTime` and a stable local tie-breaker.
42
+
43
+ ## Incremental Reads Before A Cursor Exists
44
+
45
+ Until a stable cursor is available, a downstream reader can use an overlapping time window:
46
+
47
+ 1. Export with `--contract weflow-v1` and record `coverage.newestCreateTime` locally.
48
+ 2. On the next run, use `--from` at or slightly before that timestamp so messages sharing a second are not missed.
49
+ 3. Deduplicate within the downstream store using the conversation identifier plus `localId` and `serverId` when present.
50
+
51
+ This is a best-effort synchronization recipe. It must not treat a timestamp as a globally unique message identifier, and it must retain the previous checkpoint if the export fails.
52
+
53
+ ## Compatibility Rules
54
+
55
+ - Keep the existing `export <contact> json` command working.
56
+ - Use `--from` and `--to` for bounded exports when available; dates are interpreted in local time for date-only values.
57
+ - `--date YYYY-MM-DD` applies the same local calendar-day bound to JSON, TXT, HTML, and Excel exports. It cannot be combined with `--from` or `--to`.
58
+ - Add `--json` for a machine-readable operation result containing the output path and exported message count; this flag does not change the file format selected by the positional `format` argument.
59
+ - Use `--limit 0` for a complete export. With date filters, a positive limit applies to matching messages after the time range is evaluated.
60
+ - Preserve unknown fields so new media and message metadata can be adopted without breaking consumers.
61
+ - Treat `coverage` as query metadata, not proof that the underlying database is complete; database shards and concurrent writes can affect observed bounds.
62
+ - Treat missing sender identity as `unknown`; never infer identity from a display name alone.
63
+ - Keep conversion to a downstream application's internal schema in that application. `weflow-cli` remains a general data foundation.
64
+
65
+ ## Privacy Boundary
66
+
67
+ - Data is read only from a user's own device or data they are authorized to access.
68
+ - Export files, database paths, account identifiers, keys, logs, and raw message content stay local by default.
69
+ - `she-love-me` should write its normalized bundle under its own local data directory and should not send raw exports to a model without explicit user consent and privacy filtering.
70
+ - AI analysis is not part of the export contract. An export must work without an API key or model call.
71
+
72
+ ## Future Direction
73
+
74
+ The existing CLI export is the compatibility layer for the first integration. The same contract is available through the versioned, read-only MCP tool `wechat.export_messages`. It accepts `contact` and optional `limit`, `from`, and `to` values, returns JSON directly, and never returns database paths or keys. It preserves the same authorization, local-only default, field semantics, and privacy rules rather than bypassing the CLI boundary.
@@ -0,0 +1,270 @@
1
+ # Technical Decisions
2
+
3
+ > Record decisions that affect long-term maintenance. Each entry explains the chosen direction and the reason, not every implementation detail.
4
+
5
+ ## D-001: Local-first data handling
6
+
7
+ **Status:** Active
8
+
9
+ Local WeChat data, configuration, exports, and knowledge outputs remain on the user's machine by default. Network access occurs only in explicitly selected workflows such as article retrieval, configured cloud AI, or WeRead integration.
10
+
11
+ **Reason:** The project handles highly sensitive personal communications. A local default reduces unnecessary data exposure without claiming legal or platform safety.
12
+
13
+ ## D-002: Separate data access from higher-level agents
14
+
15
+ **Status:** Active
16
+
17
+ Database access, MCP integration, local assistant behavior, and external products are separate trust boundaries. External projects may use constrained, read-only interfaces; they must not receive direct database paths, keys, credentials, or unrestricted filesystem access.
18
+
19
+ **Reason:** This keeps `weflow-cli` independently maintainable and limits the blast radius of an MCP client, agent, or collaboration.
20
+
21
+ ## D-003: Default-deny assistant access
22
+
23
+ **Status:** Active
24
+
25
+ The optional WeChat assistant denies incoming users unless `assistantWhitelist` is explicitly configured. A new or incomplete configuration defaults to strict cloud-inference privacy behavior.
26
+
27
+ **Reason:** An empty allowlist must not accidentally expose local chats, favorites, or memories to an unexpected sender.
28
+
29
+ ## D-004: Reader stays loopback-only
30
+
31
+ **Status:** Active
32
+
33
+ The daily reader binds to `127.0.0.1`; mutation endpoints enforce local-origin checks. Reader path handling and image proxying are restricted to reduce path traversal, cross-origin access, and SSRF exposure.
34
+
35
+ **Reason:** The reader serves personal reading history, notes, favorites, and locally generated article data. It is not a LAN service.
36
+
37
+ ## D-005: Configured sources take precedence over article classification
38
+
39
+ **Status:** Active
40
+
41
+ When an official-account source has a configured category, the daily workflow keeps that source category and only produces the required summary. Automatic article-topic classification remains a fallback for uncategorized sources.
42
+
43
+ **Reason:** Source-level categories are more stable and prevent unnecessary model calls or conflicting article labels.
44
+
45
+ ## D-006: Documentation has separate roles
46
+
47
+ **Status:** Active
48
+
49
+ `README.md` and `CHANGELOG.md` describe the product and release-visible changes. `docs/PROJECT_STATE.md` records the current engineering baseline. This file records durable rationale. `AGENTS.md` is the entry point for automated contributors.
50
+
51
+ **Reason:** Release notes, architecture descriptions, and current maintenance context change at different rates. Combining them caused stale plans to look current.
52
+
53
+ ## D-007: Group routing stays upstream-gated and default-deny
54
+
55
+ **Status:** Active
56
+
57
+ The assistant only recognizes a group when the upstream Bot payload explicitly identifies one. A recognized group requires an explicit group allowlist entry, an existing sender allowlist entry, and an @ mention by default. The project does not use client automation, injected code, or undocumented protocol bypasses to join groups.
58
+
59
+ **Reason:** The current official OC/iLink integration is verified for direct sessions, not group invitations or group-message metadata. Treating ambiguous payloads as groups or adding non-official automation would broaden privacy and account risk without a reliable permission model.
60
+
61
+ ## D-008: Bot-channel send is not personal-account messaging
62
+
63
+ **Status:** Active
64
+
65
+ The current `send` implementation uses the official OC/iLink Bot channel. It may only send into a previously established Bot conversation with a valid context token. It is not a facility for operating the user's personal WeChat account, initiating a message to a personal contact, or posting into an ordinary personal WeChat group.
66
+
67
+ **Reason:** Local contact lookup and the Bot transport are separate systems. Resolving a local contact ID does not grant the Bot channel permission or protocol context to message that contact. Presenting the command as generic personal-WeChat sending would be misleading and could lead users to assume unsupported access exists.
68
+
69
+ **Consequences:** Future messaging work must retain this boundary in command names, help text, and diagnostics. Any personal-account automation or undocumented protocol route requires a separate security and platform review; it is not an implicit extension of `send`.
70
+
71
+ ## D-010: Reuse verified local access before initialization
72
+
73
+ **Status:** Active
74
+
75
+ `init` first verifies an existing local database configuration and exits without a new key-capture attempt when access works. A user must explicitly pass `--refresh` to reinitialize. `dbkey` similarly avoids duplicate capture unless `--force` is supplied. `init --test-missing-keys` provides a non-persistent missing-key test; `config forget-keys` is reserved for an actual, confirmed reset without clearing unrelated settings.
76
+
77
+ **Reason:** Repeated capture depends on client lifecycle timing and is unnecessary when a valid local configuration already exists. A verification-first workflow reduces account disruption and makes recovery steps deliberate.
78
+
79
+ ## D-011: Backfill incomplete yesterday before today
80
+
81
+ **Status:** Active
82
+
83
+ An unqualified `daily` run checks yesterday's required local artifacts and completes yesterday first when `README.md`, `.articles.json`, or `index.html` is missing or empty. Explicit-date and dry-run invocations remain single-date operations.
84
+
85
+ **Reason:** A daily reader should not silently leave a gap when a previous scheduled run was interrupted. The required-artifact check is local, deterministic, and does not treat a directory alone as proof of a complete report.
86
+
87
+ ## D-012: Staged data-directory discovery
88
+
89
+ **Status:** Active
90
+
91
+ Initialization checks common user locations by default. Cross-drive searches for standard directory names require `init --search-drives`; deep structural searches require `init --full-scan`.
92
+
93
+ **Reason:** Broad recursive scans can block the CLI for a long time and unnecessarily enumerate metadata from unrelated volumes. The staged commands retain recovery options for custom locations while making the cost and privacy scope explicit.
94
+
95
+ **Consequences:** Support guidance should first request an explicit `--path`, then `--search-drives`, and only finally `--full-scan`. Diagnostic output must not include account identifiers, salts, keys, or full local paths unless a user intentionally inspects them locally.
96
+
97
+ ## D-013: Explicit AI for Vault promotion
98
+
99
+ **Status:** Active
100
+
101
+ `vault promote ideas` and `vault promote all` generate deterministic local indexes by default. AI generation is available only through explicit `--with-ai` plus a supplied API key or environment variable.
102
+
103
+ **Reason:** Knowledge-promotion outputs can be created locally, while AI promotion has monetary and privacy implications. An opt-in avoids an unexpected network request when a user is organizing notes.
104
+
105
+ **Consequences:** `vault init` must include the structured reading-note directories used by promotion. The promotion scripts must safely handle an empty or newly initialized Vault.
106
+
107
+ ## D-014: Match exported media using reliable message identity
108
+
109
+ **Status:** Active
110
+
111
+ HTML export selects message-resource records by nonzero server message ID. It does not use unscoped local message IDs or server ID zero to associate media. Content MD5 and source URL lookup remain available when a server mapping is absent.
112
+
113
+ **Reason:** Local IDs can repeat across conversations and database shards. An ambiguous fallback can attach unrelated media to a chat message.
114
+
115
+ **Consequences:** WeChat 4.x V2 media keys are derived from local `kvcomm` data, verified against a real cached V2 header, and used only in memory during export. Remote emoticons are decrypted with message-provided keys; entity-escaped XML is normalized; and URL fallbacks cover encrypted, thumbnail, CDN, and external fields. Structured app cards keep their links and use cached or resolved covers when available. Some messages remain placeholders when reliable identity or source media is unavailable. Synthetic tests cover these paths; reporter verification is still needed for issue #7.
116
+
117
+ ## D-016: Establish a stable downstream data boundary
118
+
119
+ **Status:** Active
120
+
121
+ The first integration with `she-love-me` uses the existing local `export <contact> json` interface. Its field meanings and privacy requirements are documented in `docs/DATA_CONTRACT.md`. A future MCP interface may expose the same read-only contract, but must not bypass the local authorization and privacy boundary.
122
+
123
+ **Reason:** Reusing the existing interface gives the first downstream consumer immediate compatibility while keeping `weflow-cli` general-purpose. A documented contract lets future tools build on the data layer without coupling their internal analysis schema to database implementation details.
124
+
125
+ **Consequences:** Changes to exported field semantics require a compatibility review. Downstream consumers must preserve unknown fields, handle missing identities, and keep raw exports local unless the user explicitly authorizes a privacy-filtered cloud workflow.
126
+
127
+ ## D-017: Expose the data contract through read-only MCP
128
+
129
+ **Status:** Active
130
+
131
+ The MCP server exposes `wechat.export_messages` as a bounded, read-only transport for the same `weflow-message/v1` envelope used by CLI exports. It accepts a session ID or an unambiguous display name, validates inclusive date filters, and caps the result size.
132
+
133
+ **Reason:** External projects need a stable integration boundary without receiving database paths, keys, configuration, or direct database access. Keeping MCP and CLI on the same contract avoids divergent message semantics.
134
+
135
+ **Consequences:** MCP clients must handle unknown message types and missing identities. The tool does not invoke AI or provide write/messaging operations. Any future broader access requires a separate security review.
136
+
137
+ ## D-018: Add machine-readable capability discovery
138
+
139
+ **Status:** Active
140
+
141
+ The CLI exposes `capabilities --json` as the first call for automation. Read-oriented commands progressively provide `--json` output, while interactive initialization and side-effect operations remain explicitly marked as requiring user participation or confirmation.
142
+
143
+ **Reason:** An AI client needs to discover the current implementation and safety limits before choosing a command. A capability document is more reliable than inferring support from human-oriented help text.
144
+
145
+ **Consequences:** New user-facing commands should be added to the capability response and should declare whether they read local data, invoke AI, or cause side effects. This is an additive interface and does not change existing human-readable output.
146
+
147
+ ## D-015: Keep documentation synchronized with the source baseline
148
+
149
+ **Status:** Active
150
+
151
+ User-facing setup and troubleshooting documents describe supported commands and guarantees only when they are present in the current CLI and scripts. The project state and decision log remain the handoff source for agents; architecture explains boundaries and data flow; the README stays a short entry point.
152
+
153
+ **Reason:** The project has both a GitHub source workflow and a separately published npm package. Stale examples, hard-coded tool counts, or old compatibility claims can cause users to run the wrong code or expose sensitive data while troubleshooting.
154
+
155
+ **Consequences:** When command options, platform support, data flow, security boundaries, or verification status changes, update the relevant document in the same change. Validate examples against `--help` and keep generated local output out of commits.
156
+
157
+ ## D-016: Use GPT-image-2 for future architecture visuals
158
+
159
+ **Status:** Active
160
+
161
+ When a new architecture diagram visual is requested, use GPT-image-2 for the visual asset. Keep the diagram's structure and labels aligned with the source documentation, validate the final dimensions and legibility, and retain a maintainable source representation when practical.
162
+
163
+ **Reason:** The project owner wants architecture visuals to use the project's image-generation workflow while keeping technical documentation understandable and reviewable.
164
+
165
+ **Consequences:** Do not silently substitute an unrelated image-generation model. Do not treat generated pixels as the source of truth; `ARCHITECTURE.md` and the code remain authoritative.
166
+
167
+ ## D-019: Require preview and confirmation for side effects
168
+
169
+ **Status:** Active
170
+
171
+ Machine-facing write operations use a two-phase protocol: first return a read-only preview, then execute only after explicit user approval. Todo completion, reopening, and deletion are the first commands implementing this rule.
172
+
173
+ **Reason:** An agent needs structured write access without gaining silent authority to alter local state. A stable preview and `CONFIRMATION_REQUIRED` response lets clients present the exact action before requesting approval.
174
+
175
+ **Consequences:** JSON-mode todo, access-control, message-send, configuration, destructive clear, assistant lifecycle, and local-reader startup operations require `--yes`; `--dry-run --json` never writes, deletes, or starts a process. Clear previews expose counts or impact flags rather than entries. Human access-control removals also ask for confirmation. Publishing and future side-effect interfaces must define equivalent confirmation boundaries before being advertised as agent-ready.
176
+
177
+ ## D-020: Keep secrets out of child-process arguments
178
+
179
+ **Status:** Active
180
+
181
+ The TypeScript CLI and Python pipeline pass AI credentials, database credentials, account or conversation identifiers, private queries and filters, export locations and display names, and sensitive scan roots to worker processes through environment variables. They do not append these values to child-process argument arrays.
182
+
183
+ **Reason:** Command-line arguments can be visible in process inspection tools and can be repeated in runtime errors. Environment inheritance narrows accidental exposure while preserving existing CLI, environment, and encrypted-configuration workflows.
184
+
185
+ **Consequences:** Python entry points keep explicit arguments for direct compatibility but also accept the internal `WEFLOW_*` environment variables. Long-lived workers clear unrelated internal variables before startup. New subprocess wrappers require a regression check before they may accept credentials, account identifiers, private questions, or local data roots.
186
+
187
+ ## D-021: Keep the default MCP surface read-only
188
+
189
+ **Status:** Active
190
+
191
+ The default MCP server exposes bounded read and local transformation tools only. It does not expose assistant-memory writes, official-account publishing, message sending, todo mutation, configuration changes, or deletion.
192
+
193
+ **Reason:** MCP clients can autonomously select tools and inherit the user's local permissions. Client-side approval prompts are not a stable substitute for the project's own preview and confirmation protocol.
194
+
195
+ **Consequences:** Write capabilities remain available only through explicit CLI or assistant workflows that implement an appropriate confirmation boundary. Conversation names must resolve uniquely, and MCP-facing limits reject invalid or excessive values instead of silently selecting or coercing them.
196
+
197
+ ## D-022: Keep source and compiled resource lookup equivalent
198
+
199
+ **Status:** Active
200
+
201
+ CLI, MCP, database, export, and assistant services resolve scripts, native resources, generated-output roots, and runtime entries from one shared package-root resolver rather than assuming a fixed source or `dist` directory depth.
202
+
203
+ **Reason:** Development runs execute `bin/weflow-cli.ts`, while installed and packaged runs execute `dist/bin/weflow-cli.js` through `cli.cjs`. Relative traversal that works in one layout can point at the parent repository or `dist/scripts` in the other layout.
204
+
205
+ **Consequences:** New commands and services must use the shared package-root resolver for bundled scripts, native libraries, runtime entries, and package-owned output. Both source and compiled module layouts require regression coverage when resource lookup changes.
206
+
207
+ ## D-023: Bound Agent-initiated network reads
208
+
209
+ **Status:** Active
210
+
211
+ MCP article fetching accepts only credential-free HTTPS URLs on the exact `mp.weixin.qq.com` host. Redirects are followed manually only while every destination remains allowed, with a finite redirect count, request timeout, and response-size limit. Public article search also validates its result limit and bounds the downloaded response.
212
+
213
+ **Reason:** Read-only tools can still reach external networks. Substring host checks, unrestricted redirects, and unbounded response bodies can enable SSRF, unexpected internal access, hangs, or memory exhaustion.
214
+
215
+ **Consequences:** New network-facing Agent tools must define an allowlist or equivalent public-network validation, finite time and size budgets, and tests that reject crafted URLs before network access.
216
+
217
+ ## D-024: Confirm Vault publication
218
+
219
+ **Status:** Active
220
+
221
+ `vault sync` uses `--dry-run --json` for a content-free preview and requires explicit `--yes --json` for machine execution. Preview and result JSON omit file names and remote URLs.
222
+
223
+ **Reason:** A Git push discloses local files outside the machine even when the Vault itself is local. The old change check also ignored untracked files, making first-run behavior unreliable.
224
+
225
+ **Consequences:** The command detects tracked and untracked changes with `git status --porcelain`, does not initialize a repository during preview, and does not expose credential-bearing remote URLs in output.
226
+
227
+ ## D-025: Confirm local generation and cloud analysis
228
+
229
+ **Status:** Active
230
+
231
+ Commands that create or replace local knowledge artifacts, build semantic indexes, or send selected content to an AI provider use a read-only preview followed by explicit confirmation. This applies even when no remote publication occurs.
232
+
233
+ **Reason:** Local file writes can overwrite user-managed material, while AI and embedding workflows can disclose selected content and consume quota. Treating only network publication as a side effect leaves Agent-driven local generation insufficiently controlled.
234
+
235
+ **Consequences:** Vault content mutations, Vault RAG, semantic search, RAG chat, evidence review, Wiki compilation, todo extraction, daily-favorite changes, semantic indexing, knowledge pipelines, and report generators expose `--dry-run --json` and require `--yes --json` for machine execution. Interactive key capture and interactive RAG chat expose previews but reject JSON execution. Preview mode does not read private content, call external services, scan processes, or write files; structured status results omit local paths, selected names, logs, and generated content. Queries, questions, and conversation restrictions passed to Python workers use environment inheritance instead of process arguments.
236
+
237
+ ## D-026: Reject unsupported WCDB query parameters
238
+
239
+ **Status:** Active
240
+
241
+ The bundled WCDB DLL exposes a raw SQL query ABI without parameter binding. `execQuery` rejects non-empty parameter arrays until the native interface can be upgraded and verified.
242
+
243
+ **Reason:** Silently ignoring parameters and executing the original SQL would create a misleading and unsafe API contract for future callers.
244
+
245
+ **Consequences:** Existing fixed internal queries are unchanged. A future parameterized implementation requires a native ABI change, compatibility testing, and a separate security review.
246
+
247
+ ## D-027: Add conservative coverage metadata to the versioned message contract
248
+
249
+ **Status:** Active
250
+
251
+ `weflow-message/v1` may include query coverage metadata such as requested bounds, returned count, returned time bounds, and a conservative `mayHaveMore` flag. The legacy `raw` export remains a top-level message array and does not gain this metadata.
252
+
253
+ **Reason:** Downstream data consumers need enough information to checkpoint time-window synchronization without treating a timestamp as a globally unique cursor or assuming that a database shard is complete.
254
+
255
+ **Consequences:** Consumers can perform overlapping time-window reads and deduplicate locally. A stable incremental cursor remains a separate future change and must be supported by all relevant database backends before it is advertised.
256
+
257
+ ## Decision Template
258
+
259
+
260
+ ```markdown
261
+ ## D-XXX: Short title
262
+
263
+ **Status:** Proposed | Active | Superseded
264
+
265
+ State the decision in one or two sentences.
266
+
267
+ **Reason:** Explain the constraint, trade-off, and why alternatives were not selected.
268
+
269
+ **Consequences:** List compatibility, migration, security, or documentation follow-up when relevant.
270
+ ```