weflow-cli 1.6.4 → 1.8.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 (205) hide show
  1. package/ARCHITECTURE.md +3 -2
  2. package/CHANGELOG.md +1966 -0
  3. package/OPERATIONS.md +808 -0
  4. package/README.en.md +93 -7
  5. package/README.md +31 -6
  6. package/bin/weflow-cli.ts +1245 -26
  7. package/dist/bin/weflow-cli.js +1349 -72
  8. package/dist/bin/weflow-cli.js.map +1 -1
  9. package/dist/mcp-server/index.js +39 -13
  10. package/dist/mcp-server/index.js.map +1 -1
  11. package/dist/src/core/appMsgFormat.d.ts +37 -0
  12. package/dist/src/core/appMsgFormat.d.ts.map +1 -0
  13. package/dist/src/core/appMsgFormat.js +106 -0
  14. package/dist/src/core/appMsgFormat.js.map +1 -0
  15. package/dist/src/core/ntCore.d.ts +43 -0
  16. package/dist/src/core/ntCore.d.ts.map +1 -1
  17. package/dist/src/core/ntCore.js +31 -0
  18. package/dist/src/core/ntCore.js.map +1 -1
  19. package/dist/src/core/sqlcipherCore.d.ts +0 -12
  20. package/dist/src/core/sqlcipherCore.d.ts.map +1 -1
  21. package/dist/src/core/sqlcipherCore.js +5 -64
  22. package/dist/src/core/sqlcipherCore.js.map +1 -1
  23. package/dist/src/core/wcdbCore.d.ts +1 -1
  24. package/dist/src/core/wcdbCore.d.ts.map +1 -1
  25. package/dist/src/core/wcdbCore.js +5 -1
  26. package/dist/src/core/wcdbCore.js.map +1 -1
  27. package/dist/src/panel/client.d.ts +25 -0
  28. package/dist/src/panel/client.d.ts.map +1 -0
  29. package/dist/src/panel/client.js +34 -0
  30. package/dist/src/panel/client.js.map +1 -0
  31. package/dist/src/panel/endpoint.d.ts +45 -0
  32. package/dist/src/panel/endpoint.d.ts.map +1 -0
  33. package/dist/src/panel/endpoint.js +132 -0
  34. package/dist/src/panel/endpoint.js.map +1 -0
  35. package/dist/src/panel/launch.d.ts +50 -0
  36. package/dist/src/panel/launch.d.ts.map +1 -0
  37. package/dist/src/panel/launch.js +74 -0
  38. package/dist/src/panel/launch.js.map +1 -0
  39. package/dist/src/panel/server.d.ts +23 -0
  40. package/dist/src/panel/server.d.ts.map +1 -0
  41. package/dist/src/panel/server.js +413 -0
  42. package/dist/src/panel/server.js.map +1 -0
  43. package/dist/src/panel/userId.d.ts +37 -0
  44. package/dist/src/panel/userId.d.ts.map +1 -0
  45. package/dist/src/panel/userId.js +56 -0
  46. package/dist/src/panel/userId.js.map +1 -0
  47. package/dist/src/services/assistantDaemon.d.ts +20 -3
  48. package/dist/src/services/assistantDaemon.d.ts.map +1 -1
  49. package/dist/src/services/assistantDaemon.js +46 -9
  50. package/dist/src/services/assistantDaemon.js.map +1 -1
  51. package/dist/src/services/assistantEval.d.ts +141 -0
  52. package/dist/src/services/assistantEval.d.ts.map +1 -0
  53. package/dist/src/services/assistantEval.js +497 -0
  54. package/dist/src/services/assistantEval.js.map +1 -0
  55. package/dist/src/services/assistantMemory.d.ts +106 -4
  56. package/dist/src/services/assistantMemory.d.ts.map +1 -1
  57. package/dist/src/services/assistantMemory.js +396 -61
  58. package/dist/src/services/assistantMemory.js.map +1 -1
  59. package/dist/src/services/assistantPrivacy.d.ts +15 -2
  60. package/dist/src/services/assistantPrivacy.d.ts.map +1 -1
  61. package/dist/src/services/assistantPrivacy.js +18 -4
  62. package/dist/src/services/assistantPrivacy.js.map +1 -1
  63. package/dist/src/services/assistantRouter.d.ts +41 -0
  64. package/dist/src/services/assistantRouter.d.ts.map +1 -0
  65. package/dist/src/services/assistantRouter.js +151 -0
  66. package/dist/src/services/assistantRouter.js.map +1 -0
  67. package/dist/src/services/assistantService.d.ts +209 -3
  68. package/dist/src/services/assistantService.d.ts.map +1 -1
  69. package/dist/src/services/assistantService.js +590 -75
  70. package/dist/src/services/assistantService.js.map +1 -1
  71. package/dist/src/services/assistantTools.d.ts +205 -1
  72. package/dist/src/services/assistantTools.d.ts.map +1 -1
  73. package/dist/src/services/assistantTools.js +1089 -58
  74. package/dist/src/services/assistantTools.js.map +1 -1
  75. package/dist/src/services/assistantTrace.d.ts +47 -0
  76. package/dist/src/services/assistantTrace.d.ts.map +1 -0
  77. package/dist/src/services/assistantTrace.js +150 -0
  78. package/dist/src/services/assistantTrace.js.map +1 -0
  79. package/dist/src/services/chatService.d.ts +13 -0
  80. package/dist/src/services/chatService.d.ts.map +1 -1
  81. package/dist/src/services/chatService.js +23 -0
  82. package/dist/src/services/chatService.js.map +1 -1
  83. package/dist/src/services/configService.d.ts +9 -0
  84. package/dist/src/services/configService.d.ts.map +1 -1
  85. package/dist/src/services/configService.js +15 -8
  86. package/dist/src/services/configService.js.map +1 -1
  87. package/dist/src/services/messageQuery.d.ts +35 -0
  88. package/dist/src/services/messageQuery.d.ts.map +1 -1
  89. package/dist/src/services/messageQuery.js +61 -0
  90. package/dist/src/services/messageQuery.js.map +1 -1
  91. package/dist/src/services/pythonBridge.d.ts +41 -0
  92. package/dist/src/services/pythonBridge.d.ts.map +1 -0
  93. package/dist/src/services/pythonBridge.js +119 -0
  94. package/dist/src/services/pythonBridge.js.map +1 -0
  95. package/dist/src/services/syncService.d.ts +127 -0
  96. package/dist/src/services/syncService.d.ts.map +1 -0
  97. package/dist/src/services/syncService.js +263 -0
  98. package/dist/src/services/syncService.js.map +1 -0
  99. package/dist/src/services/syncState.d.ts +113 -0
  100. package/dist/src/services/syncState.d.ts.map +1 -0
  101. package/dist/src/services/syncState.js +214 -0
  102. package/dist/src/services/syncState.js.map +1 -0
  103. package/dist/src/services/wechatMessageService.d.ts +25 -0
  104. package/dist/src/services/wechatMessageService.d.ts.map +1 -1
  105. package/dist/src/services/wechatMessageService.js +69 -7
  106. package/dist/src/services/wechatMessageService.js.map +1 -1
  107. package/dist/src/utils/atomicWrite.d.ts +4 -0
  108. package/dist/src/utils/atomicWrite.d.ts.map +1 -0
  109. package/dist/src/utils/atomicWrite.js +60 -0
  110. package/dist/src/utils/atomicWrite.js.map +1 -0
  111. package/dist/src/utils/dateRange.d.ts +15 -0
  112. package/dist/src/utils/dateRange.d.ts.map +1 -1
  113. package/dist/src/utils/dateRange.js +47 -0
  114. package/dist/src/utils/dateRange.js.map +1 -1
  115. package/dist/src/utils/text.d.ts +18 -0
  116. package/dist/src/utils/text.d.ts.map +1 -0
  117. package/dist/src/utils/text.js +20 -0
  118. package/dist/src/utils/text.js.map +1 -0
  119. package/docs/AI_INTERFACE.md +2 -0
  120. package/docs/DECISIONS.md +1484 -20
  121. package/docs/EXTENDING.md +187 -0
  122. package/docs/FUNCTIONAL-IMPROVEMENT-SPEC.md +338 -0
  123. package/docs/JEV/345/272/224/347/224/250/346/226/275/345/267/245/346/226/207/346/241/243.md +310 -0
  124. package/docs/MCP.md +23 -4
  125. package/docs/PROJECT_STATE.md +299 -96
  126. package/docs/SETUP.md +22 -0
  127. package/docs/SYNC_CONTRACT.md +180 -0
  128. package/mcp-server/index.ts +681 -657
  129. package/package.json +84 -83
  130. package/resources/panel/ball-position.cjs +153 -0
  131. package/resources/panel/index.html +46 -0
  132. package/resources/panel/main.cjs +447 -0
  133. package/resources/panel/mascot-focus.png +0 -0
  134. package/resources/panel/mascot-happy.png +0 -0
  135. package/resources/panel/mascot-sorry.png +0 -0
  136. package/resources/panel/mascot-tired.png +0 -0
  137. package/resources/panel/mascot.png +0 -0
  138. package/resources/panel/package.json +7 -0
  139. package/resources/panel/panel.css +407 -0
  140. package/resources/panel/preload.cjs +72 -0
  141. package/resources/panel/quick-menu.cjs +197 -0
  142. package/resources/panel/renderer.js +441 -0
  143. package/resources/panel/tray-menu.cjs +40 -0
  144. package/resources/panel/tray.png +0 -0
  145. package/scripts/_utils.py +403 -54
  146. package/scripts/annual_report.py +4 -2
  147. package/scripts/article_notes.py +423 -0
  148. package/scripts/backfill_articles.py +438 -0
  149. package/scripts/biz_daily.py +590 -105
  150. package/scripts/chat_notes.py +470 -0
  151. package/scripts/classify_daily.py +10 -18
  152. package/scripts/compile_wiki.py +1059 -46
  153. package/scripts/create_reading_notes.py +199 -14
  154. package/scripts/decide.py +253 -0
  155. package/scripts/draft_reply.py +671 -0
  156. package/scripts/export_chat_html.py +212 -46
  157. package/scripts/extract_todos.py +31 -5
  158. package/scripts/fav_notes.py +318 -0
  159. package/scripts/fix_topics.py +2 -1
  160. package/scripts/generate_ai_report.py +214 -9
  161. package/scripts/generate_html.py +18 -3
  162. package/scripts/generate_review.py +2 -2
  163. package/scripts/jev_client.py +294 -0
  164. package/scripts/jev_probe.py +440 -0
  165. package/scripts/nt_common.py +82 -0
  166. package/scripts/nt_decrypt.py +1755 -1352
  167. package/scripts/pipeline.py +27 -2
  168. package/scripts/promote_ideas.py +19 -4
  169. package/scripts/quality_eval.py +707 -0
  170. package/scripts/rag_chat.py +4 -4
  171. package/scripts/read_image.py +187 -0
  172. package/scripts/reply_debt.py +488 -0
  173. package/scripts/route_cards.py +453 -0
  174. package/scripts/semantic_search.py +208 -49
  175. package/scripts/user_notes.py +315 -0
  176. package/scripts/vault_rag.py +13 -7
  177. package/scripts/vault_search.py +21 -4
  178. package/scripts/wiki_lint.py +397 -0
  179. package/src/core/appMsgFormat.ts +117 -0
  180. package/src/core/ntCore.ts +67 -0
  181. package/src/core/sqlcipherCore.ts +5 -61
  182. package/src/core/wcdbCore.ts +6 -2
  183. package/src/panel/client.ts +49 -0
  184. package/src/panel/endpoint.ts +144 -0
  185. package/src/panel/launch.ts +101 -0
  186. package/src/panel/server.ts +424 -0
  187. package/src/panel/userId.ts +72 -0
  188. package/src/services/assistantDaemon.ts +57 -9
  189. package/src/services/assistantEval.ts +611 -0
  190. package/src/services/assistantMemory.ts +413 -57
  191. package/src/services/assistantPrivacy.ts +18 -4
  192. package/src/services/assistantRouter.ts +191 -0
  193. package/src/services/assistantService.ts +671 -74
  194. package/src/services/assistantTools.ts +1118 -57
  195. package/src/services/assistantTrace.ts +175 -0
  196. package/src/services/chatService.ts +30 -0
  197. package/src/services/configService.ts +403 -385
  198. package/src/services/messageQuery.ts +97 -0
  199. package/src/services/pythonBridge.ts +139 -0
  200. package/src/services/syncService.ts +363 -0
  201. package/src/services/syncState.ts +275 -0
  202. package/src/services/wechatMessageService.ts +73 -7
  203. package/src/utils/atomicWrite.ts +56 -0
  204. package/src/utils/dateRange.ts +46 -0
  205. package/src/utils/text.ts +20 -0
