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.
- package/.env +4 -0
- package/CLAUDE.md +1 -1
- package/README.md +30 -5
- package/README_CN.md +30 -5
- package/config.json +55 -0
- package/connectors/examples/email-adapter.ts +73 -0
- package/connectors/examples/logs-adapter.ts +103 -0
- package/connectors/examples/rss-adapter.ts +95 -0
- package/logs/daily-recall.error.log +0 -0
- package/logs/daily-recall.log +60 -0
- package/logs/ingest-2026-04-11.log +110 -0
- package/logs/ingest-2026-04-12.log +90 -0
- package/logs/ingest-2026-04-13.log +87 -0
- package/logs/launchagent-stderr.log +0 -0
- package/logs/launchagent-stdout.log +0 -0
- package/package.json +1 -1
- package/src/cli.ts +30 -0
- package/src/connector-types.ts +57 -0
- package/src/conversation-importer.ts +25 -1
- package/src/data-checkup.ts +31 -1
- package/src/doctor.ts +29 -0
- package/src/ingest.ts +203 -0
- package/src/mcp-server.ts +2 -2
- package/src/obsidian-connector.ts +282 -0
- package/src/session-schema.ts +2 -2
- package/src/source-heartbeat.ts +108 -0
- package/.claude-plugin/CLAUDE.md +0 -29
- package/.claude-plugin/marketplace.json +0 -18
- package/.dockerignore +0 -11
- package/.github/workflows/ci.yml +0 -28
- package/.mcp.json +0 -9
- package/CHANGELOG.md +0 -51
- package/DEMO.md +0 -94
- package/Dockerfile +0 -20
- package/EVAL.md +0 -89
- package/FAILURES.md +0 -75
- package/OPERATIONS.md +0 -59
- package/ROADMAP.md +0 -245
- package/SKILL.md +0 -250
- package/assets/dashboard.png +0 -0
- package/assets/knowledge-graph.png +0 -0
- package/assets/recallnest-workbench.png +0 -0
- package/assets/screenshots/ui-full.png +0 -0
- package/assets/screenshots/ui-overview.png +0 -0
- package/assets/screenshots/ui-search.png +0 -0
- package/assets/ui/app.js +0 -1031
- package/assets/ui/index.html +0 -224
- package/assets/ui/styles.css +0 -781
- package/assets/wechat-qr.jpg +0 -0
- package/bun.lock +0 -337
- package/daily-reflections/2026-03-05.md +0 -15
- package/daily-reflections/2026-03-06.md +0 -15
- package/daily-reflections/2026-03-07.md +0 -7
- package/daily-reflections/2026-03-08.md +0 -34
- package/daily-reflections/2026-03-09.md +0 -35
- package/daily-reflections/2026-03-10.md +0 -36
- package/daily-reflections/2026-03-11.md +0 -35
- package/daily-reflections/2026-03-12.md +0 -36
- package/daily-reflections/2026-03-13.md +0 -35
- package/daily-reflections/2026-03-14.md +0 -35
- package/daily-reflections/2026-03-15.md +0 -35
- package/daily-reflections/2026-03-16.md +0 -41
- package/daily-reflections/2026-03-17.md +0 -10
- package/daily-reflections/2026-03-18.md +0 -10
- package/daily-reflections/2026-03-19.md +0 -10
- package/daily-reflections/2026-03-20.md +0 -10
- package/daily-reflections/2026-03-21.md +0 -10
- package/daily-reflections/2026-03-22.md +0 -10
- package/daily-reflections/2026-03-23.md +0 -10
- package/daily-reflections/2026-03-24.md +0 -10
- package/daily-reflections/2026-03-25.md +0 -32
- package/daily-reflections/2026-03-26.md +0 -37
- package/daily-reflections/2026-03-27.md +0 -35
- package/daily-reflections/2026-03-28.md +0 -35
- package/daily-reflections/2026-03-29.md +0 -35
- package/daily-reflections/2026-03-30.md +0 -36
- package/daily-reflections/2026-03-31.md +0 -35
- package/daily-reflections/2026-04-01.md +0 -35
- package/daily-reflections/2026-04-02.md +0 -35
- package/daily-reflections/2026-04-03.md +0 -37
- package/daily-reflections/2026-04-04.md +0 -37
- package/daily-reflections/2026-04-05.md +0 -35
- package/daily-reflections/2026-04-06.md +0 -36
- package/daily-reflections/2026-04-07.md +0 -35
- package/daily-reflections/2026-04-08.md +0 -35
- package/daily-reflections/2026-04-12.md +0 -35
- package/data/alias-map.example.json +0 -22
- package/docs/api-reference.md +0 -1291
- package/docs/architecture.md +0 -168
- package/docs/memory-boundary-contract.md +0 -226
- package/docs/memory-categories.md +0 -119
- package/docs/pipeline-audit-ultramemory.md +0 -177
- package/docs/plans/2026-03-08-query-expansion.md +0 -270
- package/docs/plans/2026-03-16-continuity-layer.md +0 -196
- package/docs/plans/2026-04-01-recall-boost.md +0 -100
- package/docs/plans/mcp-tiering-plan.md +0 -126
- package/docs/research/recall-quality-audit-2026-03-22.md +0 -153
- package/docs/self-evolution.md +0 -198
- package/docs/superpowers/plans/2026-03-19-ingest-pipeline-upgrade.md +0 -782
- package/docs/superpowers/plans/2026-04-11-constructive-retrieval-emotion.md +0 -1195
- package/docs/superpowers/specs/2026-03-19-ingest-pipeline-upgrade-design.md +0 -77
- package/docs/superpowers/specs/2026-03-23-pull-claude-desktop-design.md +0 -95
- package/docs/superpowers/specs/2026-04-11-constructive-retrieval-emotion-design.md +0 -398
- package/eval/continuity/results-2026-03-16.md +0 -117
- package/eval/continuity/results-2026-03-19.md +0 -453
- package/eval/continuity/runbook.md +0 -110
- package/eval/continuity/seed-cases.md +0 -54
- package/eval/reports/2026-03-06-abstract-query-baseline.md +0 -96
- package/eval/reports/2026-03-06-aws-ssh-baseline.md +0 -82
- package/eval/reports/2026-03-06-baseline.md +0 -82
- package/eval/reports/query-expansion.md +0 -138
- package/glama.json +0 -6
- package/lm +0 -19
- package/plan-philosophy-upgrades.md +0 -363
- package/plan-product-upgrades.md +0 -155
- package/plan-v1.2-distributable.md +0 -105
- package/plan.md +0 -140
- package/research-memory-evolution.md +0 -440
- package/research-rl-agent-memory.md +0 -330
- package/scripts/archive-distilled-junk.ts +0 -116
- package/scripts/backfill-anchors.ts +0 -130
- package/scripts/backfill-l0l1l2.ts +0 -98
- package/scripts/blind-scan.ts +0 -588
- package/scripts/cleanup-step1-exact-dups.ts +0 -117
- package/scripts/cleanup-step2-template-dups.ts +0 -113
- package/scripts/cleanup-step3-stale-content.ts +0 -149
- package/scripts/cleanup-step4-orphan-scopes.ts +0 -131
- package/scripts/delete-distilled-junk.ts +0 -88
- package/scripts/diagnose-vector-search.ts +0 -132
- package/scripts/distill-facts.ts +0 -305
- package/scripts/health-check.ts +0 -343
- package/scripts/incremental-ingest.sh +0 -71
- package/scripts/migrate-language.ts +0 -75
- package/scripts/mlp-health-check.ts +0 -382
- package/scripts/pull-claude-desktop.ts +0 -515
- package/scripts/re-ingest-cc.sh +0 -66
- package/scripts/rebalance-memory-health.ts +0 -181
- package/scripts/run-desktop-ingest.sh +0 -11
- package/scripts/start-server.sh +0 -12
- package/scripts/verify-emotion-decay.ts +0 -148
- package/scripts/viz-dashboard.html +0 -423
- package/scripts/viz-export.ts +0 -703
- package/src/__tests__/access-tracker-novelty.test.ts +0 -228
- package/src/__tests__/activity-counter.test.ts +0 -96
- package/src/__tests__/admission-control.test.ts +0 -206
- package/src/__tests__/anchor-generator.test.ts +0 -67
- package/src/__tests__/auto-consolidation.test.ts +0 -168
- package/src/__tests__/auto-recall.test.ts +0 -131
- package/src/__tests__/babel-integration.test.ts +0 -139
- package/src/__tests__/batch-dedup.test.ts +0 -65
- package/src/__tests__/capture-engine.test.ts +0 -1144
- package/src/__tests__/capture-heuristic.test.ts +0 -171
- package/src/__tests__/cascade-forget.test.ts +0 -210
- package/src/__tests__/category-min-scores.test.ts +0 -33
- package/src/__tests__/cc8-cc1-essential-context.test.ts +0 -298
- package/src/__tests__/circuit-breaker.test.ts +0 -99
- package/src/__tests__/cluster-consolidation.test.ts +0 -712
- package/src/__tests__/confidence-metadata.test.ts +0 -125
- package/src/__tests__/confidence-tracker.test.ts +0 -249
- package/src/__tests__/conflict-advisor.test.ts +0 -206
- package/src/__tests__/conflict-escalation.test.ts +0 -149
- package/src/__tests__/conflict-lifecycle.test.ts +0 -83
- package/src/__tests__/conflict-output.test.ts +0 -85
- package/src/__tests__/conflict-store.test.ts +0 -374
- package/src/__tests__/consolidation-engine.test.ts +0 -181
- package/src/__tests__/constructive-retrieval.test.ts +0 -509
- package/src/__tests__/context-collapse-renderer.test.ts +0 -214
- package/src/__tests__/context-composer-pins.test.ts +0 -64
- package/src/__tests__/context-composer-task-selection.test.ts +0 -24
- package/src/__tests__/context-reconstructor.test.ts +0 -65
- package/src/__tests__/context-renderer.test.ts +0 -91
- package/src/__tests__/continuity-eval.test.ts +0 -275
- package/src/__tests__/continuity-schema.test.ts +0 -97
- package/src/__tests__/conversation-importer.test.ts +0 -692
- package/src/__tests__/core-recall-eval.test.ts +0 -235
- package/src/__tests__/core-summary.test.ts +0 -109
- package/src/__tests__/data-checkup.test.ts +0 -225
- package/src/__tests__/decay-exemption.test.ts +0 -84
- package/src/__tests__/dedup-actions.test.ts +0 -58
- package/src/__tests__/dedup-guard.test.ts +0 -39
- package/src/__tests__/deterministic-id.test.ts +0 -39
- package/src/__tests__/distill-lock.test.ts +0 -176
- package/src/__tests__/doctor.test.ts +0 -303
- package/src/__tests__/dream-pipeline.test.ts +0 -232
- package/src/__tests__/drill-down.test.ts +0 -108
- package/src/__tests__/embedder.test.ts +0 -122
- package/src/__tests__/emotion-decay.test.ts +0 -46
- package/src/__tests__/emotion-detector.test.ts +0 -56
- package/src/__tests__/emotion-phase1-integration.test.ts +0 -153
- package/src/__tests__/emotion-retrieval.test.ts +0 -56
- package/src/__tests__/entity-resolver.test.ts +0 -58
- package/src/__tests__/ethics-layer.test.ts +0 -476
- package/src/__tests__/event-segmenter.test.ts +0 -153
- package/src/__tests__/feature-flags-integration.test.ts +0 -54
- package/src/__tests__/frequency-tracker.test.ts +0 -113
- package/src/__tests__/graph-export.test.ts +0 -489
- package/src/__tests__/hotness-blend.test.ts +0 -76
- package/src/__tests__/ingest.test.ts +0 -360
- package/src/__tests__/interference-detector.test.ts +0 -203
- package/src/__tests__/kg-extractor.test.ts +0 -184
- package/src/__tests__/kg-store.test.ts +0 -198
- package/src/__tests__/llm-consolidation.test.ts +0 -226
- package/src/__tests__/mcp-efficiency.test.ts +0 -288
- package/src/__tests__/memory-boundaries.test.ts +0 -237
- package/src/__tests__/memory-evolution-b2-b3-e1.test.ts +0 -243
- package/src/__tests__/memory-evolution.test.ts +0 -271
- package/src/__tests__/memory-health-rebalance.test.ts +0 -144
- package/src/__tests__/memory-lint.test.ts +0 -271
- package/src/__tests__/memory-output.test.ts +0 -215
- package/src/__tests__/multi-vector.test.ts +0 -242
- package/src/__tests__/narrative-architecture.test.ts +0 -456
- package/src/__tests__/pending-review.test.ts +0 -77
- package/src/__tests__/post-retrieval-filter.test.ts +0 -178
- package/src/__tests__/ppr-traversal.test.ts +0 -256
- package/src/__tests__/prediction-engine.test.ts +0 -349
- package/src/__tests__/predictive-prospective-memory.test.ts +0 -416
- package/src/__tests__/preference-guard-smoke.test.ts +0 -211
- package/src/__tests__/preference-matcher.test.ts +0 -230
- package/src/__tests__/preference-slots.test.ts +0 -205
- package/src/__tests__/prospective-memory.test.ts +0 -283
- package/src/__tests__/query-entity-detector.test.ts +0 -171
- package/src/__tests__/query-expander-alias.test.ts +0 -89
- package/src/__tests__/query-expander.test.ts +0 -34
- package/src/__tests__/recall-governor.test.ts +0 -227
- package/src/__tests__/recall-mode.test.ts +0 -64
- package/src/__tests__/result-synthesizer.test.ts +0 -198
- package/src/__tests__/resume-context.test.ts +0 -4898
- package/src/__tests__/retrieval-trace.test.ts +0 -213
- package/src/__tests__/retriever-boundary-weight.test.ts +0 -136
- package/src/__tests__/retroactive-boost.test.ts +0 -223
- package/src/__tests__/salience-scoring.test.ts +0 -106
- package/src/__tests__/scope-inventory.test.ts +0 -200
- package/src/__tests__/scope-policy.test.ts +0 -69
- package/src/__tests__/session-checkpoint.test.ts +0 -259
- package/src/__tests__/session-distiller.test.ts +0 -611
- package/src/__tests__/session-gc.test.ts +0 -215
- package/src/__tests__/skill-engine.test.ts +0 -546
- package/src/__tests__/skill-promotion.test.ts +0 -349
- package/src/__tests__/store-scope-audit.test.ts +0 -81
- package/src/__tests__/supersede-chain.test.ts +0 -154
- package/src/__tests__/temporal-parser.test.ts +0 -241
- package/src/__tests__/temporal-validity.test.ts +0 -160
- package/src/__tests__/term-registry.test.ts +0 -121
- package/src/__tests__/tool-output-compressor.test.ts +0 -133
- package/src/__tests__/topic-tag.test.ts +0 -113
- package/src/__tests__/trusted-memory.test.ts +0 -828
- package/src/__tests__/version-manager.test.ts +0 -213
- package/src/__tests__/workflow-observation.test.ts +0 -400
- package/src/__tests__/write-verifier.test.ts +0 -122
|
@@ -1,363 +0,0 @@
|
|
|
1
|
-
# Implementation Plan: Memory Philosophy-Driven RecallNest Upgrades
|
|
2
|
-
|
|
3
|
-
> Date: 2026-04-11
|
|
4
|
-
> Status: ✅ ALL 5 PHASES COMPLETE (commits a9e53d3..d150b8d, 1391 tests / 0 fail)
|
|
5
|
-
> Source: Memory philosophy research map + Codex code analysis + Explorer codebase audit
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Overview
|
|
10
|
-
|
|
11
|
-
Five upgrade phases derived from memory philosophy research, each mapped to concrete code changes in the RecallNest codebase. Phase 1 (Emotional Valence in Decay) is implementation-ready today -- the building blocks exist but are not wired into production paths. Phases 2-5 build outward from that foundation. All phases are designed to be independently mergeable and testable.
|
|
12
|
-
|
|
13
|
-
## Dependency Graph
|
|
14
|
-
|
|
15
|
-
```
|
|
16
|
-
Phase 1 (Emotion Decay) <- standalone, no dependencies
|
|
17
|
-
Phase 2 (Ethics Layer) <- standalone, no dependencies on Phase 1
|
|
18
|
-
Phase 3 (Narrative) <- standalone, enriches Phase 4 if done first
|
|
19
|
-
Phase 4 (Constructive) <- benefits from Phase 3 (narrative siblings), Phase 1 (emotion salience)
|
|
20
|
-
Phase 5 (Predictive) <- benefits from Phase 4 (reconstruction surface)
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
Phases 1, 2, and 3 can run in parallel. Phase 4 benefits from all three. Phase 5 builds on Phase 4.
|
|
24
|
-
|
|
25
|
-
## Time Estimates
|
|
26
|
-
|
|
27
|
-
| Phase | Estimated Effort | Complexity |
|
|
28
|
-
|-------|-----------------|------------|
|
|
29
|
-
| Phase 1 | 3-4 hours | Low -- wiring existing code |
|
|
30
|
-
| Phase 2 | 2-3 days | Medium -- new forget engine + lifecycle unification |
|
|
31
|
-
| Phase 3 | 2-3 days | Medium -- new metadata layer + write/read points |
|
|
32
|
-
| Phase 4 | 3-4 days | High -- LLM pipeline changes + grounding rewrite |
|
|
33
|
-
| Phase 5 | 2-3 days | Medium -- new prediction engine + surface layer |
|
|
34
|
-
| **Total** | **~12-15 days** | |
|
|
35
|
-
|
|
36
|
-
---
|
|
37
|
-
|
|
38
|
-
## Phase 1: Emotional Valence in Decay (TODAY)
|
|
39
|
-
|
|
40
|
-
### Goal
|
|
41
|
-
Wire the existing emotion-adjusted decay functions (`adjustHalfLifeForEmotion`, `computeArousalBoost`) into the production retrieval and evolution scoring paths. Extend `EmotionMetadata` with `salience` and `source` fields. Recalculate emotion on text updates. Backfill emotion on import.
|
|
42
|
-
|
|
43
|
-
### Current State
|
|
44
|
-
- `emotion-detector.ts` -- keyword heuristic, zero LLM cost, fully tested
|
|
45
|
-
- `decay-engine.ts:99-119` -- `adjustHalfLifeForEmotion()` and `computeArousalBoost()` exist with tests but are NOT called from production code
|
|
46
|
-
- `store.ts:370` -- `detectEmotionIfEnabled()` auto-annotates on `store()`
|
|
47
|
-
- `retriever.ts:261` -- `applyEmotionWeight()` retrieval scoring is live
|
|
48
|
-
- `retriever.ts:1657` -- `applyTimeDecay()` does NOT use emotion-adjusted half-life
|
|
49
|
-
- `memory-evolution.ts:306` -- `computeDecayScore()` has no emotion factor
|
|
50
|
-
- Feature flag: `RECALLNEST_EMOTION_SCORING=true`
|
|
51
|
-
|
|
52
|
-
### Files Changed
|
|
53
|
-
|
|
54
|
-
| File | Function(s) | Change |
|
|
55
|
-
|------|------------|--------|
|
|
56
|
-
| `src/memory-schema.ts` | `EmotionMetadata`, `EmotionMetadataSchema` | Add `salience` and `source` fields |
|
|
57
|
-
| `src/retriever.ts` | `applyTimeDecay()` (line 1657) | Wire `adjustHalfLifeForEmotion()` into half-life computation |
|
|
58
|
-
| `src/memory-evolution.ts` | `computeDecayScore()` (line 306), weight constants | Add emotion salience factor, rebalance weights |
|
|
59
|
-
| `src/store.ts` | `update()` (line 863) | Recalculate emotion when text changes |
|
|
60
|
-
| `src/store.ts` | `importEntry()` (line 433) | Backfill emotion if absent |
|
|
61
|
-
| `src/emotion-detector.ts` | `detectEmotion()` | Compute `salience` from |valence| + arousal |
|
|
62
|
-
| Tests | New + updated | Emotion-decay integration, update re-detection, import backfill |
|
|
63
|
-
|
|
64
|
-
### Steps
|
|
65
|
-
|
|
66
|
-
#### 1.1 Extend EmotionMetadata schema
|
|
67
|
-
**File:** `src/memory-schema.ts` (lines 40-53)
|
|
68
|
-
|
|
69
|
-
- [x] Add `salience?: number` field to `EmotionMetadata` interface (0-1 composite of |valence| + arousal)
|
|
70
|
-
- [x] Add `source?: "keyword" | "llm" | "user"` field to `EmotionMetadata` interface
|
|
71
|
-
- [x] Update `EmotionMetadataSchema` Zod object to include `salience: z.number().min(0).max(1).optional()` and `source: z.enum(["keyword", "llm", "user"]).optional()`
|
|
72
|
-
- [x] Verify `parseEmotion()` still works with old data (no salience/source)
|
|
73
|
-
- **Why:** Salience is the single composite signal that decay and evolution scoring will consume. Source enables future LLM-based emotion detection without breaking keyword entries.
|
|
74
|
-
- **Risk:** Low -- additive optional fields, backward compatible
|
|
75
|
-
|
|
76
|
-
#### 1.2 Compute salience in detectEmotion
|
|
77
|
-
**File:** `src/emotion-detector.ts`, function `detectEmotion()` (line 62)
|
|
78
|
-
|
|
79
|
-
- [x] After computing `valence` and `arousal`, compute `salience = clamp((Math.abs(valence) + arousal) / 2, 0, 1)`
|
|
80
|
-
- [x] Add `salience` and `source: "keyword"` to the returned `EmotionMetadata` object
|
|
81
|
-
- [x] Update `detectEmotionIfEnabled()` -- no change needed (passes through)
|
|
82
|
-
- **Why:** Decay engine needs a single 0-1 signal, not separate valence/arousal. Formula: average of emotional intensity and arousal, giving equal weight to "how emotional" and "how urgent."
|
|
83
|
-
- **Risk:** Low -- pure addition to return value
|
|
84
|
-
|
|
85
|
-
#### 1.3 Wire emotion into applyTimeDecay
|
|
86
|
-
**File:** `src/retriever.ts`, method `applyTimeDecay()` (line 1657)
|
|
87
|
-
|
|
88
|
-
- [x] Import `adjustHalfLifeForEmotion` from `decay-engine.ts` and `parseEmotion` from `memory-schema.ts`
|
|
89
|
-
- [x] At line 1670-1672 (after `this.accessTracker.computeEffectiveHalfLife()`), add emotion adjustment: if `isEmotionScoringEnabled()`, parse emotion from `r.entry.metadata`, call `adjustHalfLifeForEmotion(halfLife, emotion)` to get final half-life
|
|
90
|
-
- [x] Guard behind `isEmotionScoringEnabled()` flag check
|
|
91
|
-
- [x] The arousal boost (`computeArousalBoost()`) applies to score before decay
|
|
92
|
-
|
|
93
|
-
**Current code pattern:**
|
|
94
|
-
```typescript
|
|
95
|
-
const halfLife = this.accessTracker
|
|
96
|
-
? this.accessTracker.computeEffectiveHalfLife(baseHalfLife, r.entry.metadata)
|
|
97
|
-
: baseHalfLife;
|
|
98
|
-
const tier = resolveTier(r.entry.metadata);
|
|
99
|
-
const factor = weibullDecay(ageDays, halfLife, tier);
|
|
100
|
-
return { ...r, score: clamp01(r.score * factor, r.score * 0.3) };
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
**Target code:**
|
|
104
|
-
```typescript
|
|
105
|
-
let halfLife = this.accessTracker
|
|
106
|
-
? this.accessTracker.computeEffectiveHalfLife(baseHalfLife, r.entry.metadata)
|
|
107
|
-
: baseHalfLife;
|
|
108
|
-
// HP-emo: Emotion-adjusted half-life — strong emotion slows forgetting
|
|
109
|
-
const emotion = isEmotionScoringEnabled() ? parseEmotion(r.entry.metadata) : null;
|
|
110
|
-
if (emotion) {
|
|
111
|
-
halfLife = adjustHalfLifeForEmotion(halfLife, emotion);
|
|
112
|
-
}
|
|
113
|
-
const tier = resolveTier(r.entry.metadata);
|
|
114
|
-
const factor = weibullDecay(ageDays, halfLife, tier);
|
|
115
|
-
const arousalFactor = emotion ? computeArousalBoost(emotion) : 1.0;
|
|
116
|
-
return { ...r, score: clamp01(r.score * arousalFactor * factor, r.score * 0.3) };
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
- **Why:** This is the primary gap -- emotion detection runs on write, emotion weight runs on retrieval scoring, but the decay curve itself ignores emotion. A frustrating debugging session should decay slower than a neutral log entry.
|
|
120
|
-
- **Risk:** Medium -- touches the core scoring pipeline. Parse emotion once per result to avoid double-parse overhead.
|
|
121
|
-
|
|
122
|
-
#### 1.4 Add emotion factor to computeDecayScore
|
|
123
|
-
**File:** `src/memory-evolution.ts`, function `computeDecayScore()` (line 306), constants at lines 292-295
|
|
124
|
-
|
|
125
|
-
- [x] Import `parseEmotion`, `isEmotionScoringEnabled` from `memory-schema.ts`
|
|
126
|
-
- [x] Add optional `metadata?: string` parameter to `computeDecayScore()` (backward compatible)
|
|
127
|
-
- [x] When `isEmotionScoringEnabled()` and metadata is provided, extract salience
|
|
128
|
-
- [x] Rebalance weights from `0.2/0.3/0.5` to `0.15/0.25/0.45/0.15`:
|
|
129
|
-
```typescript
|
|
130
|
-
const EMOTION_WEIGHT = isEmotionScoringEnabled() ? 0.15 : 0;
|
|
131
|
-
const TIME_W = isEmotionScoringEnabled() ? 0.15 : 0.2;
|
|
132
|
-
const FREQ_W = isEmotionScoringEnabled() ? 0.25 : 0.3;
|
|
133
|
-
const IMP_W = isEmotionScoringEnabled() ? 0.45 : 0.5;
|
|
134
|
-
// Final: TIME_W * timeDecay + FREQ_W * frequencyScore + IMP_W * importance + EMOTION_WEIGHT * salience
|
|
135
|
-
```
|
|
136
|
-
- [x] Update all callers to pass metadata where available:
|
|
137
|
-
- `auto-gc.ts:142` -- pass `entry.metadata`
|
|
138
|
-
- `retriever.ts:1712` (applyEvolutionDecayBlend) -- pass `r.entry.metadata`
|
|
139
|
-
- **Why:** The evolution decay score determines GC archival and evolution blend. Without emotion, high-emotion events get same decay as routine logs.
|
|
140
|
-
- **Risk:** Medium -- changes GC archival threshold behavior. Emotional memories will resist archival slightly more (desirable).
|
|
141
|
-
|
|
142
|
-
#### 1.5 Re-detect emotion on text update
|
|
143
|
-
**File:** `src/store.ts`, method `update()` (line 863)
|
|
144
|
-
|
|
145
|
-
- [x] After building the `updated` entry, if `updates.text` is provided (text changed), re-run emotion detection:
|
|
146
|
-
```typescript
|
|
147
|
-
if (updates.text) {
|
|
148
|
-
const emotionResult = detectEmotionIfEnabled(updated.text);
|
|
149
|
-
if (emotionResult) {
|
|
150
|
-
const meta = JSON.parse(updated.metadata || "{}");
|
|
151
|
-
meta.emotion = emotionResult;
|
|
152
|
-
updated.metadata = JSON.stringify(meta);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
```
|
|
156
|
-
- [x] Place this BEFORE the `table!.delete` + `table!.add` at lines 918-920
|
|
157
|
-
- **Why:** When text is updated (e.g., supersede-with-edit), stale emotion metadata creates scoring inaccuracy.
|
|
158
|
-
- **Risk:** Low -- only fires when text is explicitly changed
|
|
159
|
-
|
|
160
|
-
#### 1.6 Backfill emotion on importEntry
|
|
161
|
-
**File:** `src/store.ts`, method `importEntry()` (line 433)
|
|
162
|
-
|
|
163
|
-
- [x] After building `full` entry, check if emotion is already present in metadata. If not, detect and inject:
|
|
164
|
-
```typescript
|
|
165
|
-
const metaParsed = JSON.parse(full.metadata || "{}");
|
|
166
|
-
if (!metaParsed.emotion) {
|
|
167
|
-
const emotionResult = detectEmotionIfEnabled(full.text);
|
|
168
|
-
if (emotionResult) {
|
|
169
|
-
metaParsed.emotion = emotionResult;
|
|
170
|
-
full.metadata = JSON.stringify(metaParsed);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
```
|
|
174
|
-
- **Why:** Imported entries may pre-date emotion detection. Backfilling ensures all entries have emotion metadata.
|
|
175
|
-
- **Risk:** Low -- only adds when absent, never overwrites
|
|
176
|
-
|
|
177
|
-
#### 1.7 Tests
|
|
178
|
-
- [x] **emotion-decay.test.ts**: Add test that `salience` is present in `detectEmotion()` output and matches expected formula
|
|
179
|
-
- [x] **emotion-decay.test.ts**: Add test that `source` field is `"keyword"` in `detectEmotion()` output
|
|
180
|
-
- [x] **New: emotion-evolution-decay.test.ts**: Test `computeDecayScore` with emotion metadata yields higher score than without
|
|
181
|
-
- [x] **New: emotion-evolution-decay.test.ts**: Test backward compat -- no metadata param still works
|
|
182
|
-
- [x] **New: emotion-evolution-decay.test.ts**: Test weight rebalancing (weights sum to 1.0)
|
|
183
|
-
- [x] **Extend retriever tests**: Two entries, same age/importance/frequency, different emotion -- emotional one scores higher after `applyTimeDecay`
|
|
184
|
-
- [x] **Store tests**: Verify `update()` with text change re-detects emotion
|
|
185
|
-
- [x] **Store tests**: Verify `importEntry()` backfills emotion when absent, preserves when present
|
|
186
|
-
- [x] Run `bun test` -- all 1000+ tests must pass
|
|
187
|
-
|
|
188
|
-
### Verification
|
|
189
|
-
1. `bun test` -- full green, baseline maintained
|
|
190
|
-
2. Manual check: store emotional memory, retrieve at simulated t=30d, confirm higher score vs neutral
|
|
191
|
-
3. Check `computeDecayScore` output for emotional vs neutral with same evo params
|
|
192
|
-
|
|
193
|
-
### Risks for Phase 1
|
|
194
|
-
- **Double-parse overhead in applyTimeDecay**: Parse emotion once per result, pass to both functions
|
|
195
|
-
- **Weight rebalancing changes GC behavior**: Test with existing GC tests
|
|
196
|
-
- **Feature flag dependency**: All changes gated by `RECALLNEST_EMOTION_SCORING=true`. Flag off = identical to current
|
|
197
|
-
|
|
198
|
-
---
|
|
199
|
-
|
|
200
|
-
## Phase 2: Memory Ethics Layer
|
|
201
|
-
|
|
202
|
-
### Goal
|
|
203
|
-
Add privacy tiers, build a proper forget engine with cascade deletion, unify lifecycle state inconsistency, expose `forget_memory` MCP tool with audit logging.
|
|
204
|
-
|
|
205
|
-
### Current State
|
|
206
|
-
- `cascade-forget.ts:91` reads legacy `meta.state` -- inconsistent with `evolution.status`
|
|
207
|
-
- `consolidation-engine.ts:71-77` reads BOTH `isActiveMemory()` and `meta.state`
|
|
208
|
-
- `audit-log.ts` exists but lacks "forget" operation type
|
|
209
|
-
- `KGStore.deleteBySource()` exists at `kg-store.ts:314` but never called from forget path
|
|
210
|
-
- No privacy tier field exists
|
|
211
|
-
|
|
212
|
-
### Files Changed
|
|
213
|
-
|
|
214
|
-
| File | Function(s) | Change |
|
|
215
|
-
|------|------------|--------|
|
|
216
|
-
| `src/memory-schema.ts` | New types | `PrivacyTier` type + Zod schema |
|
|
217
|
-
| `src/forget-engine.ts` | **New file** | Full cascade forget with KG cleanup, audit, privacy checks |
|
|
218
|
-
| `src/audit-log.ts` | `AuditOperation` type | Add `"forget"` and `"cascade_forget"` operations |
|
|
219
|
-
| `src/cascade-forget.ts` | `cascadeForget()` | Migrate `meta.state` to `evolution.status` |
|
|
220
|
-
| `src/consolidation-engine.ts` | `isActive()` | Remove legacy `meta.state` double-check |
|
|
221
|
-
| `src/capture-engine.ts` | KG extraction gate | Privacy tier check before KG extraction |
|
|
222
|
-
| `src/mcp-server.ts` | New tool | `forget_memory` MCP tool |
|
|
223
|
-
| `src/store.ts` | `store()`, `StoreMemoryInput` | Accept optional `privacyTier` |
|
|
224
|
-
| Tests | New | forget-engine, privacy-tier, lifecycle-state tests |
|
|
225
|
-
|
|
226
|
-
### Steps
|
|
227
|
-
|
|
228
|
-
#### 2.1 Add PrivacyTier to schema
|
|
229
|
-
- [x] `PrivacyTier` type: `"ephemeral" | "private" | "durable" | "shared"`
|
|
230
|
-
- [x] `PrivacyTierSchema` Zod enum
|
|
231
|
-
- [x] Optional `privacyTier` in `StoreMemoryInputSchema`
|
|
232
|
-
|
|
233
|
-
#### 2.2 Unify lifecycle state
|
|
234
|
-
- [x] `cascade-forget.ts:91` -- replace `meta.state` with `isActiveMemory()`
|
|
235
|
-
- [x] `consolidation-engine.ts:70-77` -- simplify to only `isActiveMemory()`
|
|
236
|
-
- [x] Grep for any other `meta.state` reads, migrate them all
|
|
237
|
-
|
|
238
|
-
#### 2.3 Extend audit operations
|
|
239
|
-
- [x] Add `"forget"` and `"cascade_forget"` to `AuditOperation` union
|
|
240
|
-
|
|
241
|
-
#### 2.4 Build forget engine (NEW: `src/forget-engine.ts`)
|
|
242
|
-
- [x] `forgetMemory()`: fetch → privacy check → evidence export → KG delete → pin archive → cascade → primary delete → audit
|
|
243
|
-
- [x] `forgetByScope()` for bulk scope-level forget
|
|
244
|
-
- [x] Confirmation gate for `"durable"` entries
|
|
245
|
-
|
|
246
|
-
#### 2.5 Privacy tier gate in capture
|
|
247
|
-
- [x] Before KG extraction, skip if `privacyTier === "ephemeral" | "private"`
|
|
248
|
-
|
|
249
|
-
#### 2.6 Register `forget_memory` MCP tool
|
|
250
|
-
- [x] Schema: `{ memoryId: string, confirm: boolean, reason?: string }`
|
|
251
|
-
- [x] Returns deletion summary + evidence paths
|
|
252
|
-
|
|
253
|
-
#### 2.7 Tests
|
|
254
|
-
- [x] forget-engine: KG cleanup, cascade demotion, audit trail
|
|
255
|
-
- [x] Privacy tier blocks without confirm
|
|
256
|
-
- [x] Evidence export for high-importance memories
|
|
257
|
-
- [x] Consolidation/cascade-forget regression with new `isActiveMemory()`
|
|
258
|
-
- [x] `bun test` full green
|
|
259
|
-
|
|
260
|
-
### Verification
|
|
261
|
-
1. Store memory → extract KG → forget → verify KG triples gone
|
|
262
|
-
2. Audit log shows complete forget trail
|
|
263
|
-
3. `"ephemeral"` memory produces no KG triples
|
|
264
|
-
|
|
265
|
-
---
|
|
266
|
-
|
|
267
|
-
## Phase 3: Autobiographical Narrative Architecture
|
|
268
|
-
|
|
269
|
-
### Goal
|
|
270
|
-
Add orthogonal narrative metadata layer (life-period / general-event / specific-event) on top of existing 6 categories. Enable temporal grouping and narrative retrieval without disrupting category logic.
|
|
271
|
-
|
|
272
|
-
### Current State
|
|
273
|
-
- 6 categories hardcoded across `memory-schema.ts`, `memory-boundaries.ts`, `retriever.ts`, `context-composer.ts` -- **do not modify**
|
|
274
|
-
- `event-segmenter.ts:105` has `segmentEvents()`, `temporal-parser.ts:15` has date parsing
|
|
275
|
-
|
|
276
|
-
### Files Changed
|
|
277
|
-
|
|
278
|
-
| File | Function(s) | Change |
|
|
279
|
-
|------|------------|--------|
|
|
280
|
-
| `src/narrative-schema.ts` | **New file** | Narrative metadata types + Zod schemas |
|
|
281
|
-
| `src/narrative-tagger.ts` | **New file** | Rule-based narrative period/event assignment |
|
|
282
|
-
| `src/capture-engine.ts` | `buildStructuredMetadata()` | Inject narrative metadata |
|
|
283
|
-
| `src/ingest.ts` | `buildIngestedEntry()` | Inject narrative metadata |
|
|
284
|
-
| `src/retriever.ts` | New method | `expandNarrativeSiblings()` |
|
|
285
|
-
| `src/context-composer.ts` | Result rendering | Group by narrative period |
|
|
286
|
-
| `src/memory-output.ts` | Rendering | Narrative period labels |
|
|
287
|
-
| `src/graph-export.ts` | Graph edges | Narrative relationship edges |
|
|
288
|
-
|
|
289
|
-
### Steps
|
|
290
|
-
- [x] 3.1 Define `NarrativeMetadata` interface: `lifePeriodId/Label`, `generalEventId/Label`, `specificEventId/Label`, `startAt`, `endAt`, `sequence`
|
|
291
|
-
- [x] 3.2 Build rule-based narrative tagger (scope prefix, temporal clustering, keyword signals)
|
|
292
|
-
- [x] 3.3 Inject narrative at write points (`capture-engine.ts:140`, `ingest.ts:662`)
|
|
293
|
-
- [x] 3.4 `expandNarrativeSiblings()` in retriever: pull entries sharing same `generalEventId`
|
|
294
|
-
- [x] 3.5 Rendering updates: group by `lifePeriodLabel`, narrative edges in graph export
|
|
295
|
-
- [x] 3.6 Tests + `bun test` full green
|
|
296
|
-
|
|
297
|
-
---
|
|
298
|
-
|
|
299
|
-
## Phase 4: Constructive Retrieval
|
|
300
|
-
|
|
301
|
-
### Goal
|
|
302
|
-
Replace "top-k then summarize" with multi-source candidate expansion + grounded reconstruction. Return reconstruction as first-class object.
|
|
303
|
-
|
|
304
|
-
### Current State
|
|
305
|
-
- `context-reconstructor.ts:91` exists, `retriever.ts:706` `runReconstruction()` exists
|
|
306
|
-
- `mcp-server.ts:888` supports `reconstruct=true`
|
|
307
|
-
- But: only top-k summarize, `metadata._reconstruction` is hacky, `computeCoverage()` is lexical
|
|
308
|
-
|
|
309
|
-
### Steps
|
|
310
|
-
- [x] 4.1 Define `ReconstructionOutput` with sources, confidence, contradictions
|
|
311
|
-
- [x] 4.2 Add candidate expansion: KG neighbors + evolution chains + cluster members + narrative siblings
|
|
312
|
-
- [x] 4.3 Replace lexical coverage with source-map grounding + contradiction detection
|
|
313
|
-
- [x] 4.4 Return reconstruction as first-class object (remove `metadata._reconstruction` hack)
|
|
314
|
-
- [x] 4.5 Update MCP rendering for new output shape
|
|
315
|
-
- [x] 4.6 Pass checkpoint context (openLoops, nextActions) into reconstruction prompt
|
|
316
|
-
- [x] 4.7 Tests + `bun test` full green
|
|
317
|
-
|
|
318
|
-
---
|
|
319
|
-
|
|
320
|
-
## Phase 5: Predictive Prospective Memory
|
|
321
|
-
|
|
322
|
-
### Goal
|
|
323
|
-
Evolve `prospective-memory.ts` from explicit reminders to include pattern-predicted suggestions. Surface behavioral insights as ephemeral predicted reminders.
|
|
324
|
-
|
|
325
|
-
### Current State
|
|
326
|
-
- `prospective-memory.ts` -- `setReminder()`, `checkTriggers()`, `fireReminder()` explicit only
|
|
327
|
-
- Behavioral signals: checkpoint openLoops, workflow observations, frequency tracker, access tracker, topic tags
|
|
328
|
-
|
|
329
|
-
### Steps
|
|
330
|
-
- [x] 5.1 Extend `ProspectiveMetadata` with `source`, `confidence`, `evidence`, `lastSuggestedAt`, `acceptedAt`
|
|
331
|
-
- [x] 5.2 Build `prediction-engine.ts`: collect signals, score predictions, threshold at confidence >= 0.6
|
|
332
|
-
- [x] 5.3 `suggestPredictedReminders()`: deduplicate vs existing, store as ephemeral, auto-expire 7d
|
|
333
|
-
- [x] 5.4 Surface in `search_memory` as separate "Suggested Reminders" section
|
|
334
|
-
- [x] 5.5 Acceptance/promotion flow: repeated/accepted → promote to explicit; ignored → demote
|
|
335
|
-
- [x] 5.6 Tests + `bun test` full green
|
|
336
|
-
|
|
337
|
-
---
|
|
338
|
-
|
|
339
|
-
## Global Risks & Mitigations
|
|
340
|
-
|
|
341
|
-
| Risk | Impact | Mitigation |
|
|
342
|
-
|------|--------|-----------|
|
|
343
|
-
| Feature flag proliferation | Complexity | Phase 1-2 reuse `RECALLNEST_EMOTION_SCORING`. Phase 3-5 add `RECALLNEST_NARRATIVE_MODE` and `RECALLNEST_PREDICTIVE_MEMORY` |
|
|
344
|
-
| Metadata JSON bloat | Storage + parse cost | Each phase adds ~100 bytes/entry. Total metadata stays under 2KB |
|
|
345
|
-
| Scoring formula instability | Retrieval quality regression | Every weight change gated by feature flag and tested against eval cases |
|
|
346
|
-
| LLM cost creep (Phase 4-5) | Token spend | Phase 1-3 zero LLM. Phase 4 reuses existing reconstruction budget. Phase 5 zero LLM (heuristic) |
|
|
347
|
-
|
|
348
|
-
---
|
|
349
|
-
|
|
350
|
-
## Success Criteria
|
|
351
|
-
|
|
352
|
-
- [x] Phase 1: Emotional memories decay 20-30% slower than neutral memories of same age
|
|
353
|
-
- [x] Phase 1: `computeDecayScore` with emotion gives higher scores for high-salience memories
|
|
354
|
-
- [x] Phase 1: All existing tests pass, emotion-decay tests extended
|
|
355
|
-
- [x] Phase 2: `forget_memory` MCP tool deletes entry + KG triples + cascade demotes + audit logs
|
|
356
|
-
- [x] Phase 2: No more `meta.state` reads anywhere in codebase (all `evolution.status`)
|
|
357
|
-
- [x] Phase 3: Ingested sessions have narrative metadata with period/event IDs
|
|
358
|
-
- [x] Phase 3: Search returns narrative siblings alongside direct matches
|
|
359
|
-
- [x] Phase 4: Reconstruction uses expanded candidate set (KG + evolution + cluster)
|
|
360
|
-
- [x] Phase 4: Reconstruction is first-class return object, not metadata hack
|
|
361
|
-
- [x] Phase 5: Predicted reminders surface from behavioral signals
|
|
362
|
-
- [x] Phase 5: Predictions auto-expire and respect acceptance/rejection
|
|
363
|
-
- [x] All phases: `bun test` passes with baseline maintained or increased
|
package/plan-product-upgrades.md
DELETED
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
# RecallNest 产品化升级实施计划
|
|
2
|
-
|
|
3
|
-
## 目标
|
|
4
|
-
|
|
5
|
-
把 RecallNest 从"引擎很强但用户无感"变成"用户能看到记忆在成长"。
|
|
6
|
-
|
|
7
|
-
## 四个升级(按优先级)
|
|
8
|
-
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
### Upgrade 1: SKILL.md — 记忆伙伴使用协议
|
|
12
|
-
|
|
13
|
-
**做什么**:在 repo 根目录创建 `SKILL.md`,教 LLM 怎么当好记忆伙伴(不只是 API 文档)。
|
|
14
|
-
|
|
15
|
-
**内容结构**:
|
|
16
|
-
- Session Protocol(resume → work → checkpoint)
|
|
17
|
-
- Onboarding Flow(首次检测:memory_stats 为 0 时引导)
|
|
18
|
-
- Memory Feedback(store 后回显,search 后展示匹配)
|
|
19
|
-
- Tool Decision Tree(什么时候 store vs checkpoint vs pin)
|
|
20
|
-
- Weekly Health Check(data_checkup + dream + lint)
|
|
21
|
-
|
|
22
|
-
**改动**:
|
|
23
|
-
- 新建 `SKILL.md`(~250 行 markdown)
|
|
24
|
-
- 零代码改动
|
|
25
|
-
|
|
26
|
-
**风险**:低。纯文档。
|
|
27
|
-
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
### Upgrade 2: Memory Lint — 记忆体检
|
|
31
|
-
|
|
32
|
-
**做什么**:新增 MCP tool + CLI 命令,对记忆做质量自检。
|
|
33
|
-
|
|
34
|
-
**检查项**:
|
|
35
|
-
| 检查 | 复用什么 | 怎么做 |
|
|
36
|
-
|------|---------|--------|
|
|
37
|
-
| 矛盾检测 | `detectHeuristicContradiction`(consolidation-engine.ts) | 同 scope 同 category 内两两比较 |
|
|
38
|
-
| 重复检测 | `cosineSimilarity`(multi-vector.ts) | 向量相似度 > 0.92 的配对 |
|
|
39
|
-
| 陈旧检测 | `parseEvolution` 的 accessCount/lastAccessedAt | 90 天未被召回 + accessCount ≤ 1 |
|
|
40
|
-
| 孤儿检测 | consolidatedInto 指向的 ID | 不存在的引用 |
|
|
41
|
-
| 健康分 | 综合以上 | 100 - (矛盾×10 + 重复×5 + 陈旧×2 + 孤儿×3) |
|
|
42
|
-
|
|
43
|
-
**改动**:
|
|
44
|
-
- 新建 `src/memory-lint.ts`(~180 行)
|
|
45
|
-
- 新建 `src/__tests__/memory-lint.test.ts`(~150 行)
|
|
46
|
-
- 改 `src/mcp-server.ts`:注册 `memory_lint` tool(~25 行)
|
|
47
|
-
- 改 `src/cli.ts`:增加 `lint` 命令(~30 行)
|
|
48
|
-
- 改 `src/api-server.ts`:增加 `GET /v1/lint`(~20 行)
|
|
49
|
-
- 改 `src/consolidation-engine.ts`:export `detectHeuristicContradiction`(1 行)
|
|
50
|
-
- 改 `package.json`:增加 `lint:memory` 脚本
|
|
51
|
-
|
|
52
|
-
**性能守卫**:矛盾/重复检测是 O(n²),每个 scope/category 组限 200 条,按 importance 降序取。
|
|
53
|
-
|
|
54
|
-
**预计**:~405 LOC
|
|
55
|
-
|
|
56
|
-
**风险**:中。矛盾检测基于启发式,会有误报,报告中标注"启发式建议"。
|
|
57
|
-
|
|
58
|
-
---
|
|
59
|
-
|
|
60
|
-
### Upgrade 3: Dashboard 仪表盘首页
|
|
61
|
-
|
|
62
|
-
**做什么**:现有 UI(port 4317)只有搜索,加一个 Dashboard 首页 tab。
|
|
63
|
-
|
|
64
|
-
**展示内容**:
|
|
65
|
-
- 总记忆数 + 分类分布(bar chart,纯 CSS 实现,不引入图表库)
|
|
66
|
-
- 本周/本月新增趋势
|
|
67
|
-
- 健康分(来自 Lint)
|
|
68
|
-
- 最近召回 Top N
|
|
69
|
-
- 沉睡记忆列表(90天未召回)
|
|
70
|
-
|
|
71
|
-
**改动**:
|
|
72
|
-
- 改 `src/ui-server.ts`:新增 4 个 API endpoint(~80 行)
|
|
73
|
-
- `GET /api/dashboard-stats`
|
|
74
|
-
- `GET /api/recent-recalls`
|
|
75
|
-
- `GET /api/lint-summary`
|
|
76
|
-
- `GET /api/stale-memories`
|
|
77
|
-
- 改 `assets/ui/index.html`:增加 Dashboard tab(~60 行)
|
|
78
|
-
- 改 `assets/ui/app.js`:Dashboard 渲染逻辑(~120 行)
|
|
79
|
-
- 改 `assets/ui/styles.css`:Dashboard 样式(~80 行)
|
|
80
|
-
|
|
81
|
-
**依赖**:Upgrade 2(Lint 的健康分)。可以先不接 Lint,用 placeholder。
|
|
82
|
-
|
|
83
|
-
**预计**:~340 LOC
|
|
84
|
-
|
|
85
|
-
**风险**:中。Growth trend 需要扫全量 entries 按时间分桶,大库可能慢。缓存 60s 缓解。
|
|
86
|
-
|
|
87
|
-
---
|
|
88
|
-
|
|
89
|
-
### Upgrade 4: HTML 知识图谱
|
|
90
|
-
|
|
91
|
-
**做什么**:把记忆导出为一个交互式 HTML 文件,浏览器打开即可看到力导向图。
|
|
92
|
-
|
|
93
|
-
**节点/边设计**:
|
|
94
|
-
- 节点 = 每条记忆,颜色按 category(profile=金, preferences=蓝, entities=绿, events=灰, cases=红, patterns=紫)
|
|
95
|
-
- 边 = scope 关系 + consolidation 链 + supersede 链 + cluster 关系
|
|
96
|
-
- 支持缩放、拖拽、点击查看详情
|
|
97
|
-
|
|
98
|
-
**改动**:
|
|
99
|
-
- 新建 `src/graph-export.ts`(~250 行)
|
|
100
|
-
- `buildMemoryGraph()`:从 store 构建节点/边
|
|
101
|
-
- `renderGraphHTML()`:生成自包含 HTML(D3.js via CDN,或 `--offline` 内嵌)
|
|
102
|
-
- `exportMemoryGraph()`:写文件到 `data/exports/`
|
|
103
|
-
- 新建 `src/__tests__/graph-export.test.ts`(~100 行)
|
|
104
|
-
- 改 `src/mcp-server.ts`:注册 `export_graph` tool(~25 行)
|
|
105
|
-
- 改 `src/cli.ts`:增加 `graph` 命令(~25 行)
|
|
106
|
-
- 改 `src/ui-server.ts`:增加 `/api/graph` endpoint(~20 行)
|
|
107
|
-
|
|
108
|
-
**默认上限**:200 节点(按 importance 降序),避免图谱变成乱麻。
|
|
109
|
-
|
|
110
|
-
**预计**:~420 LOC
|
|
111
|
-
|
|
112
|
-
**风险**:中高。>100 节点时力导向布局可能卡顿。限制节点数+scope 过滤。
|
|
113
|
-
|
|
114
|
-
---
|
|
115
|
-
|
|
116
|
-
## 实施顺序
|
|
117
|
-
|
|
118
|
-
```
|
|
119
|
-
Phase 1(可独立合并)
|
|
120
|
-
├── 1.1 SKILL.md(无代码依赖)
|
|
121
|
-
└── 1.2 memory-lint.ts + tests
|
|
122
|
-
|
|
123
|
-
Phase 2(依赖 1.2)
|
|
124
|
-
├── 2.1 Lint MCP tool + CLI
|
|
125
|
-
└── 2.2 Lint API endpoint
|
|
126
|
-
|
|
127
|
-
Phase 3(依赖 Phase 2)
|
|
128
|
-
└── 3.1 Dashboard 首页
|
|
129
|
-
|
|
130
|
-
Phase 4(独立,可与 1-3 并行)
|
|
131
|
-
└── 4.1 HTML 知识图谱
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
**可并行**:SKILL.md 和 Graph Export 不依赖其他升级。
|
|
135
|
-
|
|
136
|
-
## 总改动量
|
|
137
|
-
|
|
138
|
-
| 升级 | 新文件 | 改动文件 | 新增 LOC |
|
|
139
|
-
|------|--------|---------|---------|
|
|
140
|
-
| SKILL.md | 1 | 0 | ~250 (markdown) |
|
|
141
|
-
| Memory Lint | 2 | 4 | ~405 |
|
|
142
|
-
| Dashboard | 0 | 4 | ~340 |
|
|
143
|
-
| Knowledge Graph | 2 | 3 | ~420 |
|
|
144
|
-
| **总计** | **5** | **~8** | **~1,415** |
|
|
145
|
-
|
|
146
|
-
## 成功标准
|
|
147
|
-
|
|
148
|
-
- [ ] SKILL.md 覆盖 5 个核心场景
|
|
149
|
-
- [ ] `memory_lint` MCP tool 返回矛盾/重复/陈旧/孤儿数量 + 0-100 健康分
|
|
150
|
-
- [ ] `bun run src/cli.ts lint` CLI 输出相同报告
|
|
151
|
-
- [ ] Dashboard tab 展示总记忆数、分类分布、健康分、沉睡记忆
|
|
152
|
-
- [ ] `bun run src/cli.ts graph` 生成有效 HTML,浏览器打开有交互图谱
|
|
153
|
-
- [ ] 现有 1168 个测试全部通过
|
|
154
|
-
- [ ] 新增测试 > 20 个
|
|
155
|
-
- [ ] 不引入新 npm 依赖
|
|
@@ -1,105 +0,0 @@
|
|
|
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"` 返回有意义结果
|