weflow-cli 1.7.0 → 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 (194) hide show
  1. package/ARCHITECTURE.md +3 -2
  2. package/CHANGELOG.md +1949 -1
  3. package/OPERATIONS.md +774 -1
  4. package/README.en.md +93 -7
  5. package/README.md +31 -6
  6. package/bin/weflow-cli.ts +934 -27
  7. package/dist/bin/weflow-cli.js +952 -27
  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 +19 -2
  16. package/dist/src/core/ntCore.d.ts.map +1 -1
  17. package/dist/src/core/ntCore.js +11 -1
  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 +1 -1
  80. package/dist/src/services/chatService.d.ts.map +1 -1
  81. package/dist/src/services/chatService.js +5 -2
  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/pythonBridge.d.ts +41 -0
  88. package/dist/src/services/pythonBridge.d.ts.map +1 -0
  89. package/dist/src/services/pythonBridge.js +119 -0
  90. package/dist/src/services/pythonBridge.js.map +1 -0
  91. package/dist/src/services/syncService.d.ts +8 -2
  92. package/dist/src/services/syncService.d.ts.map +1 -1
  93. package/dist/src/services/syncService.js +26 -7
  94. package/dist/src/services/syncService.js.map +1 -1
  95. package/dist/src/services/wechatMessageService.d.ts +25 -0
  96. package/dist/src/services/wechatMessageService.d.ts.map +1 -1
  97. package/dist/src/services/wechatMessageService.js +69 -7
  98. package/dist/src/services/wechatMessageService.js.map +1 -1
  99. package/dist/src/utils/atomicWrite.d.ts +4 -0
  100. package/dist/src/utils/atomicWrite.d.ts.map +1 -0
  101. package/dist/src/utils/atomicWrite.js +60 -0
  102. package/dist/src/utils/atomicWrite.js.map +1 -0
  103. package/dist/src/utils/dateRange.d.ts +15 -0
  104. package/dist/src/utils/dateRange.d.ts.map +1 -1
  105. package/dist/src/utils/dateRange.js +47 -0
  106. package/dist/src/utils/dateRange.js.map +1 -1
  107. package/dist/src/utils/text.d.ts +18 -0
  108. package/dist/src/utils/text.d.ts.map +1 -0
  109. package/dist/src/utils/text.js +20 -0
  110. package/dist/src/utils/text.js.map +1 -0
  111. package/docs/AI_INTERFACE.md +2 -0
  112. package/docs/DECISIONS.md +1424 -0
  113. package/docs/EXTENDING.md +187 -0
  114. package/docs/JEV/345/272/224/347/224/250/346/226/275/345/267/245/346/226/207/346/241/243.md +310 -0
  115. package/docs/MCP.md +23 -4
  116. package/docs/PROJECT_STATE.md +299 -98
  117. package/docs/SETUP.md +22 -0
  118. package/docs/SYNC_CONTRACT.md +31 -3
  119. package/mcp-server/index.ts +681 -657
  120. package/package.json +84 -83
  121. package/resources/panel/ball-position.cjs +153 -0
  122. package/resources/panel/index.html +46 -0
  123. package/resources/panel/main.cjs +447 -0
  124. package/resources/panel/mascot-focus.png +0 -0
  125. package/resources/panel/mascot-happy.png +0 -0
  126. package/resources/panel/mascot-sorry.png +0 -0
  127. package/resources/panel/mascot-tired.png +0 -0
  128. package/resources/panel/mascot.png +0 -0
  129. package/resources/panel/package.json +7 -0
  130. package/resources/panel/panel.css +407 -0
  131. package/resources/panel/preload.cjs +72 -0
  132. package/resources/panel/quick-menu.cjs +197 -0
  133. package/resources/panel/renderer.js +441 -0
  134. package/resources/panel/tray-menu.cjs +40 -0
  135. package/resources/panel/tray.png +0 -0
  136. package/scripts/_utils.py +403 -54
  137. package/scripts/annual_report.py +4 -2
  138. package/scripts/article_notes.py +423 -0
  139. package/scripts/backfill_articles.py +438 -0
  140. package/scripts/biz_daily.py +590 -105
  141. package/scripts/chat_notes.py +470 -0
  142. package/scripts/classify_daily.py +10 -18
  143. package/scripts/compile_wiki.py +1059 -46
  144. package/scripts/create_reading_notes.py +199 -14
  145. package/scripts/decide.py +253 -0
  146. package/scripts/draft_reply.py +671 -0
  147. package/scripts/export_chat_html.py +35 -33
  148. package/scripts/extract_todos.py +31 -5
  149. package/scripts/fav_notes.py +318 -0
  150. package/scripts/fix_topics.py +2 -1
  151. package/scripts/generate_ai_report.py +214 -9
  152. package/scripts/generate_html.py +18 -3
  153. package/scripts/generate_review.py +2 -2
  154. package/scripts/jev_client.py +294 -0
  155. package/scripts/jev_probe.py +440 -0
  156. package/scripts/nt_common.py +82 -0
  157. package/scripts/nt_decrypt.py +1755 -1460
  158. package/scripts/pipeline.py +27 -2
  159. package/scripts/promote_ideas.py +19 -4
  160. package/scripts/quality_eval.py +707 -0
  161. package/scripts/rag_chat.py +4 -4
  162. package/scripts/read_image.py +187 -0
  163. package/scripts/reply_debt.py +488 -0
  164. package/scripts/route_cards.py +453 -0
  165. package/scripts/semantic_search.py +208 -49
  166. package/scripts/user_notes.py +315 -0
  167. package/scripts/vault_rag.py +13 -7
  168. package/scripts/vault_search.py +21 -4
  169. package/scripts/wiki_lint.py +397 -0
  170. package/src/core/appMsgFormat.ts +117 -0
  171. package/src/core/ntCore.ts +27 -2
  172. package/src/core/sqlcipherCore.ts +5 -61
  173. package/src/core/wcdbCore.ts +6 -2
  174. package/src/panel/client.ts +49 -0
  175. package/src/panel/endpoint.ts +144 -0
  176. package/src/panel/launch.ts +101 -0
  177. package/src/panel/server.ts +424 -0
  178. package/src/panel/userId.ts +72 -0
  179. package/src/services/assistantDaemon.ts +57 -9
  180. package/src/services/assistantEval.ts +611 -0
  181. package/src/services/assistantMemory.ts +413 -57
  182. package/src/services/assistantPrivacy.ts +18 -4
  183. package/src/services/assistantRouter.ts +191 -0
  184. package/src/services/assistantService.ts +671 -74
  185. package/src/services/assistantTools.ts +1118 -57
  186. package/src/services/assistantTrace.ts +175 -0
  187. package/src/services/chatService.ts +6 -2
  188. package/src/services/configService.ts +403 -385
  189. package/src/services/pythonBridge.ts +139 -0
  190. package/src/services/syncService.ts +37 -9
  191. package/src/services/wechatMessageService.ts +73 -7
  192. package/src/utils/atomicWrite.ts +56 -0
  193. package/src/utils/dateRange.ts +46 -0
  194. package/src/utils/text.ts +20 -0
