recallnest 2.2.0 → 2.3.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 (249) hide show
  1. package/.env +4 -0
  2. package/CLAUDE.md +1 -1
  3. package/README.md +30 -5
  4. package/README_CN.md +30 -5
  5. package/config.json +55 -0
  6. package/connectors/examples/email-adapter.ts +73 -0
  7. package/connectors/examples/logs-adapter.ts +103 -0
  8. package/connectors/examples/rss-adapter.ts +95 -0
  9. package/logs/daily-recall.error.log +0 -0
  10. package/logs/daily-recall.log +60 -0
  11. package/logs/ingest-2026-04-11.log +110 -0
  12. package/logs/ingest-2026-04-12.log +90 -0
  13. package/logs/ingest-2026-04-13.log +87 -0
  14. package/logs/launchagent-stderr.log +0 -0
  15. package/logs/launchagent-stdout.log +0 -0
  16. package/package.json +1 -1
  17. package/src/cli.ts +30 -0
  18. package/src/connector-types.ts +57 -0
  19. package/src/conversation-importer.ts +25 -1
  20. package/src/data-checkup.ts +31 -1
  21. package/src/doctor.ts +29 -0
  22. package/src/ingest.ts +203 -0
  23. package/src/mcp-server.ts +2 -2
  24. package/src/obsidian-connector.ts +282 -0
  25. package/src/session-schema.ts +2 -2
  26. package/src/source-heartbeat.ts +108 -0
  27. package/.claude-plugin/CLAUDE.md +0 -29
  28. package/.claude-plugin/marketplace.json +0 -18
  29. package/.dockerignore +0 -11
  30. package/.github/workflows/ci.yml +0 -28
  31. package/.mcp.json +0 -9
  32. package/CHANGELOG.md +0 -51
  33. package/DEMO.md +0 -94
  34. package/Dockerfile +0 -20
  35. package/EVAL.md +0 -89
  36. package/FAILURES.md +0 -75
  37. package/OPERATIONS.md +0 -59
  38. package/ROADMAP.md +0 -245
  39. package/SKILL.md +0 -250
  40. package/assets/dashboard.png +0 -0
  41. package/assets/knowledge-graph.png +0 -0
  42. package/assets/recallnest-workbench.png +0 -0
  43. package/assets/screenshots/ui-full.png +0 -0
  44. package/assets/screenshots/ui-overview.png +0 -0
  45. package/assets/screenshots/ui-search.png +0 -0
  46. package/assets/ui/app.js +0 -1031
  47. package/assets/ui/index.html +0 -224
  48. package/assets/ui/styles.css +0 -781
  49. package/assets/wechat-qr.jpg +0 -0
  50. package/bun.lock +0 -337
  51. package/daily-reflections/2026-03-05.md +0 -15
  52. package/daily-reflections/2026-03-06.md +0 -15
  53. package/daily-reflections/2026-03-07.md +0 -7
  54. package/daily-reflections/2026-03-08.md +0 -34
  55. package/daily-reflections/2026-03-09.md +0 -35
  56. package/daily-reflections/2026-03-10.md +0 -36
  57. package/daily-reflections/2026-03-11.md +0 -35
  58. package/daily-reflections/2026-03-12.md +0 -36
  59. package/daily-reflections/2026-03-13.md +0 -35
  60. package/daily-reflections/2026-03-14.md +0 -35
  61. package/daily-reflections/2026-03-15.md +0 -35
  62. package/daily-reflections/2026-03-16.md +0 -41
  63. package/daily-reflections/2026-03-17.md +0 -10
  64. package/daily-reflections/2026-03-18.md +0 -10
  65. package/daily-reflections/2026-03-19.md +0 -10
  66. package/daily-reflections/2026-03-20.md +0 -10
  67. package/daily-reflections/2026-03-21.md +0 -10
  68. package/daily-reflections/2026-03-22.md +0 -10
  69. package/daily-reflections/2026-03-23.md +0 -10
  70. package/daily-reflections/2026-03-24.md +0 -10
  71. package/daily-reflections/2026-03-25.md +0 -32
  72. package/daily-reflections/2026-03-26.md +0 -37
  73. package/daily-reflections/2026-03-27.md +0 -35
  74. package/daily-reflections/2026-03-28.md +0 -35
  75. package/daily-reflections/2026-03-29.md +0 -35
  76. package/daily-reflections/2026-03-30.md +0 -36
  77. package/daily-reflections/2026-03-31.md +0 -35
  78. package/daily-reflections/2026-04-01.md +0 -35
  79. package/daily-reflections/2026-04-02.md +0 -35
  80. package/daily-reflections/2026-04-03.md +0 -37
  81. package/daily-reflections/2026-04-04.md +0 -37
  82. package/daily-reflections/2026-04-05.md +0 -35
  83. package/daily-reflections/2026-04-06.md +0 -36
  84. package/daily-reflections/2026-04-07.md +0 -35
  85. package/daily-reflections/2026-04-08.md +0 -35
  86. package/daily-reflections/2026-04-12.md +0 -35
  87. package/data/alias-map.example.json +0 -22
  88. package/docs/api-reference.md +0 -1291
  89. package/docs/architecture.md +0 -168
  90. package/docs/memory-boundary-contract.md +0 -226
  91. package/docs/memory-categories.md +0 -119
  92. package/docs/pipeline-audit-ultramemory.md +0 -177
  93. package/docs/plans/2026-03-08-query-expansion.md +0 -270
  94. package/docs/plans/2026-03-16-continuity-layer.md +0 -196
  95. package/docs/plans/2026-04-01-recall-boost.md +0 -100
  96. package/docs/plans/mcp-tiering-plan.md +0 -126
  97. package/docs/research/recall-quality-audit-2026-03-22.md +0 -153
  98. package/docs/self-evolution.md +0 -198
  99. package/docs/superpowers/plans/2026-03-19-ingest-pipeline-upgrade.md +0 -782
  100. package/docs/superpowers/plans/2026-04-11-constructive-retrieval-emotion.md +0 -1195
  101. package/docs/superpowers/specs/2026-03-19-ingest-pipeline-upgrade-design.md +0 -77
  102. package/docs/superpowers/specs/2026-03-23-pull-claude-desktop-design.md +0 -95
  103. package/docs/superpowers/specs/2026-04-11-constructive-retrieval-emotion-design.md +0 -398
  104. package/eval/continuity/results-2026-03-16.md +0 -117
  105. package/eval/continuity/results-2026-03-19.md +0 -453
  106. package/eval/continuity/runbook.md +0 -110
  107. package/eval/continuity/seed-cases.md +0 -54
  108. package/eval/reports/2026-03-06-abstract-query-baseline.md +0 -96
  109. package/eval/reports/2026-03-06-aws-ssh-baseline.md +0 -82
  110. package/eval/reports/2026-03-06-baseline.md +0 -82
  111. package/eval/reports/query-expansion.md +0 -138
  112. package/glama.json +0 -6
  113. package/lm +0 -19
  114. package/plan-philosophy-upgrades.md +0 -363
  115. package/plan-product-upgrades.md +0 -155
  116. package/plan-v1.2-distributable.md +0 -105
  117. package/plan.md +0 -140
  118. package/research-memory-evolution.md +0 -440
  119. package/research-rl-agent-memory.md +0 -330
  120. package/scripts/archive-distilled-junk.ts +0 -116
  121. package/scripts/backfill-anchors.ts +0 -130
  122. package/scripts/backfill-l0l1l2.ts +0 -98
  123. package/scripts/blind-scan.ts +0 -588
  124. package/scripts/cleanup-step1-exact-dups.ts +0 -117
  125. package/scripts/cleanup-step2-template-dups.ts +0 -113
  126. package/scripts/cleanup-step3-stale-content.ts +0 -149
  127. package/scripts/cleanup-step4-orphan-scopes.ts +0 -131
  128. package/scripts/delete-distilled-junk.ts +0 -88
  129. package/scripts/diagnose-vector-search.ts +0 -132
  130. package/scripts/distill-facts.ts +0 -305
  131. package/scripts/health-check.ts +0 -343
  132. package/scripts/incremental-ingest.sh +0 -71
  133. package/scripts/migrate-language.ts +0 -75
  134. package/scripts/mlp-health-check.ts +0 -382
  135. package/scripts/pull-claude-desktop.ts +0 -515
  136. package/scripts/re-ingest-cc.sh +0 -66
  137. package/scripts/rebalance-memory-health.ts +0 -181
  138. package/scripts/run-desktop-ingest.sh +0 -11
  139. package/scripts/start-server.sh +0 -12
  140. package/scripts/verify-emotion-decay.ts +0 -148
  141. package/scripts/viz-dashboard.html +0 -423
  142. package/scripts/viz-export.ts +0 -703
  143. package/src/__tests__/access-tracker-novelty.test.ts +0 -228
  144. package/src/__tests__/activity-counter.test.ts +0 -96
  145. package/src/__tests__/admission-control.test.ts +0 -206
  146. package/src/__tests__/anchor-generator.test.ts +0 -67
  147. package/src/__tests__/auto-consolidation.test.ts +0 -168
  148. package/src/__tests__/auto-recall.test.ts +0 -131
  149. package/src/__tests__/babel-integration.test.ts +0 -139
  150. package/src/__tests__/batch-dedup.test.ts +0 -65
  151. package/src/__tests__/capture-engine.test.ts +0 -1144
  152. package/src/__tests__/capture-heuristic.test.ts +0 -171
  153. package/src/__tests__/cascade-forget.test.ts +0 -210
  154. package/src/__tests__/category-min-scores.test.ts +0 -33
  155. package/src/__tests__/cc8-cc1-essential-context.test.ts +0 -298
  156. package/src/__tests__/circuit-breaker.test.ts +0 -99
  157. package/src/__tests__/cluster-consolidation.test.ts +0 -712
  158. package/src/__tests__/confidence-metadata.test.ts +0 -125
  159. package/src/__tests__/confidence-tracker.test.ts +0 -249
  160. package/src/__tests__/conflict-advisor.test.ts +0 -206
  161. package/src/__tests__/conflict-escalation.test.ts +0 -149
  162. package/src/__tests__/conflict-lifecycle.test.ts +0 -83
  163. package/src/__tests__/conflict-output.test.ts +0 -85
  164. package/src/__tests__/conflict-store.test.ts +0 -374
  165. package/src/__tests__/consolidation-engine.test.ts +0 -181
  166. package/src/__tests__/constructive-retrieval.test.ts +0 -509
  167. package/src/__tests__/context-collapse-renderer.test.ts +0 -214
  168. package/src/__tests__/context-composer-pins.test.ts +0 -64
  169. package/src/__tests__/context-composer-task-selection.test.ts +0 -24
  170. package/src/__tests__/context-reconstructor.test.ts +0 -65
  171. package/src/__tests__/context-renderer.test.ts +0 -91
  172. package/src/__tests__/continuity-eval.test.ts +0 -275
  173. package/src/__tests__/continuity-schema.test.ts +0 -97
  174. package/src/__tests__/conversation-importer.test.ts +0 -692
  175. package/src/__tests__/core-recall-eval.test.ts +0 -235
  176. package/src/__tests__/core-summary.test.ts +0 -109
  177. package/src/__tests__/data-checkup.test.ts +0 -225
  178. package/src/__tests__/decay-exemption.test.ts +0 -84
  179. package/src/__tests__/dedup-actions.test.ts +0 -58
  180. package/src/__tests__/dedup-guard.test.ts +0 -39
  181. package/src/__tests__/deterministic-id.test.ts +0 -39
  182. package/src/__tests__/distill-lock.test.ts +0 -176
  183. package/src/__tests__/doctor.test.ts +0 -303
  184. package/src/__tests__/dream-pipeline.test.ts +0 -232
  185. package/src/__tests__/drill-down.test.ts +0 -108
  186. package/src/__tests__/embedder.test.ts +0 -122
  187. package/src/__tests__/emotion-decay.test.ts +0 -46
  188. package/src/__tests__/emotion-detector.test.ts +0 -56
  189. package/src/__tests__/emotion-phase1-integration.test.ts +0 -153
  190. package/src/__tests__/emotion-retrieval.test.ts +0 -56
  191. package/src/__tests__/entity-resolver.test.ts +0 -58
  192. package/src/__tests__/ethics-layer.test.ts +0 -476
  193. package/src/__tests__/event-segmenter.test.ts +0 -153
  194. package/src/__tests__/feature-flags-integration.test.ts +0 -54
  195. package/src/__tests__/frequency-tracker.test.ts +0 -113
  196. package/src/__tests__/graph-export.test.ts +0 -489
  197. package/src/__tests__/hotness-blend.test.ts +0 -76
  198. package/src/__tests__/ingest.test.ts +0 -360
  199. package/src/__tests__/interference-detector.test.ts +0 -203
  200. package/src/__tests__/kg-extractor.test.ts +0 -184
  201. package/src/__tests__/kg-store.test.ts +0 -198
  202. package/src/__tests__/llm-consolidation.test.ts +0 -226
  203. package/src/__tests__/mcp-efficiency.test.ts +0 -288
  204. package/src/__tests__/memory-boundaries.test.ts +0 -237
  205. package/src/__tests__/memory-evolution-b2-b3-e1.test.ts +0 -243
  206. package/src/__tests__/memory-evolution.test.ts +0 -271
  207. package/src/__tests__/memory-health-rebalance.test.ts +0 -144
  208. package/src/__tests__/memory-lint.test.ts +0 -271
  209. package/src/__tests__/memory-output.test.ts +0 -215
  210. package/src/__tests__/multi-vector.test.ts +0 -242
  211. package/src/__tests__/narrative-architecture.test.ts +0 -456
  212. package/src/__tests__/pending-review.test.ts +0 -77
  213. package/src/__tests__/post-retrieval-filter.test.ts +0 -178
  214. package/src/__tests__/ppr-traversal.test.ts +0 -256
  215. package/src/__tests__/prediction-engine.test.ts +0 -349
  216. package/src/__tests__/predictive-prospective-memory.test.ts +0 -416
  217. package/src/__tests__/preference-guard-smoke.test.ts +0 -211
  218. package/src/__tests__/preference-matcher.test.ts +0 -230
  219. package/src/__tests__/preference-slots.test.ts +0 -205
  220. package/src/__tests__/prospective-memory.test.ts +0 -283
  221. package/src/__tests__/query-entity-detector.test.ts +0 -171
  222. package/src/__tests__/query-expander-alias.test.ts +0 -89
  223. package/src/__tests__/query-expander.test.ts +0 -34
  224. package/src/__tests__/recall-governor.test.ts +0 -227
  225. package/src/__tests__/recall-mode.test.ts +0 -64
  226. package/src/__tests__/result-synthesizer.test.ts +0 -198
  227. package/src/__tests__/resume-context.test.ts +0 -4898
  228. package/src/__tests__/retrieval-trace.test.ts +0 -213
  229. package/src/__tests__/retriever-boundary-weight.test.ts +0 -136
  230. package/src/__tests__/retroactive-boost.test.ts +0 -223
  231. package/src/__tests__/salience-scoring.test.ts +0 -106
  232. package/src/__tests__/scope-inventory.test.ts +0 -200
  233. package/src/__tests__/scope-policy.test.ts +0 -69
  234. package/src/__tests__/session-checkpoint.test.ts +0 -259
  235. package/src/__tests__/session-distiller.test.ts +0 -611
  236. package/src/__tests__/session-gc.test.ts +0 -215
  237. package/src/__tests__/skill-engine.test.ts +0 -546
  238. package/src/__tests__/skill-promotion.test.ts +0 -349
  239. package/src/__tests__/store-scope-audit.test.ts +0 -81
  240. package/src/__tests__/supersede-chain.test.ts +0 -154
  241. package/src/__tests__/temporal-parser.test.ts +0 -241
  242. package/src/__tests__/temporal-validity.test.ts +0 -160
  243. package/src/__tests__/term-registry.test.ts +0 -121
  244. package/src/__tests__/tool-output-compressor.test.ts +0 -133
  245. package/src/__tests__/topic-tag.test.ts +0 -113
  246. package/src/__tests__/trusted-memory.test.ts +0 -828
  247. package/src/__tests__/version-manager.test.ts +0 -213
  248. package/src/__tests__/workflow-observation.test.ts +0 -400
  249. package/src/__tests__/write-verifier.test.ts +0 -122
