recallnest 2.2.0 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (232) hide show
  1. package/.env +4 -0
  2. package/config.json +55 -0
  3. package/logs/daily-recall.error.log +0 -0
  4. package/logs/daily-recall.log +30 -0
  5. package/logs/ingest-2026-04-11.log +110 -0
  6. package/logs/ingest-2026-04-12.log +90 -0
  7. package/logs/launchagent-stderr.log +0 -0
  8. package/logs/launchagent-stdout.log +0 -0
  9. package/package.json +1 -1
  10. package/.claude-plugin/CLAUDE.md +0 -29
  11. package/.claude-plugin/marketplace.json +0 -18
  12. package/.dockerignore +0 -11
  13. package/.github/workflows/ci.yml +0 -28
  14. package/.mcp.json +0 -9
  15. package/CHANGELOG.md +0 -51
  16. package/DEMO.md +0 -94
  17. package/Dockerfile +0 -20
  18. package/EVAL.md +0 -89
  19. package/FAILURES.md +0 -75
  20. package/OPERATIONS.md +0 -59
  21. package/ROADMAP.md +0 -245
  22. package/SKILL.md +0 -250
  23. package/assets/dashboard.png +0 -0
  24. package/assets/knowledge-graph.png +0 -0
  25. package/assets/recallnest-workbench.png +0 -0
  26. package/assets/screenshots/ui-full.png +0 -0
  27. package/assets/screenshots/ui-overview.png +0 -0
  28. package/assets/screenshots/ui-search.png +0 -0
  29. package/assets/ui/app.js +0 -1031
  30. package/assets/ui/index.html +0 -224
  31. package/assets/ui/styles.css +0 -781
  32. package/assets/wechat-qr.jpg +0 -0
  33. package/bun.lock +0 -337
  34. package/daily-reflections/2026-03-05.md +0 -15
  35. package/daily-reflections/2026-03-06.md +0 -15
  36. package/daily-reflections/2026-03-07.md +0 -7
  37. package/daily-reflections/2026-03-08.md +0 -34
  38. package/daily-reflections/2026-03-09.md +0 -35
  39. package/daily-reflections/2026-03-10.md +0 -36
  40. package/daily-reflections/2026-03-11.md +0 -35
  41. package/daily-reflections/2026-03-12.md +0 -36
  42. package/daily-reflections/2026-03-13.md +0 -35
  43. package/daily-reflections/2026-03-14.md +0 -35
  44. package/daily-reflections/2026-03-15.md +0 -35
  45. package/daily-reflections/2026-03-16.md +0 -41
  46. package/daily-reflections/2026-03-17.md +0 -10
  47. package/daily-reflections/2026-03-18.md +0 -10
  48. package/daily-reflections/2026-03-19.md +0 -10
  49. package/daily-reflections/2026-03-20.md +0 -10
  50. package/daily-reflections/2026-03-21.md +0 -10
  51. package/daily-reflections/2026-03-22.md +0 -10
  52. package/daily-reflections/2026-03-23.md +0 -10
  53. package/daily-reflections/2026-03-24.md +0 -10
  54. package/daily-reflections/2026-03-25.md +0 -32
  55. package/daily-reflections/2026-03-26.md +0 -37
  56. package/daily-reflections/2026-03-27.md +0 -35
  57. package/daily-reflections/2026-03-28.md +0 -35
  58. package/daily-reflections/2026-03-29.md +0 -35
  59. package/daily-reflections/2026-03-30.md +0 -36
  60. package/daily-reflections/2026-03-31.md +0 -35
  61. package/daily-reflections/2026-04-01.md +0 -35
  62. package/daily-reflections/2026-04-02.md +0 -35
  63. package/daily-reflections/2026-04-03.md +0 -37
  64. package/daily-reflections/2026-04-04.md +0 -37
  65. package/daily-reflections/2026-04-05.md +0 -35
  66. package/daily-reflections/2026-04-06.md +0 -36
  67. package/daily-reflections/2026-04-07.md +0 -35
  68. package/daily-reflections/2026-04-08.md +0 -35
  69. package/daily-reflections/2026-04-12.md +0 -35
  70. package/data/alias-map.example.json +0 -22
  71. package/docs/api-reference.md +0 -1291
  72. package/docs/architecture.md +0 -168
  73. package/docs/memory-boundary-contract.md +0 -226
  74. package/docs/memory-categories.md +0 -119
  75. package/docs/pipeline-audit-ultramemory.md +0 -177
  76. package/docs/plans/2026-03-08-query-expansion.md +0 -270
  77. package/docs/plans/2026-03-16-continuity-layer.md +0 -196
  78. package/docs/plans/2026-04-01-recall-boost.md +0 -100
  79. package/docs/plans/mcp-tiering-plan.md +0 -126
  80. package/docs/research/recall-quality-audit-2026-03-22.md +0 -153
  81. package/docs/self-evolution.md +0 -198
  82. package/docs/superpowers/plans/2026-03-19-ingest-pipeline-upgrade.md +0 -782
  83. package/docs/superpowers/plans/2026-04-11-constructive-retrieval-emotion.md +0 -1195
  84. package/docs/superpowers/specs/2026-03-19-ingest-pipeline-upgrade-design.md +0 -77
  85. package/docs/superpowers/specs/2026-03-23-pull-claude-desktop-design.md +0 -95
  86. package/docs/superpowers/specs/2026-04-11-constructive-retrieval-emotion-design.md +0 -398
  87. package/eval/continuity/results-2026-03-16.md +0 -117
  88. package/eval/continuity/results-2026-03-19.md +0 -453
  89. package/eval/continuity/runbook.md +0 -110
  90. package/eval/continuity/seed-cases.md +0 -54
  91. package/eval/reports/2026-03-06-abstract-query-baseline.md +0 -96
  92. package/eval/reports/2026-03-06-aws-ssh-baseline.md +0 -82
  93. package/eval/reports/2026-03-06-baseline.md +0 -82
  94. package/eval/reports/query-expansion.md +0 -138
  95. package/glama.json +0 -6
  96. package/lm +0 -19
  97. package/plan-philosophy-upgrades.md +0 -363
  98. package/plan-product-upgrades.md +0 -155
  99. package/plan-v1.2-distributable.md +0 -105
  100. package/plan.md +0 -140
  101. package/research-memory-evolution.md +0 -440
  102. package/research-rl-agent-memory.md +0 -330
  103. package/scripts/archive-distilled-junk.ts +0 -116
  104. package/scripts/backfill-anchors.ts +0 -130
  105. package/scripts/backfill-l0l1l2.ts +0 -98
  106. package/scripts/blind-scan.ts +0 -588
  107. package/scripts/cleanup-step1-exact-dups.ts +0 -117
  108. package/scripts/cleanup-step2-template-dups.ts +0 -113
  109. package/scripts/cleanup-step3-stale-content.ts +0 -149
  110. package/scripts/cleanup-step4-orphan-scopes.ts +0 -131
  111. package/scripts/delete-distilled-junk.ts +0 -88
  112. package/scripts/diagnose-vector-search.ts +0 -132
  113. package/scripts/distill-facts.ts +0 -305
  114. package/scripts/health-check.ts +0 -343
  115. package/scripts/incremental-ingest.sh +0 -71
  116. package/scripts/migrate-language.ts +0 -75
  117. package/scripts/mlp-health-check.ts +0 -382
  118. package/scripts/pull-claude-desktop.ts +0 -515
  119. package/scripts/re-ingest-cc.sh +0 -66
  120. package/scripts/rebalance-memory-health.ts +0 -181
  121. package/scripts/run-desktop-ingest.sh +0 -11
  122. package/scripts/start-server.sh +0 -12
  123. package/scripts/verify-emotion-decay.ts +0 -148
  124. package/scripts/viz-dashboard.html +0 -423
  125. package/scripts/viz-export.ts +0 -703
  126. package/src/__tests__/access-tracker-novelty.test.ts +0 -228
  127. package/src/__tests__/activity-counter.test.ts +0 -96
  128. package/src/__tests__/admission-control.test.ts +0 -206
  129. package/src/__tests__/anchor-generator.test.ts +0 -67
  130. package/src/__tests__/auto-consolidation.test.ts +0 -168
  131. package/src/__tests__/auto-recall.test.ts +0 -131
  132. package/src/__tests__/babel-integration.test.ts +0 -139
  133. package/src/__tests__/batch-dedup.test.ts +0 -65
  134. package/src/__tests__/capture-engine.test.ts +0 -1144
  135. package/src/__tests__/capture-heuristic.test.ts +0 -171
  136. package/src/__tests__/cascade-forget.test.ts +0 -210
  137. package/src/__tests__/category-min-scores.test.ts +0 -33
  138. package/src/__tests__/cc8-cc1-essential-context.test.ts +0 -298
  139. package/src/__tests__/circuit-breaker.test.ts +0 -99
  140. package/src/__tests__/cluster-consolidation.test.ts +0 -712
  141. package/src/__tests__/confidence-metadata.test.ts +0 -125
  142. package/src/__tests__/confidence-tracker.test.ts +0 -249
  143. package/src/__tests__/conflict-advisor.test.ts +0 -206
  144. package/src/__tests__/conflict-escalation.test.ts +0 -149
  145. package/src/__tests__/conflict-lifecycle.test.ts +0 -83
  146. package/src/__tests__/conflict-output.test.ts +0 -85
  147. package/src/__tests__/conflict-store.test.ts +0 -374
  148. package/src/__tests__/consolidation-engine.test.ts +0 -181
  149. package/src/__tests__/constructive-retrieval.test.ts +0 -509
  150. package/src/__tests__/context-collapse-renderer.test.ts +0 -214
  151. package/src/__tests__/context-composer-pins.test.ts +0 -64
  152. package/src/__tests__/context-composer-task-selection.test.ts +0 -24
  153. package/src/__tests__/context-reconstructor.test.ts +0 -65
  154. package/src/__tests__/context-renderer.test.ts +0 -91
  155. package/src/__tests__/continuity-eval.test.ts +0 -275
  156. package/src/__tests__/continuity-schema.test.ts +0 -97
  157. package/src/__tests__/conversation-importer.test.ts +0 -692
  158. package/src/__tests__/core-recall-eval.test.ts +0 -235
  159. package/src/__tests__/core-summary.test.ts +0 -109
  160. package/src/__tests__/data-checkup.test.ts +0 -225
  161. package/src/__tests__/decay-exemption.test.ts +0 -84
  162. package/src/__tests__/dedup-actions.test.ts +0 -58
  163. package/src/__tests__/dedup-guard.test.ts +0 -39
  164. package/src/__tests__/deterministic-id.test.ts +0 -39
  165. package/src/__tests__/distill-lock.test.ts +0 -176
  166. package/src/__tests__/doctor.test.ts +0 -303
  167. package/src/__tests__/dream-pipeline.test.ts +0 -232
  168. package/src/__tests__/drill-down.test.ts +0 -108
  169. package/src/__tests__/embedder.test.ts +0 -122
  170. package/src/__tests__/emotion-decay.test.ts +0 -46
  171. package/src/__tests__/emotion-detector.test.ts +0 -56
  172. package/src/__tests__/emotion-phase1-integration.test.ts +0 -153
  173. package/src/__tests__/emotion-retrieval.test.ts +0 -56
  174. package/src/__tests__/entity-resolver.test.ts +0 -58
  175. package/src/__tests__/ethics-layer.test.ts +0 -476
  176. package/src/__tests__/event-segmenter.test.ts +0 -153
  177. package/src/__tests__/feature-flags-integration.test.ts +0 -54
  178. package/src/__tests__/frequency-tracker.test.ts +0 -113
  179. package/src/__tests__/graph-export.test.ts +0 -489
  180. package/src/__tests__/hotness-blend.test.ts +0 -76
  181. package/src/__tests__/ingest.test.ts +0 -360
  182. package/src/__tests__/interference-detector.test.ts +0 -203
  183. package/src/__tests__/kg-extractor.test.ts +0 -184
  184. package/src/__tests__/kg-store.test.ts +0 -198
  185. package/src/__tests__/llm-consolidation.test.ts +0 -226
  186. package/src/__tests__/mcp-efficiency.test.ts +0 -288
  187. package/src/__tests__/memory-boundaries.test.ts +0 -237
  188. package/src/__tests__/memory-evolution-b2-b3-e1.test.ts +0 -243
  189. package/src/__tests__/memory-evolution.test.ts +0 -271
  190. package/src/__tests__/memory-health-rebalance.test.ts +0 -144
  191. package/src/__tests__/memory-lint.test.ts +0 -271
  192. package/src/__tests__/memory-output.test.ts +0 -215
  193. package/src/__tests__/multi-vector.test.ts +0 -242
  194. package/src/__tests__/narrative-architecture.test.ts +0 -456
  195. package/src/__tests__/pending-review.test.ts +0 -77
  196. package/src/__tests__/post-retrieval-filter.test.ts +0 -178
  197. package/src/__tests__/ppr-traversal.test.ts +0 -256
  198. package/src/__tests__/prediction-engine.test.ts +0 -349
  199. package/src/__tests__/predictive-prospective-memory.test.ts +0 -416
  200. package/src/__tests__/preference-guard-smoke.test.ts +0 -211
  201. package/src/__tests__/preference-matcher.test.ts +0 -230
  202. package/src/__tests__/preference-slots.test.ts +0 -205
  203. package/src/__tests__/prospective-memory.test.ts +0 -283
  204. package/src/__tests__/query-entity-detector.test.ts +0 -171
  205. package/src/__tests__/query-expander-alias.test.ts +0 -89
  206. package/src/__tests__/query-expander.test.ts +0 -34
  207. package/src/__tests__/recall-governor.test.ts +0 -227
  208. package/src/__tests__/recall-mode.test.ts +0 -64
  209. package/src/__tests__/result-synthesizer.test.ts +0 -198
  210. package/src/__tests__/resume-context.test.ts +0 -4898
  211. package/src/__tests__/retrieval-trace.test.ts +0 -213
  212. package/src/__tests__/retriever-boundary-weight.test.ts +0 -136
  213. package/src/__tests__/retroactive-boost.test.ts +0 -223
  214. package/src/__tests__/salience-scoring.test.ts +0 -106
  215. package/src/__tests__/scope-inventory.test.ts +0 -200
  216. package/src/__tests__/scope-policy.test.ts +0 -69
  217. package/src/__tests__/session-checkpoint.test.ts +0 -259
  218. package/src/__tests__/session-distiller.test.ts +0 -611
  219. package/src/__tests__/session-gc.test.ts +0 -215
  220. package/src/__tests__/skill-engine.test.ts +0 -546
  221. package/src/__tests__/skill-promotion.test.ts +0 -349
  222. package/src/__tests__/store-scope-audit.test.ts +0 -81
  223. package/src/__tests__/supersede-chain.test.ts +0 -154
  224. package/src/__tests__/temporal-parser.test.ts +0 -241
  225. package/src/__tests__/temporal-validity.test.ts +0 -160
  226. package/src/__tests__/term-registry.test.ts +0 -121
  227. package/src/__tests__/tool-output-compressor.test.ts +0 -133
  228. package/src/__tests__/topic-tag.test.ts +0 -113
  229. package/src/__tests__/trusted-memory.test.ts +0 -828
  230. package/src/__tests__/version-manager.test.ts +0 -213
  231. package/src/__tests__/workflow-observation.test.ts +0 -400
  232. 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);