recallnest 1.4.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.
- package/.claude-plugin/CLAUDE.md +29 -0
- package/.claude-plugin/marketplace.json +18 -0
- package/.env.example +3 -0
- package/.github/workflows/ci.yml +28 -0
- package/.mcp.json +9 -0
- package/CHANGELOG.md +51 -0
- package/CLAUDE.md +42 -0
- package/DEMO.md +94 -0
- package/EVAL.md +89 -0
- package/FAILURES.md +75 -0
- package/LICENSE +21 -0
- package/OPERATIONS.md +59 -0
- package/README.md +427 -0
- package/README_CN.md +425 -0
- package/ROADMAP.md +198 -0
- package/assets/recallnest-workbench.png +0 -0
- package/assets/ui/app.js +807 -0
- package/assets/ui/index.html +154 -0
- package/assets/ui/styles.css +605 -0
- package/assets/wechat-qr.jpg +0 -0
- package/config.json.example +38 -0
- package/daily-recall.sh +87 -0
- package/daily-reflections/2026-03-05.md +15 -0
- package/daily-reflections/2026-03-06.md +15 -0
- package/daily-reflections/2026-03-07.md +7 -0
- package/daily-reflections/2026-03-08.md +34 -0
- package/daily-reflections/2026-03-09.md +35 -0
- package/daily-reflections/2026-03-10.md +36 -0
- package/daily-reflections/2026-03-11.md +35 -0
- package/daily-reflections/2026-03-12.md +36 -0
- package/daily-reflections/2026-03-13.md +35 -0
- package/daily-reflections/2026-03-14.md +35 -0
- package/daily-reflections/2026-03-15.md +35 -0
- package/daily-reflections/2026-03-16.md +41 -0
- package/daily-reflections/2026-03-17.md +10 -0
- package/daily-reflections/2026-03-18.md +10 -0
- package/daily-reflections/2026-03-19.md +10 -0
- package/daily-reflections/2026-03-20.md +10 -0
- package/daily-reflections/2026-03-21.md +10 -0
- package/daily-reflections/2026-03-22.md +10 -0
- package/daily-reflections/2026-03-23.md +10 -0
- package/daily-reflections/2026-03-24.md +10 -0
- package/daily-reflections/2026-03-25.md +32 -0
- package/daily-reflections/2026-03-26.md +37 -0
- package/daily-reflections/2026-03-27.md +35 -0
- package/daily-reflections/2026-03-28.md +35 -0
- package/daily-reflections/2026-03-29.md +35 -0
- package/daily-reflections/2026-03-30.md +36 -0
- package/daily-reflections/2026-03-31.md +35 -0
- package/daily-reflections/2026-04-01.md +35 -0
- package/docs/api-reference.md +1291 -0
- package/docs/architecture.md +168 -0
- package/docs/memory-boundary-contract.md +226 -0
- package/docs/memory-categories.md +119 -0
- package/docs/pipeline-audit-ultramemory.md +177 -0
- package/docs/plans/2026-03-08-query-expansion.md +270 -0
- package/docs/plans/2026-03-16-continuity-layer.md +196 -0
- package/docs/plans/mcp-tiering-plan.md +126 -0
- package/docs/research/recall-quality-audit-2026-03-22.md +153 -0
- package/docs/self-evolution.md +198 -0
- package/docs/superpowers/plans/2026-03-19-ingest-pipeline-upgrade.md +782 -0
- package/docs/superpowers/specs/2026-03-19-ingest-pipeline-upgrade-design.md +77 -0
- package/docs/superpowers/specs/2026-03-23-pull-claude-desktop-design.md +95 -0
- package/eval/cases.json +85 -0
- package/eval/continuity/case-seeds.json +90 -0
- package/eval/continuity/cases.json +302 -0
- package/eval/continuity/memory-seeds.json +26 -0
- package/eval/continuity/pattern-seeds.json +100 -0
- package/eval/continuity/results-2026-03-16.md +117 -0
- package/eval/continuity/results-2026-03-19.md +453 -0
- package/eval/continuity/runbook.md +110 -0
- package/eval/continuity/seed-cases.md +54 -0
- package/eval/reports/2026-03-06-abstract-query-baseline.md +96 -0
- package/eval/reports/2026-03-06-aws-ssh-baseline.md +82 -0
- package/eval/reports/2026-03-06-baseline.md +82 -0
- package/eval/reports/query-expansion.md +138 -0
- package/integrations/README.md +57 -0
- package/integrations/claude-code/README.md +133 -0
- package/integrations/claude-code/claude-md-snippet.md +31 -0
- package/integrations/claude-code/setup.sh +66 -0
- package/integrations/claude-code/smoke-continuity.sh +452 -0
- package/integrations/codex/README.md +49 -0
- package/integrations/codex/agents-md-snippet.md +31 -0
- package/integrations/codex/setup.sh +58 -0
- package/integrations/examples/claude-agent-sdk/memory-agent.ts +182 -0
- package/integrations/examples/langchain/memory-chain.py +111 -0
- package/integrations/examples/openai-agents-sdk/memory-agent.py +109 -0
- package/integrations/gemini-cli/README.md +57 -0
- package/integrations/gemini-cli/gemini-md-snippet.md +31 -0
- package/integrations/gemini-cli/setup.sh +64 -0
- package/integrations/shared/install-managed-block.sh +51 -0
- package/lm +19 -0
- package/package.json +50 -0
- package/plan-v1.2-distributable.md +105 -0
- package/scripts/archive-distilled-junk.ts +116 -0
- package/scripts/backfill-l0l1l2.ts +98 -0
- package/scripts/blind-scan.ts +588 -0
- package/scripts/cleanup-step1-exact-dups.ts +117 -0
- package/scripts/cleanup-step2-template-dups.ts +113 -0
- package/scripts/cleanup-step3-stale-content.ts +149 -0
- package/scripts/cleanup-step4-orphan-scopes.ts +131 -0
- package/scripts/delete-distilled-junk.ts +88 -0
- package/scripts/distill-facts.ts +305 -0
- package/scripts/health-check.ts +343 -0
- package/scripts/incremental-ingest.sh +71 -0
- package/scripts/mlp-health-check.ts +382 -0
- package/scripts/pull-claude-desktop.ts +515 -0
- package/scripts/re-ingest-cc.sh +66 -0
- package/scripts/rebalance-memory-health.ts +181 -0
- package/scripts/run-desktop-ingest.sh +11 -0
- package/scripts/start-server.sh +12 -0
- package/scripts/viz-dashboard.html +423 -0
- package/scripts/viz-export.ts +703 -0
- package/src/__tests__/access-tracker-novelty.test.ts +228 -0
- package/src/__tests__/auto-consolidation.test.ts +168 -0
- package/src/__tests__/auto-recall.test.ts +131 -0
- package/src/__tests__/batch-dedup.test.ts +65 -0
- package/src/__tests__/capture-engine.test.ts +1142 -0
- package/src/__tests__/capture-heuristic.test.ts +171 -0
- package/src/__tests__/cascade-forget.test.ts +210 -0
- package/src/__tests__/category-min-scores.test.ts +33 -0
- package/src/__tests__/confidence-tracker.test.ts +196 -0
- package/src/__tests__/conflict-advisor.test.ts +206 -0
- package/src/__tests__/conflict-escalation.test.ts +149 -0
- package/src/__tests__/conflict-lifecycle.test.ts +83 -0
- package/src/__tests__/conflict-output.test.ts +85 -0
- package/src/__tests__/conflict-store.test.ts +374 -0
- package/src/__tests__/consolidation-engine.test.ts +181 -0
- package/src/__tests__/context-composer-pins.test.ts +64 -0
- package/src/__tests__/context-composer-task-selection.test.ts +24 -0
- package/src/__tests__/context-renderer.test.ts +91 -0
- package/src/__tests__/continuity-eval.test.ts +275 -0
- package/src/__tests__/continuity-schema.test.ts +97 -0
- package/src/__tests__/core-recall-eval.test.ts +235 -0
- package/src/__tests__/core-summary.test.ts +109 -0
- package/src/__tests__/dedup-actions.test.ts +58 -0
- package/src/__tests__/deterministic-id.test.ts +39 -0
- package/src/__tests__/doctor.test.ts +303 -0
- package/src/__tests__/drill-down.test.ts +108 -0
- package/src/__tests__/embedder.test.ts +122 -0
- package/src/__tests__/entity-resolver.test.ts +58 -0
- package/src/__tests__/event-segmenter.test.ts +153 -0
- package/src/__tests__/hotness-blend.test.ts +76 -0
- package/src/__tests__/ingest.test.ts +360 -0
- package/src/__tests__/kg-extractor.test.ts +184 -0
- package/src/__tests__/kg-store.test.ts +198 -0
- package/src/__tests__/llm-consolidation.test.ts +226 -0
- package/src/__tests__/memory-boundaries.test.ts +237 -0
- package/src/__tests__/memory-health-rebalance.test.ts +144 -0
- package/src/__tests__/memory-output.test.ts +215 -0
- package/src/__tests__/multi-vector.test.ts +242 -0
- package/src/__tests__/ppr-traversal.test.ts +256 -0
- package/src/__tests__/preference-guard-smoke.test.ts +211 -0
- package/src/__tests__/preference-matcher.test.ts +230 -0
- package/src/__tests__/preference-slots.test.ts +106 -0
- package/src/__tests__/prospective-memory.test.ts +283 -0
- package/src/__tests__/query-entity-detector.test.ts +171 -0
- package/src/__tests__/query-expander.test.ts +34 -0
- package/src/__tests__/recall-mode.test.ts +64 -0
- package/src/__tests__/result-synthesizer.test.ts +198 -0
- package/src/__tests__/resume-context.test.ts +4743 -0
- package/src/__tests__/retrieval-trace.test.ts +213 -0
- package/src/__tests__/retriever-boundary-weight.test.ts +136 -0
- package/src/__tests__/retroactive-boost.test.ts +223 -0
- package/src/__tests__/scope-inventory.test.ts +200 -0
- package/src/__tests__/scope-policy.test.ts +69 -0
- package/src/__tests__/session-checkpoint.test.ts +259 -0
- package/src/__tests__/session-gc.test.ts +215 -0
- package/src/__tests__/store-scope-audit.test.ts +81 -0
- package/src/__tests__/temporal-parser.test.ts +241 -0
- package/src/__tests__/term-registry.test.ts +121 -0
- package/src/__tests__/tool-output-compressor.test.ts +133 -0
- package/src/__tests__/version-manager.test.ts +213 -0
- package/src/__tests__/workflow-observation.test.ts +400 -0
- package/src/access-tracker.ts +316 -0
- package/src/adaptive-retrieval.ts +64 -0
- package/src/api-server.ts +667 -0
- package/src/asset-sync.ts +79 -0
- package/src/auto-consolidation.ts +133 -0
- package/src/auto-gc.ts +124 -0
- package/src/auto-recall.ts +95 -0
- package/src/capture-engine.ts +931 -0
- package/src/capture-heuristic.ts +177 -0
- package/src/cascade-forget.ts +135 -0
- package/src/chunker.ts +253 -0
- package/src/cli.ts +1917 -0
- package/src/confidence-tracker.ts +166 -0
- package/src/conflict-advisor.ts +433 -0
- package/src/conflict-engine.ts +181 -0
- package/src/conflict-escalation.ts +138 -0
- package/src/conflict-lifecycle.ts +67 -0
- package/src/conflict-output.ts +218 -0
- package/src/conflict-schema.ts +130 -0
- package/src/conflict-store.ts +127 -0
- package/src/consolidation-engine.ts +256 -0
- package/src/context-composer-pins.ts +183 -0
- package/src/context-composer-queries.ts +121 -0
- package/src/context-composer-scope.ts +56 -0
- package/src/context-composer-stable-selection.ts +200 -0
- package/src/context-composer-stable.ts +217 -0
- package/src/context-composer-task-fallbacks.ts +36 -0
- package/src/context-composer-task-ranking.ts +197 -0
- package/src/context-composer-task-results.ts +137 -0
- package/src/context-composer-task-selection.ts +342 -0
- package/src/context-composer-text.ts +57 -0
- package/src/context-composer.ts +300 -0
- package/src/context-renderer.ts +179 -0
- package/src/decay-engine.ts +189 -0
- package/src/doctor.ts +543 -0
- package/src/embedder.ts +557 -0
- package/src/entity-resolver.ts +131 -0
- package/src/eval.ts +632 -0
- package/src/event-segmenter.ts +216 -0
- package/src/ingest.ts +1822 -0
- package/src/kg-extractor.ts +217 -0
- package/src/kg-store.ts +353 -0
- package/src/legacy-scope-review.ts +53 -0
- package/src/llm-client.ts +629 -0
- package/src/llm-consolidation.ts +168 -0
- package/src/mcp-server.ts +1337 -0
- package/src/memory-assets.ts +475 -0
- package/src/memory-boundaries.ts +354 -0
- package/src/memory-health-rebalance.ts +220 -0
- package/src/memory-output.ts +474 -0
- package/src/memory-schema.ts +184 -0
- package/src/multi-vector.ts +234 -0
- package/src/noise-filter.ts +155 -0
- package/src/ppr-traversal.ts +279 -0
- package/src/preference-matcher.ts +174 -0
- package/src/preference-slots.ts +259 -0
- package/src/prospective-memory.ts +198 -0
- package/src/query-entity-detector.ts +207 -0
- package/src/query-expander.ts +98 -0
- package/src/result-synthesizer.ts +114 -0
- package/src/retrieval-profiles.ts +101 -0
- package/src/retrieval-trace.ts +94 -0
- package/src/retriever.ts +1338 -0
- package/src/retroactive-boost.ts +154 -0
- package/src/rif.ts +73 -0
- package/src/runtime-config.ts +172 -0
- package/src/schema-utils.ts +56 -0
- package/src/scope-inventory.ts +310 -0
- package/src/scope-policy.ts +142 -0
- package/src/session-engine.ts +168 -0
- package/src/session-output.ts +96 -0
- package/src/session-schema.ts +60 -0
- package/src/session-store.ts +293 -0
- package/src/stderr-log.ts +16 -0
- package/src/store.ts +903 -0
- package/src/temporal-parser.ts +318 -0
- package/src/term-registry.ts +791 -0
- package/src/tool-output-compressor.ts +115 -0
- package/src/tracker.ts +57 -0
- package/src/ui-server.ts +430 -0
- package/src/version-manager.ts +172 -0
- package/src/workflow-observation-engine.ts +316 -0
- package/src/workflow-observation-managed.ts +83 -0
- package/src/workflow-observation-output.ts +86 -0
- package/src/workflow-observation-schema.ts +87 -0
- package/src/workflow-observation-scope-review.ts +409 -0
- package/src/workflow-observation-store.ts +69 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# RecallNest v1.2: 首个可传播版本 Plan
|
|
2
|
+
|
|
3
|
+
> 目标:别人 15 分钟能跑起来,30 分钟能感知价值
|
|
4
|
+
> 负责人:CC (实现) + 用户 (审批)
|
|
5
|
+
> 预计:3-4 天
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 阻塞项(必须修,按优先级排)
|
|
10
|
+
|
|
11
|
+
### B1: `recallnest doctor` 命令(新增) ✅ DONE
|
|
12
|
+
**问题**:用户装完后没有一键验证手段,每个环节都可能静默失败
|
|
13
|
+
**方案**:新增 `lm doctor` 子命令,检查清单:
|
|
14
|
+
- [x] Bun 运行时可用?(检测版本)
|
|
15
|
+
- [x] Jina API key 已配置?(读 .env)
|
|
16
|
+
- [x] Jina API key 有效?(发一个测试 embedding 请求)
|
|
17
|
+
- [x] CC transcript 路径可访问?(auto-detect 或 config)
|
|
18
|
+
- [x] LanceDB 数据目录可写?
|
|
19
|
+
- [x] 已有索引?多少条?
|
|
20
|
+
- 输出:绿色 PASS / 红色 FAIL + 修复建议
|
|
21
|
+
|
|
22
|
+
### B2: README 安装体验重写 ✅ DONE
|
|
23
|
+
**问题**:Bun 未提及、Jina key 获取无引导、步骤跳跃
|
|
24
|
+
**方案**:
|
|
25
|
+
- [x] Prerequisites 段:明确列出 Bun ≥1.0 + Node ≥20(Bun 优先,Node 作为 fallback 说明)
|
|
26
|
+
- [x] 快速开始改为 5 步 copy-paste:clone → install → 配 key → doctor → search
|
|
27
|
+
- [x] 每步附带预期输出(用户知道"成功了"长什么样)
|
|
28
|
+
- [x] 添加 "Troubleshooting" 段:Bun not found / Jina 401 / 路径不存在
|
|
29
|
+
|
|
30
|
+
### B3: Jina API key 前置验证 ✅ DONE
|
|
31
|
+
**问题**:config 加载成功,但第一次 ingest 才报 embedding 失败,错误信息是 OpenAI SDK 的原始 401
|
|
32
|
+
**方案**:
|
|
33
|
+
- [x] `ingest` 命令启动时,先调 embedder 发一个测试请求(embed "test")
|
|
34
|
+
- [x] 失败则立即报错:`Jina API key invalid or missing. Get one at https://jina.ai/embeddings/`
|
|
35
|
+
- [x] `doctor` 命令复用同一验证逻辑
|
|
36
|
+
|
|
37
|
+
### B4: Gemini 支持诚实化 ✅ DONE
|
|
38
|
+
**问题**:README 说支持 Gemini CLI,config 里有 gemini 源,但实际 Gemini 会话是加密 protobuf,解析不了
|
|
39
|
+
**方案**:
|
|
40
|
+
- [x] README 中 Gemini 行标注为 `Coming soon`(不是 ✅)
|
|
41
|
+
- [x] config.json.example 中移除 gemini source(新用户不会误配)
|
|
42
|
+
- [x] ingest 遇到 gemini source 时打印明确 warning:`Gemini CLI sessions are encrypted protobuf; skipping`
|
|
43
|
+
- [x] doctor 显示 Gemini 状态为 warn(已有配置的用户看到明确提示)
|
|
44
|
+
- 不删代码,保留未来扩展能力
|
|
45
|
+
|
|
46
|
+
### B5: 配置路径健壮化 ✅ DONE
|
|
47
|
+
**问题**:`./data/lancedb` 是相对路径,换目录就炸;auto-detect 失败后建议不够具体
|
|
48
|
+
**方案**:
|
|
49
|
+
- [x] config.json.example 默认路径改为 `~/.recallnest/data/lancedb`(绝对,用户无感)
|
|
50
|
+
- [x] 首次运行自动创建目录(validateStoragePath 已有 mkdirSync recursive)
|
|
51
|
+
- [x] auto-detect 失败时,给出完整示例(含用户名的真实路径)
|
|
52
|
+
- [x] config.json 加入 .gitignore,用户配置不被 git 覆盖
|
|
53
|
+
- [x] findConfigPath 失败时提示 `cp config.json.example config.json`
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 加分项(做了更好,不阻塞发布)
|
|
58
|
+
|
|
59
|
+
### P1: Demo 查询内置 ✅ DONE
|
|
60
|
+
- [x] `lm demo` 命令:用 3 个内置 query 跑搜索,展示结果格式
|
|
61
|
+
- [x] 显示索引统计 + 每条结果的分数/来源/预览
|
|
62
|
+
|
|
63
|
+
### P2: 一键安装脚本
|
|
64
|
+
- [ ] `curl -fsSL https://raw.githubusercontent.com/.../install.sh | bash`
|
|
65
|
+
- [ ] 检测 Bun → clone → npm install → 提示配 key → 跑 doctor
|
|
66
|
+
- [ ] 可以 Q2 再做,现在 README 手动步骤够用
|
|
67
|
+
|
|
68
|
+
### P3: CI 基础 ✅ DONE
|
|
69
|
+
- [x] GitHub Actions:push/PR 时跑 `doctor --ci` + TypeScript check
|
|
70
|
+
- [x] `lm doctor --ci` 模式跳过 API key 在线验证
|
|
71
|
+
|
|
72
|
+
### P4: CHANGELOG.md ✅ DONE
|
|
73
|
+
- [x] v1.0.0 到 v1.2.0 的变更记录
|
|
74
|
+
- [x] 后续每个 release 维护
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## 不做的事(明确排除)
|
|
79
|
+
|
|
80
|
+
- ❌ 不做 Docker 化(用户群是 CLI/MCP 用户,不是 Docker 用户)
|
|
81
|
+
- ❌ 不做 NPM 发布(先 git clone 模式验证需求)
|
|
82
|
+
- ❌ 不做 UI 重写(现有 UI 够用,不是本次重点)
|
|
83
|
+
- ❌ 不做多用户支持(单 operator 场景)
|
|
84
|
+
- ❌ 不重写检索逻辑(已经够好,不是本次范围)
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## 执行顺序
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
Day 1: B1 (doctor) + B3 (Jina 验证) — 核心安全网 ✅
|
|
92
|
+
Day 2: B5 (路径健壮化) + B4 (Gemini 诚实化) + B2 (README 重写) ✅
|
|
93
|
+
Day 3: P1 (demo 查询) + P3 (CI) + P4 (CHANGELOG) ✅
|
|
94
|
+
Day 4: 自测完整流程
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## 验收标准
|
|
100
|
+
|
|
101
|
+
1. 全新 macOS 机器(有 Bun),从 clone 到第一条搜索结果 ≤ 15 分钟
|
|
102
|
+
2. `lm doctor` 全绿
|
|
103
|
+
3. Jina key 错误时,3 秒内给出明确修复建议
|
|
104
|
+
4. README 无需翻代码即可完成安装
|
|
105
|
+
5. `lm search "telegram bridge"` 返回有意义结果
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Archive raw fact fragments that have already been distilled.
|
|
4
|
+
* Targets: entries in distill-completed scopes with importance < 0.4, no L0, category=fact.
|
|
5
|
+
* Action: set tier="archived", importance=0.05 — they won't surface but data isn't lost.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* bun scripts/archive-distilled-junk.ts --dry-run # preview
|
|
9
|
+
* bun scripts/archive-distilled-junk.ts # execute
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import fs from "fs";
|
|
13
|
+
import path from "path";
|
|
14
|
+
import { loadDotEnv, loadConfig, expandHome } from "../src/runtime-config.js";
|
|
15
|
+
import { loadLanceDB } from "../src/store.js";
|
|
16
|
+
|
|
17
|
+
loadDotEnv();
|
|
18
|
+
const config = loadConfig();
|
|
19
|
+
const dryRun = process.argv.includes("--dry-run");
|
|
20
|
+
|
|
21
|
+
const PROGRESS_FILE = path.join(import.meta.dir, "..", "data", "distill-progress.json");
|
|
22
|
+
|
|
23
|
+
async function main() {
|
|
24
|
+
// Load distill progress to know which scopes are done
|
|
25
|
+
const progress = JSON.parse(fs.readFileSync(PROGRESS_FILE, "utf-8"));
|
|
26
|
+
const completedScopes = new Set<string>(progress.completedScopes);
|
|
27
|
+
console.log(`=== Archive distilled junk${dryRun ? " (dry run)" : ""} ===\n`);
|
|
28
|
+
console.log(` Distill-completed scopes: ${completedScopes.size}`);
|
|
29
|
+
|
|
30
|
+
const lancedb = await loadLanceDB();
|
|
31
|
+
const dbPath = expandHome(config.database?.path || "data/lancedb");
|
|
32
|
+
const db = await lancedb.connect(dbPath);
|
|
33
|
+
const table = await db.openTable("memories");
|
|
34
|
+
|
|
35
|
+
// Read all fact entries
|
|
36
|
+
const allFacts = await table.query()
|
|
37
|
+
.where("category = 'fact'")
|
|
38
|
+
.select(["id", "text", "vector", "category", "scope", "importance", "timestamp", "metadata"])
|
|
39
|
+
.toArray();
|
|
40
|
+
|
|
41
|
+
console.log(` Total fact entries: ${allFacts.length}`);
|
|
42
|
+
|
|
43
|
+
// Filter: in completed scope, importance < 0.4, no L0
|
|
44
|
+
const toArchive: any[] = [];
|
|
45
|
+
const sampleJunk: string[] = [];
|
|
46
|
+
|
|
47
|
+
for (const row of allFacts) {
|
|
48
|
+
const scope = (row.scope as string) || "";
|
|
49
|
+
if (!completedScopes.has(scope)) continue;
|
|
50
|
+
|
|
51
|
+
const imp = Number(row.importance);
|
|
52
|
+
if (imp >= 0.4) continue;
|
|
53
|
+
|
|
54
|
+
const metaStr = (row.metadata as string) || "{}";
|
|
55
|
+
let meta: Record<string, unknown>;
|
|
56
|
+
try { meta = JSON.parse(metaStr); } catch { continue; }
|
|
57
|
+
|
|
58
|
+
// Has L0 = already a quality entry, skip
|
|
59
|
+
if (typeof meta.l0_abstract === "string" && meta.l0_abstract.length > 0) continue;
|
|
60
|
+
|
|
61
|
+
// Mark as archived
|
|
62
|
+
meta.tier = "archived";
|
|
63
|
+
meta.archived_reason = "distilled-junk-cleanup-2026-03-26";
|
|
64
|
+
|
|
65
|
+
toArchive.push({
|
|
66
|
+
id: row.id,
|
|
67
|
+
text: row.text,
|
|
68
|
+
vector: Array.from(row.vector as Iterable<number>),
|
|
69
|
+
category: row.category,
|
|
70
|
+
scope: scope,
|
|
71
|
+
importance: 0.05, // near-zero so it never surfaces
|
|
72
|
+
timestamp: Number(row.timestamp),
|
|
73
|
+
metadata: JSON.stringify(meta),
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Collect samples
|
|
77
|
+
if (sampleJunk.length < 10) {
|
|
78
|
+
const text = (row.text as string).slice(0, 80);
|
|
79
|
+
sampleJunk.push(` ${(row.id as string).slice(0, 8)} imp=${imp.toFixed(2)} scope=${scope.slice(0, 15)} | ${text}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
console.log(` Junk to archive: ${toArchive.length}`);
|
|
84
|
+
console.log(` Would keep: ${allFacts.length - toArchive.length} fact entries\n`);
|
|
85
|
+
|
|
86
|
+
if (sampleJunk.length > 0) {
|
|
87
|
+
console.log(` Sample junk:\n${sampleJunk.join("\n")}\n`);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (dryRun) {
|
|
91
|
+
console.log(` (dry run — no changes made)`);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (toArchive.length === 0) {
|
|
96
|
+
console.log(` Nothing to archive.`);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Batch update
|
|
101
|
+
const batchSize = 1000;
|
|
102
|
+
for (let i = 0; i < toArchive.length; i += batchSize) {
|
|
103
|
+
const batch = toArchive.slice(i, i + batchSize);
|
|
104
|
+
const ids = batch.map((r: any) => `'${r.id.replace(/'/g, "''")}'`).join(",");
|
|
105
|
+
await table.delete(`id IN (${ids})`);
|
|
106
|
+
await table.add(batch);
|
|
107
|
+
console.log(` Batch ${Math.floor(i / batchSize) + 1}: archived ${batch.length} entries`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
console.log(`\nDone. Archived ${toArchive.length} junk fact entries (importance → 0.05, tier → archived).`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
main().catch(err => {
|
|
114
|
+
console.error("Archive failed:", err);
|
|
115
|
+
process.exit(1);
|
|
116
|
+
});
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* One-time backfill: normalize legacy l0/l1 short names to l0_abstract/l1_overview/l2_content
|
|
4
|
+
* in metadata. Uses batch read + batch write for performance.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* bun scripts/backfill-l0l1l2.ts --dry-run # preview
|
|
8
|
+
* bun scripts/backfill-l0l1l2.ts # execute
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { loadDotEnv, loadConfig, expandHome } from "../src/runtime-config.js";
|
|
12
|
+
import { loadLanceDB } from "../src/store.js";
|
|
13
|
+
|
|
14
|
+
loadDotEnv();
|
|
15
|
+
const config = loadConfig();
|
|
16
|
+
const dryRun = process.argv.includes("--dry-run");
|
|
17
|
+
|
|
18
|
+
async function main() {
|
|
19
|
+
const lancedb = await loadLanceDB();
|
|
20
|
+
const dbPath = expandHome(config.database?.path || "data/lancedb");
|
|
21
|
+
const db = await lancedb.connect(dbPath);
|
|
22
|
+
const table = await db.openTable("memories");
|
|
23
|
+
|
|
24
|
+
console.log(`=== L0/L1/L2 metadata backfill${dryRun ? " (dry run)" : ""} ===\n`);
|
|
25
|
+
|
|
26
|
+
// Read all rows with metadata
|
|
27
|
+
const allRows = await table.query()
|
|
28
|
+
.select(["id", "text", "vector", "category", "scope", "importance", "timestamp", "metadata"])
|
|
29
|
+
.toArray();
|
|
30
|
+
|
|
31
|
+
console.log(` Total entries: ${allRows.length}`);
|
|
32
|
+
|
|
33
|
+
const toMigrate: any[] = [];
|
|
34
|
+
|
|
35
|
+
for (const row of allRows) {
|
|
36
|
+
const metaStr = row.metadata as string;
|
|
37
|
+
if (!metaStr) continue;
|
|
38
|
+
|
|
39
|
+
let meta: Record<string, unknown>;
|
|
40
|
+
try { meta = JSON.parse(metaStr); } catch { continue; }
|
|
41
|
+
|
|
42
|
+
const hasShortL0 = typeof meta.l0 === "string" && (meta.l0 as string).length > 0;
|
|
43
|
+
const hasShortL1 = typeof meta.l1 === "string" && (meta.l1 as string).length > 0;
|
|
44
|
+
const hasLongL0 = typeof meta.l0_abstract === "string";
|
|
45
|
+
const hasLongL1 = typeof meta.l1_overview === "string";
|
|
46
|
+
|
|
47
|
+
if (!hasShortL0 && !hasShortL1) continue;
|
|
48
|
+
if (hasLongL0 && hasLongL1) continue;
|
|
49
|
+
|
|
50
|
+
// Migrate field names
|
|
51
|
+
if (hasShortL0 && !hasLongL0) meta.l0_abstract = meta.l0;
|
|
52
|
+
if (hasShortL1 && !hasLongL1) meta.l1_overview = meta.l1;
|
|
53
|
+
if (!meta.l2_content && row.text) meta.l2_content = row.text;
|
|
54
|
+
delete meta.l0;
|
|
55
|
+
delete meta.l1;
|
|
56
|
+
|
|
57
|
+
toMigrate.push({
|
|
58
|
+
id: row.id,
|
|
59
|
+
text: row.text,
|
|
60
|
+
vector: Array.from(row.vector as Iterable<number>),
|
|
61
|
+
category: row.category,
|
|
62
|
+
scope: row.scope ?? "",
|
|
63
|
+
importance: Number(row.importance),
|
|
64
|
+
timestamp: Number(row.timestamp),
|
|
65
|
+
metadata: JSON.stringify(meta),
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
console.log(` Need migration: ${toMigrate.length}`);
|
|
70
|
+
console.log(` Skipped: ${allRows.length - toMigrate.length}`);
|
|
71
|
+
|
|
72
|
+
if (dryRun) {
|
|
73
|
+
console.log(`\n (dry run — no changes made)`);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (toMigrate.length === 0) {
|
|
78
|
+
console.log(`\n Nothing to do.`);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Batch delete + batch add
|
|
83
|
+
const batchSize = 1000;
|
|
84
|
+
for (let i = 0; i < toMigrate.length; i += batchSize) {
|
|
85
|
+
const batch = toMigrate.slice(i, i + batchSize);
|
|
86
|
+
const ids = batch.map((r: any) => `'${r.id.replace(/'/g, "''")}'`).join(",");
|
|
87
|
+
await table.delete(`id IN (${ids})`);
|
|
88
|
+
await table.add(batch);
|
|
89
|
+
console.log(` Batch ${Math.floor(i / batchSize) + 1}: migrated ${batch.length} entries`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
console.log(`\nDone. Migrated ${toMigrate.length} entries.`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
main().catch(err => {
|
|
96
|
+
console.error("Backfill failed:", err);
|
|
97
|
+
process.exit(1);
|
|
98
|
+
});
|