@@ -1,382 +0,0 @@
1
- /**
2
- * memory-lancedb-pro 通用记忆体检脚本
3
- * 只读分析 LanceDB 数据,不写入任何内容
4
- * 兼容 RecallNest (camelCase) 和 memory-lancedb-pro (snake_case) metadata 格式
5
- *
6
- * 用法:
7
- * bun run scripts/mlp-health-check.ts <lancedb-dir> [bot-name]
8
- *
9
- * 示例:
10
- * bun run scripts/mlp-health-check.ts /tmp/mlp-healthcheck/antigravity/lancedb-pro AntiBot
11
- * bun run scripts/mlp-health-check.ts ./data/lancedb RecallNest
12
- */
13
-
14
- import lancedb from "@lancedb/lancedb";
15
-
16
- const DB_PATH = process.argv[2] || "./data/lancedb";
17
- const BOT_NAME = process.argv[3] || "未命名";
18
- const TABLE_NAME = "memories";
19
-
20
- interface MemoryRow {
21
- id: string;
22
- text: string;
23
- vector: number[];
24
- category: string;
25
- scope: string;
26
- importance: number;
27
- timestamp: number;
28
- metadata?: string;
29
- }
30
-
31
- /** 兼容 camelCase (RecallNest) 和 snake_case (memory-lancedb-pro) */
32
- function getAccessCount(meta: Record<string, any>): number {
33
- return meta.accessCount ?? meta.access_count ?? 0;
34
- }
35
-
36
- function getLastAccessed(meta: Record<string, any>): number {
37
- return meta.lastAccessedAt ?? meta.last_accessed_at ?? 0;
38
- }
39
-
40
- function getTier(meta: Record<string, any>): string {
41
- return meta.tier ?? "unknown";
42
- }
43
-
44
- function getSource(meta: Record<string, any>): string {
45
- return meta.source ?? meta.source_session ?? "";
46
- }
47
-
48
- function cosineSimilarity(a: number[], b: number[]): number {
49
- let dot = 0, normA = 0, normB = 0;
50
- for (let i = 0; i < a.length; i++) {
51
- dot += a[i] * b[i];
52
- normA += a[i] * a[i];
53
- normB += b[i] * b[i];
54
- }
55
- return dot / (Math.sqrt(normA) * Math.sqrt(normB));
56
- }
57
-
58
- function formatDate(ts: number): string {
59
- return new Date(ts).toISOString().slice(0, 10);
60
- }
61
-
62
- function percentBar(pct: number, width = 30): string {
63
- const filled = Math.round(pct / 100 * width);
64
- return "█".repeat(filled) + "░".repeat(width - filled);
65
- }
66
-
67
- async function main() {
68
- console.log(`\n🏥 记忆体检报告 — ${BOT_NAME}`);
69
- console.log("=".repeat(60));
70
- console.log(`📅 检查时间: ${new Date().toISOString().slice(0, 19)}`);
71
- console.log(`📂 数据路径: ${DB_PATH}\n`);
72
-
73
- const db = await lancedb.connect(DB_PATH);
74
- const table = await db.openTable(TABLE_NAME);
75
-
76
- // Fetch all rows (without vectors first for speed)
77
- console.log("⏳ 正在读取全量数据...");
78
- const allRows: MemoryRow[] = await table
79
- .query()
80
- .select(["id", "text", "category", "scope", "importance", "timestamp", "metadata"])
81
- .toArray() as any;
82
-
83
- const total = allRows.length;
84
- if (total === 0) {
85
- console.log("⚠️ 记忆库为空,无数据可分析。");
86
- return;
87
- }
88
- console.log(`✅ 读取完成: ${total.toLocaleString()} 条记忆\n`);
89
-
90
- // Parse metadata once
91
- const parsedRows = allRows.map(row => ({
92
- ...row,
93
- meta: row.metadata ? JSON.parse(row.metadata) : {},
94
- }));
95
-
96
- // ============================================
97
- // 1. Category 分布
98
- // ============================================
99
- console.log("📊 1. Category 分布");
100
- console.log("-".repeat(60));
101
- const catMap = new Map<string, number>();
102
- for (const row of parsedRows) {
103
- catMap.set(row.category, (catMap.get(row.category) || 0) + 1);
104
- }
105
- const catSorted = [...catMap.entries()].sort((a, b) => b[1] - a[1]);
106
- for (const [cat, count] of catSorted) {
107
- const pct = (count / total * 100).toFixed(1);
108
- console.log(` ${cat.padEnd(14)} ${count.toString().padStart(6)} (${pct.padStart(5)}%) ${percentBar(parseFloat(pct))}`);
109
- }
110
-
111
- // ============================================
112
- // 2. Tier 分布
113
- // ============================================
114
- console.log("\n📊 2. Tier 分布");
115
- console.log("-".repeat(60));
116
- const tierMap = new Map<string, number>();
117
- for (const row of parsedRows) {
118
- const tier = getTier(row.meta);
119
- tierMap.set(tier, (tierMap.get(tier) || 0) + 1);
120
- }
121
- const tierSorted = [...tierMap.entries()].sort((a, b) => b[1] - a[1]);
122
- for (const [tier, count] of tierSorted) {
123
- const pct = (count / total * 100).toFixed(1);
124
- console.log(` ${tier.padEnd(14)} ${count.toString().padStart(6)} (${pct.padStart(5)}%) ${percentBar(parseFloat(pct))}`);
125
- }
126
-
127
- // ============================================
128
- // 3. 死记忆分析
129
- // ============================================
130
- console.log("\n📊 3. 死记忆分析(accessCount = 0 或无记录)");
131
- console.log("-".repeat(60));
132
- let deadCount = 0;
133
- let aliveCount = 0;
134
- let totalAccess = 0;
135
- let maxAccess = 0;
136
- let maxAccessText = "";
137
- const accessDistribution = new Map<string, number>();
138
-
139
- for (const row of parsedRows) {
140
- const ac = getAccessCount(row.meta);
141
- totalAccess += ac;
142
-
143
- if (ac === 0) deadCount++;
144
- else aliveCount++;
145
-
146
- if (ac > maxAccess) {
147
- maxAccess = ac;
148
- maxAccessText = row.text.slice(0, 80);
149
- }
150
-
151
- let bucket: string;
152
- if (ac === 0) bucket = "0 (死记忆)";
153
- else if (ac <= 2) bucket = "1-2";
154
- else if (ac <= 5) bucket = "3-5";
155
- else if (ac <= 10) bucket = "6-10";
156
- else if (ac <= 50) bucket = "11-50";
157
- else bucket = "50+";
158
- accessDistribution.set(bucket, (accessDistribution.get(bucket) || 0) + 1);
159
- }
160
-
161
- const deadPct = (deadCount / total * 100).toFixed(1);
162
- const alivePct = (aliveCount / total * 100).toFixed(1);
163
- console.log(` 死记忆: ${deadCount.toLocaleString()} / ${total.toLocaleString()} (${deadPct}%)`);
164
- console.log(` 活记忆: ${aliveCount.toLocaleString()} / ${total.toLocaleString()} (${alivePct}%)`);
165
- console.log(` 总访问次: ${totalAccess.toLocaleString()}`);
166
- console.log(` 平均访问: ${(totalAccess / total).toFixed(2)} 次/条`);
167
- if (maxAccess > 0) {
168
- console.log(` 最热记忆: [${maxAccess}次] ${maxAccessText}...`);
169
- }
170
-
171
- console.log("\n 访问次数分布:");
172
- const bucketOrder = ["0 (死记忆)", "1-2", "3-5", "6-10", "11-50", "50+"];
173
- for (const bucket of bucketOrder) {
174
- const count = accessDistribution.get(bucket) || 0;
175
- const pct = (count / total * 100).toFixed(1);
176
- console.log(` ${bucket.padEnd(14)} ${count.toString().padStart(6)} (${pct.padStart(5)}%) ${percentBar(parseFloat(pct))}`);
177
- }
178
-
179
- // ============================================
180
- // 4. Importance 分布
181
- // ============================================
182
- console.log("\n📊 4. Importance 分布");
183
- console.log("-".repeat(60));
184
- const impBuckets = new Map<string, number>();
185
- let impSum = 0;
186
- for (const row of parsedRows) {
187
- const imp = row.importance || 0;
188
- impSum += imp;
189
- let bucket: string;
190
- if (imp < 0.2) bucket = "0.0-0.2 (低)";
191
- else if (imp < 0.4) bucket = "0.2-0.4";
192
- else if (imp < 0.6) bucket = "0.4-0.6 (中)";
193
- else if (imp < 0.8) bucket = "0.6-0.8";
194
- else bucket = "0.8-1.0 (高)";
195
- impBuckets.set(bucket, (impBuckets.get(bucket) || 0) + 1);
196
- }
197
- console.log(` 平均 importance: ${(impSum / total).toFixed(3)}`);
198
- const impOrder = ["0.0-0.2 (低)", "0.2-0.4", "0.4-0.6 (中)", "0.6-0.8", "0.8-1.0 (高)"];
199
- for (const bucket of impOrder) {
200
- const count = impBuckets.get(bucket) || 0;
201
- const pct = (count / total * 100).toFixed(1);
202
- console.log(` ${bucket.padEnd(16)} ${count.toString().padStart(6)} (${pct.padStart(5)}%) ${percentBar(parseFloat(pct))}`);
203
- }
204
-
205
- // ============================================
206
- // 5. Scope 分布
207
- // ============================================
208
- console.log("\n📊 5. Scope 分布");
209
- console.log("-".repeat(60));
210
- const scopeMap = new Map<string, number>();
211
- for (const row of parsedRows) {
212
- const s = row.scope || "(empty)";
213
- scopeMap.set(s, (scopeMap.get(s) || 0) + 1);
214
- }
215
- const scopeSorted = [...scopeMap.entries()].sort((a, b) => b[1] - a[1]);
216
- console.log(` 独立 scope 数: ${scopeMap.size}`);
217
- console.log(" Top 10:");
218
- for (const [scope, count] of scopeSorted.slice(0, 10)) {
219
- const pct = (count / total * 100).toFixed(1);
220
- const label = scope.length > 30 ? scope.slice(0, 27) + "..." : scope;
221
- console.log(` ${label.padEnd(32)} ${count.toString().padStart(6)} (${pct.padStart(5)}%)`);
222
- }
223
-
224
- // ============================================
225
- // 6. 年龄分布
226
- // ============================================
227
- console.log("\n📊 6. 年龄分布");
228
- console.log("-".repeat(60));
229
- const now = Date.now();
230
- const ageBuckets = new Map<string, number>();
231
- let oldest = Infinity, newest = 0;
232
- for (const row of parsedRows) {
233
- const ts = row.timestamp;
234
- if (ts < oldest) oldest = ts;
235
- if (ts > newest) newest = ts;
236
- const ageHours = (now - ts) / (1000 * 60 * 60);
237
- let bucket: string;
238
- if (ageHours < 24) bucket = "< 1 天";
239
- else if (ageHours < 24 * 7) bucket = "1-7 天";
240
- else if (ageHours < 24 * 30) bucket = "7-30 天";
241
- else if (ageHours < 24 * 90) bucket = "30-90 天";
242
- else bucket = "> 90 天";
243
- ageBuckets.set(bucket, (ageBuckets.get(bucket) || 0) + 1);
244
- }
245
- console.log(` 最早: ${formatDate(oldest)}`);
246
- console.log(` 最新: ${formatDate(newest)}`);
247
- const ageOrder = ["< 1 天", "1-7 天", "7-30 天", "30-90 天", "> 90 天"];
248
- for (const bucket of ageOrder) {
249
- const count = ageBuckets.get(bucket) || 0;
250
- const pct = (count / total * 100).toFixed(1);
251
- console.log(` ${bucket.padEnd(12)} ${count.toString().padStart(6)} (${pct.padStart(5)}%) ${percentBar(parseFloat(pct))}`);
252
- }
253
-
254
- // ============================================
255
- // 7. 近似重复检测(采样)
256
- // ============================================
257
- const sampleSize = Math.min(500, total);
258
- console.log(`\n📊 7. 近似重复检测(采样 ${sampleSize} 条,cosine > 0.95)`);
259
- console.log("-".repeat(60));
260
- console.log(" ⏳ 正在读取向量数据(采样)...");
261
-
262
- const sampleRows: MemoryRow[] = await table
263
- .query()
264
- .select(["id", "text", "vector", "category"])
265
- .limit(sampleSize)
266
- .toArray() as any;
267
-
268
- let dupPairs = 0;
269
- const dupExamples: Array<{sim: number, textA: string, textB: string}> = [];
270
-
271
- for (let i = 0; i < sampleRows.length; i++) {
272
- for (let j = i + 1; j < sampleRows.length; j++) {
273
- if (sampleRows[i].vector && sampleRows[j].vector) {
274
- const sim = cosineSimilarity(sampleRows[i].vector, sampleRows[j].vector);
275
- if (sim > 0.95) {
276
- dupPairs++;
277
- if (dupExamples.length < 3) {
278
- dupExamples.push({
279
- sim,
280
- textA: sampleRows[i].text.slice(0, 60),
281
- textB: sampleRows[j].text.slice(0, 60),
282
- });
283
- }
284
- }
285
- }
286
- }
287
- }
288
-
289
- const totalPairs = sampleSize * (sampleSize - 1) / 2;
290
- const dupRate = (dupPairs / totalPairs * 100).toFixed(3);
291
- console.log(` 采样对数: ${totalPairs.toLocaleString()}`);
292
- console.log(` 高相似对: ${dupPairs} (${dupRate}%)`);
293
- if (total > sampleSize) {
294
- console.log(` 推算全库: ~${Math.round(dupPairs / totalPairs * total * (total-1) / 2).toLocaleString()} 对潜在重复`);
295
- }
296
-
297
- if (dupExamples.length > 0) {
298
- console.log("\n 示例重复对:");
299
- for (const ex of dupExamples) {
300
- console.log(` [sim=${ex.sim.toFixed(3)}]`);
301
- console.log(` A: ${ex.textA}...`);
302
- console.log(` B: ${ex.textB}...`);
303
- }
304
- }
305
-
306
- // ============================================
307
- // 8. 综合诊断
308
- // ============================================
309
- console.log("\n" + "=".repeat(60));
310
- console.log(`🩺 综合诊断 — ${BOT_NAME}`);
311
- console.log("=".repeat(60));
312
-
313
- const issues: string[] = [];
314
- const healthy: string[] = [];
315
-
316
- // Total count check
317
- if (total < 10) {
318
- issues.push(`🟡 记忆总量仅 ${total} 条,数据量偏少`);
319
- } else {
320
- healthy.push(`✅ 记忆总量 ${total.toLocaleString()} 条`);
321
- }
322
-
323
- // Dead memory ratio
324
- const deadRatio = deadCount / total;
325
- if (deadRatio > 0.9) {
326
- issues.push(`🔴 ${deadPct}% 记忆从未被访问(死记忆率过高)`);
327
- } else if (deadRatio > 0.7) {
328
- issues.push(`🟡 ${deadPct}% 记忆从未被访问(死记忆率偏高)`);
329
- } else {
330
- healthy.push(`✅ 死记忆率 ${deadPct}% 在合理范围`);
331
- }
332
-
333
- // Category balance — check if any single legacy category dominates
334
- const factCount = catMap.get("fact") || 0;
335
- const decisionCount = catMap.get("decision") || 0;
336
- const legacyRatio = (factCount + decisionCount) / total;
337
- if (legacyRatio > 0.5) {
338
- issues.push(`🟡 legacy 类别(fact/decision)占 ${(legacyRatio*100).toFixed(1)}%,建议迁移到 6-category 体系`);
339
- }
340
- // Check structural category coverage
341
- const structuredCount = (catMap.get("entities") || 0) + (catMap.get("patterns") || 0) + (catMap.get("cases") || 0);
342
- if (structuredCount === 0 && total > 20) {
343
- issues.push(`🟡 无结构化记忆(entities/patterns/cases 均为 0)`);
344
- } else if (structuredCount > 0) {
345
- healthy.push(`✅ 结构化记忆 ${structuredCount} 条(entities+patterns+cases)`);
346
- }
347
-
348
- // Tier distribution
349
- const coreCount = tierMap.get("core") || 0;
350
- const unknownTier = tierMap.get("unknown") || 0;
351
- if (unknownTier / total > 0.5) {
352
- issues.push(`🟡 ${(unknownTier/total*100).toFixed(1)}% 记忆无 tier 标记`);
353
- }
354
- if (coreCount < 5 && total > 50) {
355
- issues.push(`🟡 core tier 仅 ${coreCount} 条,高价值记忆太少`);
356
- } else if (coreCount >= 5) {
357
- healthy.push(`✅ core tier 有 ${coreCount} 条高价值记忆`);
358
- }
359
-
360
- // Importance differentiation
361
- const modeImpBucket = [...impBuckets.entries()].sort((a, b) => b[1] - a[1])[0];
362
- if (modeImpBucket && modeImpBucket[1] / total > 0.9) {
363
- issues.push(`🟡 ${(modeImpBucket[1]/total*100).toFixed(1)}% importance 集中在 ${modeImpBucket[0]},区分度不足`);
364
- } else {
365
- healthy.push(`✅ importance 分布有区分度`);
366
- }
367
-
368
- // Dup rate
369
- if (parseFloat(dupRate) > 1) {
370
- issues.push(`🟡 采样重复率 ${dupRate}%,全库可能存在大量近似重复`);
371
- } else {
372
- healthy.push(`✅ 采样重复率 ${dupRate}%,重复可控`);
373
- }
374
-
375
- for (const h of healthy) console.log(` ${h}`);
376
- for (const i of issues) console.log(` ${i}`);
377
-
378
- console.log("\n" + "=".repeat(60));
379
- console.log("📋 体检完成\n");
380
- }
381
-
382
- main().catch(console.error);