@@ -0,0 +1,175 @@
1
+ /**
2
+ * 助手一轮的**决策轨迹**:它判断了什么、调了哪个工具、调了几轮、为什么停下。
3
+ *
4
+ * 为什么要有:助手此前对外只吐一句答复,中间过程全在审计里散成一行行事件
5
+ * (`CLOUD_CALL` / `TOOL:x` / `TURN_DONE tools=N`)——`TURN_DONE tools=5` 只告诉你有 5 次
6
+ * 工具调用,不告诉你是哪 5 次、按什么顺序、每次带什么参数。排查"它为什么答成这样"时,
7
+ * 缺的正是这一层。
8
+ *
9
+ * ## 与审计的分工(别混)
10
+ *
11
+ * - **审计**(`assistant_audit.log`):只记事件与字节量,**绝不记内容**,且是出境记录。
12
+ * - **轨迹**(`assistant_trace.jsonl`):记这一步是**怎么走的**,包括工具参数的摘要——
13
+ * 所以它是本地排查用的,不是给第三方看的。参数摘要**过一遍 `privacyGate.redact`**,
14
+ * 值截断,和别处的出境纪律一致。
15
+ *
16
+ * ## 思维链
17
+ *
18
+ * 轨迹里的 `reasoning` 是模型**真返回**的推理内容(OpenAI 兼容接口的 `reasoning_content`)。
19
+ * 当前默认模型 `deepseek-chat` 不返回它(那是 `deepseek-reasoner` 一类模型的行为),
20
+ * 所以这个字段平时是空的——**空就是空,不假装有**。`reasoningChars` 会如实记 0。
21
+ */
22
+ import { appendFileSync, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'
23
+ import { join } from 'node:path'
24
+ import { homedir } from 'node:os'
25
+ import { privacyGate } from './assistantPrivacy.js'
26
+
27
+ const TRACE_FILE = join(homedir(), '.weflow-cli', 'assistant_trace.jsonl')
28
+ /** 单条记录里推理内容最多留多少字(它是模型的独白,不是给用户看的东西) */
29
+ const REASONING_KEEP = 800
30
+ /** 单个参数值最多留多少字 */
31
+ const ARG_VALUE_KEEP = 40
32
+ /** 文件超过这个大小就裁到最近 `TRACE_KEEP` 条 */
33
+ const TRACE_MAX_BYTES = 512 * 1024
34
+ const TRACE_KEEP = 200
35
+
36
+ export type StopReason = 'answered' | 'rounds-exhausted' | 'llm-error' | 'builtin' | 'denied'
37
+
38
+ export interface ToolStep {
39
+ kind: 'tool'
40
+ name: string
41
+ /** 参数摘要(已脱敏、已截断) */
42
+ args: string
43
+ bytes: number
44
+ /** 这次**有没有给出内容**。判据与边界见 `assistantTools.producedContent` */
45
+ produced: boolean
46
+ }
47
+
48
+ export interface NoteStep {
49
+ kind: 'route' | 'round' | 'note'
50
+ detail: string
51
+ }
52
+
53
+ export type TraceStep = ToolStep | NoteStep
54
+
55
+ export interface TurnTrace {
56
+ at: string
57
+ /** 会话/用户 id。**只留在本地文件里**,微信里那条 `轨迹` 不打印它 */
58
+ userId: string
59
+ questionChars: number
60
+ steps: TraceStep[]
61
+ rounds: number
62
+ toolCalls: number
63
+ /** 模型真返回的推理内容;当前默认模型不返回,所以通常是空串 */
64
+ reasoning: string
65
+ reasoningChars: number
66
+ answerChars: number
67
+ stop: StopReason
68
+ elapsedMs: number
69
+ error?: string
70
+ }
71
+
72
+ /** 工具参数的摘要:`contact=甲, limit=20`。过脱敏、值截断。 */
73
+ export function summarizeArgs(args: Record<string, unknown>): string {
74
+ const parts: string[] = []
75
+ for (const [key, value] of Object.entries(args ?? {})) {
76
+ let text: string
77
+ if (value === null || value === undefined) text = String(value)
78
+ else if (typeof value === 'object') text = Array.isArray(value) ? `[${value.length} 项]` : '{…}'
79
+ else text = String(value)
80
+ if (text.length > ARG_VALUE_KEEP) text = text.slice(0, ARG_VALUE_KEEP) + '…'
81
+ parts.push(`${key}=${text}`)
82
+ }
83
+ const joined = parts.join(', ')
84
+ return privacyGate.redact(joined).safe
85
+ }
86
+
87
+ function trimIfLarge(): void {
88
+ try {
89
+ if (!existsSync(TRACE_FILE) || statSync(TRACE_FILE).size <= TRACE_MAX_BYTES) return
90
+ const lines = readFileSync(TRACE_FILE, 'utf8').split('\n').filter(Boolean)
91
+ writeFileSync(TRACE_FILE, lines.slice(-TRACE_KEEP).join('\n') + '\n', 'utf8')
92
+ } catch { /* 裁剪失败不该影响记录 */ }
93
+ }
94
+
95
+ /** 记一轮。失败不抛——排查用的东西不该把对话弄挂。 */
96
+ export function recordTurn(trace: TurnTrace): void {
97
+ try {
98
+ // 目录要先建:新机器上 `~/.weflow-cli` 可能还不存在,而 `appendFileSync` 会抛 ENOENT——
99
+ // 被下面那个 catch 吞掉,就成了"轨迹静默地永远不落盘"(审计那边一开始就有这一步,
100
+ // 轨迹漏了;写这条测试时被自己抓到)。
101
+ const dir = join(homedir(), '.weflow-cli')
102
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true })
103
+ trimIfLarge()
104
+ appendFileSync(TRACE_FILE, JSON.stringify(trace, null, 0) + '\n', 'utf8')
105
+ } catch { /* 记录失败不阻断 */ }
106
+ }
107
+
108
+ /** 读最近 `n` 轮(新→旧)。读不出来就给空数组,不抛。 */
109
+ export function readTurns(n = 5): TurnTrace[] {
110
+ try {
111
+ const lines = readFileSync(TRACE_FILE, 'utf8').split('\n').filter(Boolean)
112
+ return lines.slice(-n).map(line => {
113
+ try { return JSON.parse(line) as TurnTrace } catch { return null }
114
+ }).filter(Boolean).reverse() as TurnTrace[]
115
+ } catch {
116
+ return []
117
+ }
118
+ }
119
+
120
+ export function traceFile(): string {
121
+ return TRACE_FILE
122
+ }
123
+
124
+ /** 一轮的推理内容该留多少。截断时留个记号,别让"截断"读起来像"说完了"。 */
125
+ export function clipReasoning(text: string): string {
126
+ const trimmed = (text ?? '').trim()
127
+ return trimmed.length <= REASONING_KEEP ? trimmed : trimmed.slice(0, REASONING_KEEP) + '…'
128
+ }
129
+
130
+ const STEP_LABEL: Record<string, string> = {
131
+ route: '判断层', round: '模型往返', note: '说明', tool: '工具',
132
+ }
133
+
134
+ /** 给终端看的多行描述。纯函数,好测。 */
135
+ export function describeTurn(trace: TurnTrace): string[] {
136
+ const lines: string[] = []
137
+ const stamp = (trace.at || '').replace('T', ' ').slice(0, 19)
138
+ lines.push(`${stamp} ${trace.elapsedMs}ms 往返 ${trace.rounds} 次 · 工具 ${trace.toolCalls} 次 · 结束于「${trace.stop}」`)
139
+ for (const step of trace.steps) {
140
+ if (step.kind === 'tool') {
141
+ const mark = step.produced ? '' : ' (无内容)'
142
+ lines.push(` · ${STEP_LABEL.tool} ${step.name}(${step.args}) → ${step.bytes} 字节${mark}`)
143
+ } else {
144
+ lines.push(` · ${STEP_LABEL[step.kind] ?? step.kind}: ${step.detail}`)
145
+ }
146
+ }
147
+ if (trace.reasoningChars) {
148
+ lines.push(` · 推理 ${trace.reasoningChars} 字${trace.reasoning ? ':' : '(模型这次没有返回内容)'}`)
149
+ for (const line of (trace.reasoning || '').split('\n')) lines.push(` ${line}`)
150
+ } else {
151
+ lines.push(' · 推理: 无(当前模型不返回 reasoning_content)')
152
+ }
153
+ if (trace.error) lines.push(` · 出错: ${trace.error}`)
154
+ return lines
155
+ }
156
+
157
+ /**
158
+ * 微信里 `轨迹` 那条要短。**不打印 userId**——它是账号标识,没必要出现在聊天里。
159
+ */
160
+ export function describeForChat(trace: TurnTrace | undefined): string {
161
+ if (!trace) return '还没有可看的轨迹:这条之前的记录不在本机(或这是第一条消息)。'
162
+ const lines: string[] = [`上一轮(${(trace.at || '').slice(11, 19)},${trace.elapsedMs}ms,往返 ${trace.rounds} 次)`]
163
+ for (const step of trace.steps) {
164
+ if (step.kind === 'tool') {
165
+ lines.push(`· ${step.name}(${step.args}) → ${step.bytes} 字节${step.produced ? '' : '(无内容)'}`)
166
+ } else {
167
+ lines.push(`· ${step.detail}`)
168
+ }
169
+ }
170
+ lines.push(`· 结束: ${trace.stop}`)
171
+ lines.push(trace.reasoningChars
172
+ ? `· 推理: ${trace.reasoningChars} 字(当前模型${trace.reasoning ? '有返回' : '只报了长度'})`
173
+ : '· 推理: 无(当前模型不返回 reasoning_content)')
174
+ return lines.join('\n')
175
+ }
@@ -251,17 +251,21 @@ export class ChatService {
251
251
  async getMessagesWithShards(
252
252
  talker: string,
253
253
  limit = 0,
254
- offset = 0
254
+ offset = 0,
255
+ fromTime?: number | null
255
256
  ): Promise<{ messages: Message[]; shards?: ShardReport }> {
256
257
  const conn = await this.connect()
257
258
  if (!conn.success) return { messages: [] }
258
259
 
259
260
  if (this.ntCore) {
260
- const result = await this.ntCore.getMessagesWithShards(talker, limit, offset)
261
+ const result = await this.ntCore.getMessagesWithShards(talker, limit, offset, fromTime)
261
262
  if (!result.success || !result.messages) return { messages: [] }
262
263
  return { messages: result.messages, shards: result.shards }
263
264
  }
264
265
 
266
+ // The other backends have no shard report and no range pushdown. They
267
+ // return everything and the caller's own window filter does the rest,
268
+ // which is why a sync over them reports `coverage: 'unverified'`.
265
269
  return { messages: await this.getMessages(talker, limit, offset) }
266
270
  }
267
271