weflow-cli 1.5.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (331) hide show
  1. package/ARCHITECTURE.md +105 -0
  2. package/CHANGELOG.md +110 -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 +333 -149
  8. package/SECURITY.md +47 -0
  9. package/bin/weflow-cli.ts +4032 -583
  10. package/dist/bin/weflow-cli.js +4296 -593
  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 +188 -64
  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/ROADMAP.md +191 -0
  132. package/docs/SETUP.md +103 -0
  133. package/docs/images/weflow-architecture-gpt-image-2.png +0 -0
  134. package/docs/images/weflow-architecture.png +0 -0
  135. package/docs/images/weflow-architecture.svg +65 -0
  136. package/mcp-server/index.ts +169 -269
  137. package/package.json +81 -72
  138. package/requirements-3x.txt +4 -0
  139. package/requirements-voice.txt +15 -0
  140. package/requirements.txt +9 -0
  141. package/resources/js/marked.min.js +69 -0
  142. package/resources/wechat-emoji/666.png +0 -0
  143. package/resources/wechat-emoji/Awesome.png +0 -0
  144. package/resources/wechat-emoji/Concerned.png +0 -0
  145. package/resources/wechat-emoji/Cry.png +0 -0
  146. package/resources/wechat-emoji/Emm.png +0 -0
  147. package/resources/wechat-emoji/Facepalm.png +0 -0
  148. package/resources/wechat-emoji/Grin.png +0 -0
  149. package/resources/wechat-emoji/OK.png +0 -0
  150. package/resources/wechat-emoji/Respect.png +0 -0
  151. package/resources/wechat-emoji/Sick.png +0 -0
  152. package/resources/wechat-emoji/Sleep.png +0 -0
  153. package/resources/wechat-emoji/Smile.png +0 -0
  154. package/resources/wechat-emoji//344/272/262/344/272/262.png +0 -0
  155. package/resources/wechat-emoji//344/276/277/344/276/277.png +0 -0
  156. package/resources/wechat-emoji//345/201/267/347/254/221.png +0 -0
  157. package/resources/wechat-emoji//345/202/262/346/205/242.png +0 -0
  158. package/resources/wechat-emoji//345/206/215/350/247/201.png +0 -0
  159. package/resources/wechat-emoji//345/207/213/350/260/242.png +0 -0
  160. package/resources/wechat-emoji//345/212/240/346/262/271.png +0 -0
  161. package/resources/wechat-emoji//345/213/276/345/274/225.png +0 -0
  162. package/resources/wechat-emoji//345/217/221/345/221/206.png +0 -0
  163. package/resources/wechat-emoji//345/217/221/346/200/222.png +0 -0
  164. package/resources/wechat-emoji//345/217/221/346/212/226.png +0 -0
  165. package/resources/wechat-emoji//345/217/257/346/200/234.png +0 -0
  166. package/resources/wechat-emoji//345/217/263/345/223/274/345/223/274.png +0 -0
  167. package/resources/wechat-emoji//345/217/271/346/260/224.png +0 -0
  168. package/resources/wechat-emoji//345/220/203/347/223/234.png +0 -0
  169. package/resources/wechat-emoji//345/220/210/345/215/201.png +0 -0
  170. package/resources/wechat-emoji//345/220/220.png +0 -0
  171. package/resources/wechat-emoji//345/221/262/347/211/231.png +0 -0
  172. package/resources/wechat-emoji//345/222/222/351/252/202.png +0 -0
  173. package/resources/wechat-emoji//345/222/226/345/225/241.png +0 -0
  174. package/resources/wechat-emoji//345/223/207.png +0 -0
  175. package/resources/wechat-emoji//345/225/244/351/205/222.png +0 -0
  176. package/resources/wechat-emoji//345/230/230.png +0 -0
  177. package/resources/wechat-emoji//345/230/264/345/224/207.png +0 -0
  178. package/resources/wechat-emoji//345/230/277/345/223/210.png +0 -0
  179. package/resources/wechat-emoji//345/233/247.png +0 -0
  180. package/resources/wechat-emoji//345/233/260.png +0 -0
  181. package/resources/wechat-emoji//345/235/217/347/254/221.png +0 -0
  182. package/resources/wechat-emoji//345/244/247/345/223/255.png +0 -0
  183. package/resources/wechat-emoji//345/244/251/345/225/212.png +0 -0
  184. package/resources/wechat-emoji//345/244/252/351/230/263.png +0 -0
  185. package/resources/wechat-emoji//345/244/261/346/234/233.png +0 -0
  186. package/resources/wechat-emoji//345/245/270/347/254/221.png +0 -0
  187. package/resources/wechat-emoji//345/245/275/347/232/204.png +0 -0
  188. package/resources/wechat-emoji//345/247/224/345/261/210.png +0 -0
  189. package/resources/wechat-emoji//345/256/263/347/276/236.png +0 -0
  190. package/resources/wechat-emoji//345/260/264/345/260/254.png +0 -0
  191. package/resources/wechat-emoji//345/272/206/347/245/235.png +0 -0
  192. package/resources/wechat-emoji//345/274/261.png +0 -0
  193. package/resources/wechat-emoji//345/274/272.png +0 -0
  194. package/resources/wechat-emoji//345/276/227/346/204/217.png +0 -0
  195. package/resources/wechat-emoji//345/276/256/347/254/221.png +0 -0
  196. package/resources/wechat-emoji//345/277/203/347/242/216.png +0 -0
  197. package/resources/wechat-emoji//345/277/253/345/223/255/344/272/206.png +0 -0
  198. package/resources/wechat-emoji//346/201/220/346/203/247.png +0 -0
  199. package/resources/wechat-emoji//346/202/240/351/227/262.png +0 -0
  200. package/resources/wechat-emoji//346/203/212/346/201/220.png +0 -0
  201. package/resources/wechat-emoji//346/203/212/350/256/266.png +0 -0
  202. package/resources/wechat-emoji//346/204/211/345/277/253.png +0 -0
  203. package/resources/wechat-emoji//346/206/250/347/254/221.png +0 -0
  204. package/resources/wechat-emoji//346/211/223/350/204/270.png +0 -0
  205. package/resources/wechat-emoji//346/212/223/347/213/202.png +0 -0
  206. package/resources/wechat-emoji//346/212/240/351/274/273.png +0 -0
  207. package/resources/wechat-emoji//346/212/261/346/213/263.png +0 -0
  208. package/resources/wechat-emoji//346/213/245/346/212/261.png +0 -0
  209. package/resources/wechat-emoji//346/213/263/345/244/264.png +0 -0
  210. package/resources/wechat-emoji//346/215/202/350/204/270.png +0 -0
  211. package/resources/wechat-emoji//346/217/241/346/211/213.png +0 -0
  212. package/resources/wechat-emoji//346/222/207/345/230/264.png +0 -0
  213. package/resources/wechat-emoji//346/223/246/346/261/227.png +0 -0
  214. package/resources/wechat-emoji//346/225/262/346/211/223.png +0 -0
  215. package/resources/wechat-emoji//346/227/240/350/257/255.png +0 -0
  216. package/resources/wechat-emoji//346/227/272/346/237/264.png +0 -0
  217. package/resources/wechat-emoji//346/231/225.png +0 -0
  218. package/resources/wechat-emoji//346/234/210/344/272/256.png +0 -0
  219. package/resources/wechat-emoji//346/234/272/346/231/272.png +0 -0
  220. package/resources/wechat-emoji//346/261/227.png +0 -0
  221. package/resources/wechat-emoji//346/265/201/346/263/252.png +0 -0
  222. package/resources/wechat-emoji//347/202/270/345/274/271.png +0 -0
  223. package/resources/wechat-emoji//347/203/237/350/212/261.png +0 -0
  224. package/resources/wechat-emoji//347/210/206/347/253/271.png +0 -0
  225. package/resources/wechat-emoji//347/210/261/345/277/203.png +0 -0
  226. package/resources/wechat-emoji//347/214/252/345/244/264.png +0 -0
  227. package/resources/wechat-emoji//347/216/253/347/221/260.png +0 -0
  228. package/resources/wechat-emoji//347/224/237/347/227/205.png +0 -0
  229. package/resources/wechat-emoji//347/226/221/351/227/256.png +0 -0
  230. package/resources/wechat-emoji//347/231/274.png +0 -0
  231. package/resources/wechat-emoji//347/231/275/347/234/274.png +0 -0
  232. package/resources/wechat-emoji//347/232/261/347/234/211.png +0 -0
  233. package/resources/wechat-emoji//347/235/241.png +0 -0
  234. package/resources/wechat-emoji//347/240/264/346/266/225/344/270/272/347/254/221.png +0 -0
  235. package/resources/wechat-emoji//347/244/274/347/211/251.png +0 -0
  236. package/resources/wechat-emoji//347/244/276/344/274/232/347/244/276/344/274/232.png +0 -0
  237. package/resources/wechat-emoji//347/246/217.png +0 -0
  238. package/resources/wechat-emoji//347/254/221/350/204/270.png +0 -0
  239. package/resources/wechat-emoji//347/272/242/345/214/205.png +0 -0
  240. package/resources/wechat-emoji//347/277/273/347/231/275/347/234/274.png +0 -0
  241. package/resources/wechat-emoji//350/200/266.png +0 -0
  242. package/resources/wechat-emoji//350/203/234/345/210/251.png +0 -0
  243. package/resources/wechat-emoji//350/204/270/347/272/242.png +0 -0
  244. package/resources/wechat-emoji//350/211/262.png +0 -0
  245. package/resources/wechat-emoji//350/213/246/346/266/251.png +0 -0
  246. package/resources/wechat-emoji//350/217/234/345/210/200.png +0 -0
  247. package/resources/wechat-emoji//350/233/213/347/263/225.png +0 -0
  248. package/resources/wechat-emoji//350/241/260.png +0 -0
  249. package/resources/wechat-emoji//350/243/202/345/274/200.png +0 -0
  250. package/resources/wechat-emoji//350/256/251/346/210/221/347/234/213/347/234/213.png +0 -0
  251. package/resources/wechat-emoji//350/260/203/347/232/256.png +0 -0
  252. package/resources/wechat-emoji//350/267/263/350/267/263.png +0 -0
  253. package/resources/wechat-emoji//350/275/254/345/234/210.png +0 -0
  254. package/resources/wechat-emoji//351/204/231/350/247/206.png +0 -0
  255. package/resources/wechat-emoji//351/227/255/345/230/264.png +0 -0
  256. package/resources/wechat-emoji//351/230/264/351/231/251.png +0 -0
  257. package/resources/wechat-emoji//351/232/276/350/277/207.png +0 -0
  258. package/resources/wechat-emoji//351/252/267/351/253/205.png +0 -0
  259. package/resources/wechat-emoji//351/274/223/346/216/214.png +0 -0
  260. package/scripts/_batch_link_sources.py +73 -73
  261. package/scripts/_utils.py +29 -0
  262. package/scripts/annual_report.py +796 -796
  263. package/scripts/auto_tag.py +128 -128
  264. package/scripts/biz_daily.py +210 -53
  265. package/scripts/chat_report.py +10 -0
  266. package/scripts/chat_stats.py +702 -702
  267. package/scripts/classify_daily.py +17 -11
  268. package/scripts/create_reading_notes.py +370 -370
  269. package/scripts/daily_stats.py +132 -0
  270. package/scripts/enrich_backlinks.py +163 -163
  271. package/scripts/export_chat_html.py +1704 -107
  272. package/scripts/extract_todos.py +445 -404
  273. package/scripts/fav_server.py +119 -12
  274. package/scripts/fix_topics.py +111 -111
  275. package/scripts/generate_ai_report.py +1 -1
  276. package/scripts/generate_html.py +597 -277
  277. package/scripts/inspection_records.py +354 -0
  278. package/scripts/mcp_bridge.py +398 -398
  279. package/scripts/nt_decrypt.py +693 -48
  280. package/scripts/pipeline.py +27 -19
  281. package/scripts/promote_all.py +312 -310
  282. package/scripts/promote_ideas.py +299 -297
  283. package/scripts/rag_chat.py +194 -191
  284. package/scripts/semantic_search.py +435 -431
  285. package/scripts/sync_fav.py +201 -146
  286. package/scripts/sync_weread.py +192 -192
  287. package/scripts/vault_rag.py +140 -139
  288. package/scripts/vault_search.py +141 -141
  289. package/scripts/wechat_emoji.py +132 -0
  290. package/scripts/wechat_emoticon.py +433 -0
  291. package/scripts/wechat_image.py +258 -0
  292. package/scripts/wechat_voice.py +327 -0
  293. package/src/core/dbPathService.ts +163 -18
  294. package/src/core/keyService.ts +137 -25
  295. package/src/core/ntCore.ts +202 -61
  296. package/src/core/sqlcipherCore.ts +17 -1
  297. package/src/core/wcdbCore.ts +3 -7
  298. package/src/services/assistantDaemon.ts +111 -0
  299. package/src/services/assistantMemory.ts +193 -0
  300. package/src/services/assistantPrivacy.ts +87 -0
  301. package/src/services/assistantRouting.ts +92 -0
  302. package/src/services/assistantService.ts +295 -0
  303. package/src/services/assistantTools.ts +549 -0
  304. package/src/services/chatService.ts +133 -4
  305. package/src/services/configService.ts +194 -6
  306. package/src/services/evidenceService.ts +129 -0
  307. package/src/services/exportService.ts +113 -48
  308. package/src/services/initKeyService.ts +83 -0
  309. package/src/services/messageContract.ts +77 -0
  310. package/src/services/messageQuery.ts +38 -0
  311. package/src/services/wechat-formatter.ts +348 -348
  312. package/src/services/wechatMessageService.ts +25 -3
  313. package/src/services/wereadService.ts +308 -308
  314. package/src/services/whitelistService.ts +209 -22
  315. package/src/types.ts +20 -0
  316. package/src/utils/dateRange.ts +58 -0
  317. package/src/utils/mcpSecurity.ts +39 -0
  318. package/src/utils/packageRoot.ts +14 -0
  319. package/src/utils/python.ts +73 -0
  320. package/src/utils/pythonProcessEnv.ts +45 -0
  321. package/src/utils/talkerUtils.ts +14 -2
  322. package/dist/src/utils/errors.d.ts +0 -25
  323. package/dist/src/utils/errors.d.ts.map +0 -1
  324. package/dist/src/utils/errors.js +0 -43
  325. package/dist/src/utils/errors.js.map +0 -1
  326. package/dist/src/utils/pythonRunner.d.ts +0 -27
  327. package/dist/src/utils/pythonRunner.d.ts.map +0 -1
  328. package/dist/src/utils/pythonRunner.js +0 -62
  329. package/dist/src/utils/pythonRunner.js.map +0 -1
  330. package/src/utils/errors.ts +0 -42
  331. 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()