@@ -0,0 +1,191 @@
1
+ /**
2
+ * 单轮快路径的路由(D-035)。
3
+ *
4
+ * ReAct 循环对"从本地数据答一句"这类问题要两次往返:第一轮挑工具与参数,第二轮拿结果组织
5
+ * 回答。这里在循环之前先用一次判断层调用把 `{要不要工具, 哪个能力}` 定下来,执行掉那一个
6
+ * 工具,于是循环的第一轮就已经看得到结果——**两次往返变一次**。
7
+ *
8
+ * 三条边界,都是刻意的:
9
+ *
10
+ * 1. **只路由参数封闭或为空的工具**。"查我和某某的聊天"里的联系人、"搜收藏里的关键词"里的
11
+ * 关键词都是自由文本,判断层给不出来(它只能从封闭集合里选)。硬拿用户整句话当参数,
12
+ * 正好制造 D-035 点名的那个失败模式:**工具挑错,模型拿着一份不相关的结果自信地作答**。
13
+ * 所以能力表里只有 6 个工具、9 个"能力",其余一律回退到循环。
14
+ * 2. **拿不准就回退**。回退路径必须与今天逐字段一致(有测试断言这一点),而不是"一个更差的
15
+ * 新兜底"。
16
+ * 3. **判断走本机既有的 `scripts/decide.py`**,不在 TS 里再写一个判断层客户端——同一份契约
17
+ * 两份实现,这个仓库已经被咬过(`noul` 被当成布尔的教训)。
18
+ *
19
+ * 隐私:出境的是**用户这条消息本身**加一份固定的能力表说明。消息本来就会发给配置的 LLM
20
+ * (生成回答时),所以这不是新的出境类别;但这里的 state **不含**历史对话与任何本地数据。
21
+ */
22
+ import { runPythonJson } from './pythonBridge.js'
23
+
24
+ export type FastRouteMode = 'off' | 'log' | 'on'
25
+
26
+ /** 能力 = 工具 + 一组固定参数。名字要能在日志与审计里一眼看懂 */
27
+ export interface RouteCapability {
28
+ name: string
29
+ tool: string
30
+ args: Record<string, unknown>
31
+ /** 写进 criteria 的判据:**同时说明它假定了什么查法**(参数表就藏在这句话里) */
32
+ when: string
33
+ }
34
+
35
+ export const NO_CAPABILITY = 'none'
36
+
37
+ export const FAST_ROUTE_CAPABILITIES: RouteCapability[] = [
38
+ { name: 'list_sessions', tool: 'list_sessions', args: {},
39
+ when: '用户想知道最近在和谁聊天、有哪些会话' },
40
+ { name: 'get_stats', tool: 'get_stats', args: {},
41
+ when: '用户问本机数据的统计概览(会话数、收藏总数)' },
42
+ { name: 'get_daily_report', tool: 'get_daily_report', args: {},
43
+ when: '用户问今天或最近公众号推了哪些文章、日报里有什么' },
44
+ { name: 'sns_timeline', tool: 'get_sns', args: { mode: 'timeline' },
45
+ when: '用户问朋友圈最近有什么动态' },
46
+ { name: 'sns_stats', tool: 'get_sns', args: { mode: 'stats' },
47
+ when: '用户问朋友圈的统计(发了多少、多少人发)' },
48
+ { name: 'weread_shelf', tool: 'get_weread', args: { mode: 'shelf' },
49
+ when: '用户问自己在读什么书、书架有什么' },
50
+ { name: 'weread_notebooks', tool: 'get_weread', args: { mode: 'notebooks' },
51
+ when: '用户问自己的读书笔记' },
52
+ { name: 'todos_pending', tool: 'get_todos', args: { status: 'pending' },
53
+ when: '用户问有什么待办、要做的事' },
54
+ { name: 'todos_done', tool: 'get_todos', args: { status: 'done' },
55
+ when: '用户问已经完成的事' },
56
+ ]
57
+
58
+ /** 两次概率都过线才算路由成功;改这两个数等于改行为,测试会盯着 */
59
+ export const MIN_NEEDS_TOOL = 0.5
60
+ export const MIN_CONFIDENCE = 0.6
61
+
62
+ export function buildRouteRequest(message: string, capabilities = FAST_ROUTE_CAPABILITIES): unknown {
63
+ const criteria: Record<string, string> = {}
64
+ for (const capability of capabilities) criteria[capability.name] = capability.when
65
+ criteria[NO_CAPABILITY] =
66
+ '上面那些都不对:要么不需要查本机数据(闲聊、常识、写作、翻译、先问清楚),'
67
+ + '要么需要查但不在这几种查法里(例如要点名某个人、某个关键词,而上面每一项都没有这个参数)'
68
+
69
+ return {
70
+ state: `用户发来的消息:${message}`,
71
+ questions: {
72
+ needs_local_data: {
73
+ type: 'noul',
74
+ instructions: '要回答这条消息,是否必须去查本机保存的数据(聊天记录、朋友圈、'
75
+ + '读书数据、待办、公众号日报)?仅凭常识或对话本身就能回答的不算。',
76
+ },
77
+ capability: {
78
+ type: 'choice',
79
+ instructions: '假设这条消息必须查本机数据:要查的是哪一项?每一项都写明了它假定的查法;'
80
+ + '拿不准、或消息还需要先问清楚,就选 ' + NO_CAPABILITY + '。',
81
+ criteria,
82
+ },
83
+ },
84
+ }
85
+ }
86
+
87
+ export interface RouteDecision {
88
+ /** 定下来的能力;null 表示回退到正常循环 */
89
+ capability: RouteCapability | null
90
+ needsTool: number
91
+ confidence: number
92
+ /** 实际服务我们的判断模型版本(来自 decide.py 的返回),落进日志 */
93
+ model: string
94
+ /** 为什么路由 / 为什么回退——日志与审计里要看的就是这句 */
95
+ reason: string
96
+ }
97
+
98
+ interface RouterOptions {
99
+ /** 注入的判断调用(测试用)。默认走本机 decide.py */
100
+ runDecide?: (request: unknown) => Promise<any>
101
+ capabilities?: RouteCapability[]
102
+ minNeedsTool?: number
103
+ minConfidence?: number
104
+ }
105
+
106
+ /** 本机判断层的默认出口:request 从 stdin 进,答案从 stdout 出,路径里没有密钥。
107
+ *
108
+ * 走 pythonBridge(唯一的脚本调用入口)——此前这里自己 spawn 了一遍,与 get_todos 那份
109
+ * 各写一套超时与错误处理,正是"同一件事两处实现"的老毛病。
110
+ */
111
+ async function runDecideViaPython(request: unknown): Promise<any> {
112
+ const result = await runPythonJson(
113
+ 'decide.py', ['--request', '-'], { stdin: JSON.stringify(request), timeoutMs: 60_000 })
114
+ if (!result.ok) {
115
+ // 调用方(decideRoute)用抛错来表达"判断层不可用",这里保持那个契约
116
+ throw new Error(`${result.error}${result.stderr ? " · " + result.stderr : ""}`)
117
+ }
118
+ return result.data
119
+ }
120
+
121
+ function asProbability(value: unknown): number | null {
122
+ // `noul` 是**概率浮点**,不是布尔。两种读错都要挡:
123
+ // `Number(true)` 是 1 —— 布尔会被当成"概率 1.0",于是**确定地**路由,比读成否更危险;
124
+ // `Number('')` 是 0 —— 空串会被当成"确定不需要"。
125
+ // 所以只认数字与像数字的字符串,别的一律当"契约变了",由调用方回退。
126
+ if (typeof value === 'number') return Number.isFinite(value) ? value : null
127
+ if (typeof value === 'string' && value.trim() !== '') {
128
+ const parsed = Number(value)
129
+ return Number.isFinite(parsed) ? parsed : null
130
+ }
131
+ return null
132
+ }
133
+
134
+ /**
135
+ * 问一次:这条消息该不该走快路径。
136
+ *
137
+ * **任何不确定都回退**:判断层报错、概率不是数、能力名不认识、`choice` 与概率不一致——
138
+ * 全部返回 `capability: null`,让调用方走原本的循环。回退不是降级路径,它就是今天的行为。
139
+ */
140
+ export async function decideRoute(message: string, options: RouterOptions = {}): Promise<RouteDecision> {
141
+ const capabilities = options.capabilities ?? FAST_ROUTE_CAPABILITIES
142
+ const minNeedsTool = options.minNeedsTool ?? MIN_NEEDS_TOOL
143
+ const minConfidence = options.minConfidence ?? MIN_CONFIDENCE
144
+ const run = options.runDecide ?? runDecideViaPython
145
+
146
+ const fallback = (reason: string, needsTool = 0, confidence = 0, model = ''): RouteDecision =>
147
+ ({ capability: null, needsTool, confidence, model, reason })
148
+
149
+ let response: any
150
+ try {
151
+ response = await run(buildRouteRequest(message, capabilities))
152
+ } catch (error: any) {
153
+ return fallback(`判断层不可用: ${error?.message?.slice(0, 120) ?? error}`)
154
+ }
155
+ if (!response || response.success === false) {
156
+ return fallback(`判断层返回失败: ${String(response?.error ?? '未知').slice(0, 120)}`)
157
+ }
158
+
159
+ const answers = response.answers ?? {}
160
+ const model = String(response.model ?? '')
161
+ const needsTool = asProbability(answers.needs_local_data?.noul)
162
+ if (needsTool === null) {
163
+ return fallback('判断层没给出「要不要查本机数据」的概率', 0, 0, model)
164
+ }
165
+ if (needsTool < minNeedsTool) {
166
+ return fallback(`不需要查本机数据 (${needsTool.toFixed(2)})`, needsTool, 0, model)
167
+ }
168
+
169
+ const capabilityAnswer = answers.capability ?? {}
170
+ const picked = String(capabilityAnswer.choice ?? '')
171
+ const confidence = asProbability(capabilityAnswer.confidence) ?? 0
172
+ if (picked === NO_CAPABILITY || !picked) {
173
+ return fallback(`判断层认为不需要工具 (${picked || '空'})`, needsTool, confidence, model)
174
+ }
175
+ const capability = capabilities.find(item => item.name === picked)
176
+ if (!capability) {
177
+ // 能力表是封闭的:出现陌生名字说明契约变了,回退而不是猜
178
+ return fallback(`判断层给了一个不在能力表里的名字: ${picked}`, needsTool, confidence, model)
179
+ }
180
+ if (confidence < minConfidence) {
181
+ return fallback(`路由置信度不足 (${confidence.toFixed(2)} < ${minConfidence})`, needsTool, confidence, model)
182
+ }
183
+ return {
184
+ capability,
185
+ needsTool,
186
+ confidence,
187
+ model,
188
+ reason: `路由到 ${capability.name}(${capability.tool},needs_tool=${needsTool.toFixed(2)},`
189
+ + `confidence=${confidence.toFixed(2)})`,
190
+ }
191
+ }