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
@@ -1,308 +1,308 @@
1
- /**
2
- * 微信读书 Agent API Gateway 封装
3
- *
4
- * 接口文档: ~/.claude/skills/weread-skills/
5
- * Gateway: https://i.weread.qq.com/api/agent/gateway
6
- */
7
-
8
- import https from 'node:https'
9
-
10
- const GATEWAY = 'https://i.weread.qq.com/api/agent/gateway'
11
- const SKILL_VERSION = '1.0.3'
12
-
13
- // weread.qq.com 服务端不支持 TLS 1.3,需要强制使用 TLS 1.2
14
- const httpsAgent = new https.Agent({ maxVersion: 'TLSv1.2' })
15
-
16
- export interface WereadResult<T = any> {
17
- ok: boolean
18
- data?: T
19
- error?: string
20
- }
21
-
22
- // ---- shelf ----
23
-
24
- export interface ShelfBook {
25
- bookId: string
26
- title: string
27
- author: string
28
- cover: string
29
- category: string
30
- readUpdateTime: number
31
- finishReading: number
32
- updateTime: number
33
- secret: number
34
- isTop: boolean
35
- payType: number
36
- }
37
-
38
- export interface ShelfData {
39
- books: ShelfBook[]
40
- albums: any[]
41
- mp: any
42
- archive: { name: string; bookIds: string[]; albumIds: string[] }[]
43
- bookCount: number
44
- }
45
-
46
- // ---- readdata ----
47
-
48
- export interface ReadDetail {
49
- baseTime: number
50
- readTimes: Record<string, number>
51
- readDays: number
52
- totalReadTime: number
53
- dayAverageReadTime: number
54
- compare?: number
55
- readLongest: { book?: any; albumInfo?: any; readTime: number; tags?: string[] }[]
56
- readStat: { stat: string; counts: string; scheme?: string }[]
57
- preferCategory: { categoryId: number; categoryTitle: string; readingTime: number; readingCount: number; val: number }[]
58
- preferCategoryWord?: string
59
- preferTime: number[]
60
- preferTimeWord?: string
61
- }
62
-
63
- // ---- notes ----
64
-
65
- export interface NotebookItem {
66
- bookId: string
67
- title: string
68
- author: string
69
- cover: string
70
- highlightCount: number
71
- noteCount: number
72
- bookmarkCount: number
73
- updateTime: number
74
- }
75
-
76
- export interface NoteDetail {
77
- bookId: string
78
- chapterUid: number
79
- chapterTitle: string
80
- markText: string
81
- content: string
82
- range: string
83
- createTime: number
84
- type: number // 0=划线, 1=想法
85
- }
86
-
87
- // ---- search ----
88
-
89
- export interface SearchResult {
90
- bookId: string
91
- title: string
92
- author: string
93
- cover: string
94
- rating: number
95
- ratingCount: number
96
- category: string
97
- wordCount: string
98
- intro: string
99
- }
100
-
101
- // ---- book ----
102
-
103
- export interface BookInfo {
104
- bookId: string
105
- title: string
106
- author: string
107
- cover: string
108
- rating: number
109
- ratingCount: number
110
- category: string
111
- wordCount: string
112
- intro: string
113
- publisher: string
114
- isbn: string
115
- totalWords: string
116
- format: string
117
- }
118
-
119
- export interface ChapterInfo {
120
- bookId: string
121
- title: string
122
- chapters: { chapterUid: number; title: string; level: number; wordCount: number }[]
123
- }
124
-
125
- // ---- review ----
126
-
127
- export interface BookReview {
128
- reviewId: string
129
- content: string
130
- rating: number
131
- createTime: number
132
- user: { name: string; avatar: string }
133
- likeCount: number
134
- }
135
-
136
- // ---- discover ----
137
-
138
- export interface RecommendBook {
139
- bookId: string
140
- title: string
141
- author: string
142
- cover: string
143
- rating: number
144
- intro: string
145
- }
146
-
147
- // ---- profile ----
148
-
149
- export interface UserProfile {
150
- vid: string
151
- name: string
152
- avatar: string
153
- gender: number
154
- totalReadTime: number
155
- totalReadDays: number
156
- totalBooks: number
157
- totalFinished: number
158
- totalNotes: number
159
- totalHighlights: number
160
- totalReviews: number
161
- }
162
-
163
-
164
- export class WereadService {
165
- private apiKey: string
166
-
167
- constructor(apiKey?: string) {
168
- this.apiKey = apiKey || process.env.WEREAD_API_KEY || ''
169
- }
170
-
171
- private async call<T>(apiName: string, params: Record<string, any> = {}): Promise<WereadResult<T>> {
172
- if (!this.apiKey) {
173
- return { ok: false, error: '未设置 WEREAD_API_KEY,请设置环境变量或在 CLI 中配置' }
174
- }
175
-
176
- try {
177
- const body = JSON.stringify({ api_name: apiName, skill_version: SKILL_VERSION, ...params })
178
- const json = await new Promise<any>((resolve, reject) => {
179
- const url = new URL(GATEWAY)
180
- const req = https.request({
181
- hostname: url.hostname,
182
- path: url.pathname,
183
- method: 'POST',
184
- agent: httpsAgent,
185
- headers: {
186
- 'Authorization': `Bearer ${this.apiKey}`,
187
- 'Content-Type': 'application/json',
188
- 'Content-Length': Buffer.byteLength(body),
189
- },
190
- }, (res) => {
191
- let data = ''
192
- res.on('data', (chunk: Buffer) => data += chunk.toString())
193
- res.on('end', () => {
194
- try { resolve(JSON.parse(data)) }
195
- catch { reject(new Error(`Invalid JSON response: ${data.slice(0, 200)}`)) }
196
- })
197
- })
198
- req.on('error', reject)
199
- req.write(body)
200
- req.end()
201
- })
202
-
203
- if (json.errcode && json.errcode !== 0) {
204
- return { ok: false, error: `API 错误: ${json.errmsg || json.errcode}` }
205
- }
206
- return { ok: true, data: json as T }
207
- } catch (e: any) {
208
- return { ok: false, error: `请求失败: ${e.message}` }
209
- }
210
- }
211
-
212
- /** 书架同步 */
213
- async shelf(): Promise<WereadResult<ShelfData>> {
214
- return this.call<ShelfData>('/shelf/sync')
215
- }
216
-
217
- /** 阅读统计: mode = weekly | monthly | annually | overall */
218
- async readData(mode: string = 'monthly', baseTime?: number): Promise<WereadResult<ReadDetail>> {
219
- const params: any = { mode }
220
- if (baseTime !== undefined) params.baseTime = baseTime
221
- return this.call<ReadDetail>('/readdata/detail', params)
222
- }
223
-
224
- /** 笔记列表: 获取用户的笔记本列表 */
225
- async notebooks(count: number = 100, lastSort?: number): Promise<WereadResult<{ books: NotebookItem[]; synckey: number }>> {
226
- const params: any = { count }
227
- if (lastSort !== undefined) params.lastSort = lastSort
228
- return this.call('/user/notebooks', params)
229
- }
230
-
231
- /** 某本书的划线 */
232
- async bookmarks(bookId: string, count: number = 50): Promise<WereadResult<{ updated: NoteDetail[]; removed: any[]; synckey: number }>> {
233
- return this.call('/book/bookmarklist', { bookId, count })
234
- }
235
-
236
- /** 某本书的热门划线 */
237
- async bestBookmarks(bookId: string, count: number = 20): Promise<WereadResult<{ chapters: any[] }>> {
238
- return this.call('/book/bestbookmarks', { bookId, count })
239
- }
240
-
241
- /** 搜索书籍 */
242
- async search(keyword: string, count: number = 10, scope: string = 'all'): Promise<WereadResult<{ books: SearchResult[] }>> {
243
- return this.call('/store/search', { keyword, count, scope })
244
- }
245
-
246
- /** 书籍详情 */
247
- async bookInfo(bookId: string): Promise<WereadResult<BookInfo>> {
248
- return this.call<BookInfo>('/book/info', { bookId })
249
- }
250
-
251
- /** 章节目录 */
252
- async chapterInfo(bookId: string): Promise<WereadResult<ChapterInfo>> {
253
- return this.call<ChapterInfo>('/book/chapterinfo', { bookId })
254
- }
255
-
256
- /** 阅读进度 */
257
- async getProgress(bookId: string): Promise<WereadResult<{ chapterUid: number; chapterTitle: string; progress: number }>> {
258
- return this.call('/book/getprogress', { bookId })
259
- }
260
-
261
- /** 书评 */
262
- async reviews(bookId: string, count: number = 20, sort: string = 'hot'): Promise<WereadResult<{ reviews: BookReview[] }>> {
263
- return this.call('/book/readreviews', { bookId, count, sort })
264
- }
265
-
266
- /** 个性化推荐 */
267
- async recommend(count: number = 10): Promise<WereadResult<{ books: RecommendBook[] }>> {
268
- return this.call('/book/recommend', { count })
269
- }
270
-
271
- /** 相似推荐 */
272
- async similar(bookId: string, count: number = 5): Promise<WereadResult<{ books: RecommendBook[] }>> {
273
- return this.call('/book/recommend', { bookId, count, type: 'similar' })
274
- }
275
-
276
- /** 个人中心(聚合多个接口) */
277
- async profile(): Promise<WereadResult<UserProfile>> {
278
- const [shelfRes, readRes] = await Promise.all([
279
- this.shelf(),
280
- this.readData('overall'),
281
- ])
282
-
283
- if (!shelfRes.ok) return { ok: false, error: shelfRes.error }
284
- if (!readRes.ok) return { ok: false, error: readRes.error }
285
-
286
- const shelf = shelfRes.data!
287
- const read = readRes.data!
288
-
289
- return {
290
- ok: true,
291
- data: {
292
- vid: '',
293
- name: '',
294
- avatar: '',
295
- gender: 0,
296
- totalReadTime: read.totalReadTime || 0,
297
- totalReadDays: read.readDays || 0,
298
- totalBooks: shelf.books?.length || 0,
299
- totalFinished: shelf.books?.filter(b => b.finishReading === 1).length || 0,
300
- totalNotes: 0,
301
- totalHighlights: 0,
302
- totalReviews: 0,
303
- },
304
- }
305
- }
306
- }
307
-
308
- export const wereadService = new WereadService()
1
+ /**
2
+ * 微信读书 Agent API Gateway 封装
3
+ *
4
+ * 接口文档: ~/.claude/skills/weread-skills/
5
+ * Gateway: https://i.weread.qq.com/api/agent/gateway
6
+ */
7
+
8
+ import https from 'node:https'
9
+
10
+ const GATEWAY = 'https://i.weread.qq.com/api/agent/gateway'
11
+ const SKILL_VERSION = '1.0.3'
12
+
13
+ // weread.qq.com 服务端不支持 TLS 1.3,需要强制使用 TLS 1.2
14
+ const httpsAgent = new https.Agent({ maxVersion: 'TLSv1.2' })
15
+
16
+ export interface WereadResult<T = any> {
17
+ ok: boolean
18
+ data?: T
19
+ error?: string
20
+ }
21
+
22
+ // ---- shelf ----
23
+
24
+ export interface ShelfBook {
25
+ bookId: string
26
+ title: string
27
+ author: string
28
+ cover: string
29
+ category: string
30
+ readUpdateTime: number
31
+ finishReading: number
32
+ updateTime: number
33
+ secret: number
34
+ isTop: boolean
35
+ payType: number
36
+ }
37
+
38
+ export interface ShelfData {
39
+ books: ShelfBook[]
40
+ albums: any[]
41
+ mp: any
42
+ archive: { name: string; bookIds: string[]; albumIds: string[] }[]
43
+ bookCount: number
44
+ }
45
+
46
+ // ---- readdata ----
47
+
48
+ export interface ReadDetail {
49
+ baseTime: number
50
+ readTimes: Record<string, number>
51
+ readDays: number
52
+ totalReadTime: number
53
+ dayAverageReadTime: number
54
+ compare?: number
55
+ readLongest: { book?: any; albumInfo?: any; readTime: number; tags?: string[] }[]
56
+ readStat: { stat: string; counts: string; scheme?: string }[]
57
+ preferCategory: { categoryId: number; categoryTitle: string; readingTime: number; readingCount: number; val: number }[]
58
+ preferCategoryWord?: string
59
+ preferTime: number[]
60
+ preferTimeWord?: string
61
+ }
62
+
63
+ // ---- notes ----
64
+
65
+ export interface NotebookItem {
66
+ bookId: string
67
+ title: string
68
+ author: string
69
+ cover: string
70
+ highlightCount: number
71
+ noteCount: number
72
+ bookmarkCount: number
73
+ updateTime: number
74
+ }
75
+
76
+ export interface NoteDetail {
77
+ bookId: string
78
+ chapterUid: number
79
+ chapterTitle: string
80
+ markText: string
81
+ content: string
82
+ range: string
83
+ createTime: number
84
+ type: number // 0=划线, 1=想法
85
+ }
86
+
87
+ // ---- search ----
88
+
89
+ export interface SearchResult {
90
+ bookId: string
91
+ title: string
92
+ author: string
93
+ cover: string
94
+ rating: number
95
+ ratingCount: number
96
+ category: string
97
+ wordCount: string
98
+ intro: string
99
+ }
100
+
101
+ // ---- book ----
102
+
103
+ export interface BookInfo {
104
+ bookId: string
105
+ title: string
106
+ author: string
107
+ cover: string
108
+ rating: number
109
+ ratingCount: number
110
+ category: string
111
+ wordCount: string
112
+ intro: string
113
+ publisher: string
114
+ isbn: string
115
+ totalWords: string
116
+ format: string
117
+ }
118
+
119
+ export interface ChapterInfo {
120
+ bookId: string
121
+ title: string
122
+ chapters: { chapterUid: number; title: string; level: number; wordCount: number }[]
123
+ }
124
+
125
+ // ---- review ----
126
+
127
+ export interface BookReview {
128
+ reviewId: string
129
+ content: string
130
+ rating: number
131
+ createTime: number
132
+ user: { name: string; avatar: string }
133
+ likeCount: number
134
+ }
135
+
136
+ // ---- discover ----
137
+
138
+ export interface RecommendBook {
139
+ bookId: string
140
+ title: string
141
+ author: string
142
+ cover: string
143
+ rating: number
144
+ intro: string
145
+ }
146
+
147
+ // ---- profile ----
148
+
149
+ export interface UserProfile {
150
+ vid: string
151
+ name: string
152
+ avatar: string
153
+ gender: number
154
+ totalReadTime: number
155
+ totalReadDays: number
156
+ totalBooks: number
157
+ totalFinished: number
158
+ totalNotes: number
159
+ totalHighlights: number
160
+ totalReviews: number
161
+ }
162
+
163
+
164
+ export class WereadService {
165
+ private apiKey: string
166
+
167
+ constructor(apiKey?: string) {
168
+ this.apiKey = apiKey || process.env.WEREAD_API_KEY || ''
169
+ }
170
+
171
+ private async call<T>(apiName: string, params: Record<string, any> = {}): Promise<WereadResult<T>> {
172
+ if (!this.apiKey) {
173
+ return { ok: false, error: '未设置 WEREAD_API_KEY,请设置环境变量或在 CLI 中配置' }
174
+ }
175
+
176
+ try {
177
+ const body = JSON.stringify({ api_name: apiName, skill_version: SKILL_VERSION, ...params })
178
+ const json = await new Promise<any>((resolve, reject) => {
179
+ const url = new URL(GATEWAY)
180
+ const req = https.request({
181
+ hostname: url.hostname,
182
+ path: url.pathname,
183
+ method: 'POST',
184
+ agent: httpsAgent,
185
+ headers: {
186
+ 'Authorization': `Bearer ${this.apiKey}`,
187
+ 'Content-Type': 'application/json',
188
+ 'Content-Length': Buffer.byteLength(body),
189
+ },
190
+ }, (res) => {
191
+ let data = ''
192
+ res.on('data', (chunk: Buffer) => data += chunk.toString())
193
+ res.on('end', () => {
194
+ try { resolve(JSON.parse(data)) }
195
+ catch { reject(new Error(`Invalid JSON response: ${data.slice(0, 200)}`)) }
196
+ })
197
+ })
198
+ req.on('error', reject)
199
+ req.write(body)
200
+ req.end()
201
+ })
202
+
203
+ if (json.errcode && json.errcode !== 0) {
204
+ return { ok: false, error: `API 错误: ${json.errmsg || json.errcode}` }
205
+ }
206
+ return { ok: true, data: json as T }
207
+ } catch (e: any) {
208
+ return { ok: false, error: `请求失败: ${e.message}` }
209
+ }
210
+ }
211
+
212
+ /** 书架同步 */
213
+ async shelf(): Promise<WereadResult<ShelfData>> {
214
+ return this.call<ShelfData>('/shelf/sync')
215
+ }
216
+
217
+ /** 阅读统计: mode = weekly | monthly | annually | overall */
218
+ async readData(mode: string = 'monthly', baseTime?: number): Promise<WereadResult<ReadDetail>> {
219
+ const params: any = { mode }
220
+ if (baseTime !== undefined) params.baseTime = baseTime
221
+ return this.call<ReadDetail>('/readdata/detail', params)
222
+ }
223
+
224
+ /** 笔记列表: 获取用户的笔记本列表 */
225
+ async notebooks(count: number = 100, lastSort?: number): Promise<WereadResult<{ books: NotebookItem[]; synckey: number }>> {
226
+ const params: any = { count }
227
+ if (lastSort !== undefined) params.lastSort = lastSort
228
+ return this.call('/user/notebooks', params)
229
+ }
230
+
231
+ /** 某本书的划线 */
232
+ async bookmarks(bookId: string, count: number = 50): Promise<WereadResult<{ updated: NoteDetail[]; removed: any[]; synckey: number }>> {
233
+ return this.call('/book/bookmarklist', { bookId, count })
234
+ }
235
+
236
+ /** 某本书的热门划线 */
237
+ async bestBookmarks(bookId: string, count: number = 20): Promise<WereadResult<{ chapters: any[] }>> {
238
+ return this.call('/book/bestbookmarks', { bookId, count })
239
+ }
240
+
241
+ /** 搜索书籍 */
242
+ async search(keyword: string, count: number = 10, scope: string = 'all'): Promise<WereadResult<{ books: SearchResult[] }>> {
243
+ return this.call('/store/search', { keyword, count, scope })
244
+ }
245
+
246
+ /** 书籍详情 */
247
+ async bookInfo(bookId: string): Promise<WereadResult<BookInfo>> {
248
+ return this.call<BookInfo>('/book/info', { bookId })
249
+ }
250
+
251
+ /** 章节目录 */
252
+ async chapterInfo(bookId: string): Promise<WereadResult<ChapterInfo>> {
253
+ return this.call<ChapterInfo>('/book/chapterinfo', { bookId })
254
+ }
255
+
256
+ /** 阅读进度 */
257
+ async getProgress(bookId: string): Promise<WereadResult<{ chapterUid: number; chapterTitle: string; progress: number }>> {
258
+ return this.call('/book/getprogress', { bookId })
259
+ }
260
+
261
+ /** 书评 */
262
+ async reviews(bookId: string, count: number = 20, sort: string = 'hot'): Promise<WereadResult<{ reviews: BookReview[] }>> {
263
+ return this.call('/book/readreviews', { bookId, count, sort })
264
+ }
265
+
266
+ /** 个性化推荐 */
267
+ async recommend(count: number = 10): Promise<WereadResult<{ books: RecommendBook[] }>> {
268
+ return this.call('/book/recommend', { count })
269
+ }
270
+
271
+ /** 相似推荐 */
272
+ async similar(bookId: string, count: number = 5): Promise<WereadResult<{ books: RecommendBook[] }>> {
273
+ return this.call('/book/recommend', { bookId, count, type: 'similar' })
274
+ }
275
+
276
+ /** 个人中心(聚合多个接口) */
277
+ async profile(): Promise<WereadResult<UserProfile>> {
278
+ const [shelfRes, readRes] = await Promise.all([
279
+ this.shelf(),
280
+ this.readData('overall'),
281
+ ])
282
+
283
+ if (!shelfRes.ok) return { ok: false, error: shelfRes.error }
284
+ if (!readRes.ok) return { ok: false, error: readRes.error }
285
+
286
+ const shelf = shelfRes.data!
287
+ const read = readRes.data!
288
+
289
+ return {
290
+ ok: true,
291
+ data: {
292
+ vid: '',
293
+ name: '',
294
+ avatar: '',
295
+ gender: 0,
296
+ totalReadTime: read.totalReadTime || 0,
297
+ totalReadDays: read.readDays || 0,
298
+ totalBooks: shelf.books?.length || 0,
299
+ totalFinished: shelf.books?.filter(b => b.finishReading === 1).length || 0,
300
+ totalNotes: 0,
301
+ totalHighlights: 0,
302
+ totalReviews: 0,
303
+ },
304
+ }
305
+ }
306
+ }
307
+
308
+ export const wereadService = new WereadService()