fix(context): inject project dream namespaces alongside recent raw memory (closes #2834)#2858
fix(context): inject project dream namespaces alongside recent raw memory (closes #2834)#2858rodboev wants to merge 10 commits into
Conversation
Greptile SummaryThis PR fixes a gap where
Confidence Score: 4/5Safe to merge for the primary feature, but users with CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE=true will silently lose the show-last-message capability once any dream row exists. The read-path expansion from queryObservations to queryObservationsMulti works correctly for context injection, and prioritizeProjectRows handles the raw-row guarantee. The one concrete regression is in getPriorSessionMessages: because the prioritized observation list puts dream rows first, find short-circuits on the first dream row (whose session ID is always different from the current user session), constructs a transcript path that does not exist, and returns empty strings — skipping every raw-observation transcript. This silently breaks the show last message feature for any user who has enabled it. Since that setting defaults to false the blast radius is limited, but the regression is real for opted-in users. src/services/context/ObservationCompiler.ts (getPriorSessionMessages) and src/services/context/ContextBuilder.ts (mostRecentObservation = observations[0]) both need to account for dream rows appearing at the top of the prioritized list. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["Hook fires: getProjectContext(cwd)"] --> B{cwd null?}
B -- yes --> C["allProjects = [rawProject]"]
B -- no --> D{isWorktree?}
D -- yes --> E["allProjects = [parent:dream, composite:dream, parent, composite]"]
D -- no --> F["allProjects = [proj:dream, proj]"]
C --> G[generateContext]
E --> G
F --> G
G --> H{"projects.length > 1?"}
H -- "always yes" --> I["queryObservationsMulti + querySummariesMulti"]
I --> K[prioritizeProjectRows]
K --> L{"dream rows exist?"}
L -- yes --> M["emit limit-1 dream rows + at least 1 raw row"]
L -- no --> N["emit limit raw rows"]
M --> O[buildContextOutput]
N --> O
O --> P["getPriorSessionMessages: find first obs != currentSession"]
P --> R["dream row found first, transcript missing, lastMessage empty"]
|
|
Added the worktree composite dream namespace to |
|
Review finding that blocks this one: |
Summary
Distilled memories stored under
<project>:dreamwere absent from normal project context injection because the default query path only used the cwd-derived raw project name. This PR adds the dream namespace to the default project list and keeps a bounded recent raw-memory fallback so distilled context becomes primary without hiding fresh undistilled observations.Why
generateContext()insrc/services/context/ContextBuilder.ts:105-128already supports multi-project queries, andqueryObservationsMulti()/querySummariesMulti()insrc/services/context/ObservationCompiler.ts:88-175already union rows across project lists. The gap was thatgetProjectContext()insrc/utils/project-name.ts:76-96never emitted the companion dream namespace for ordinary project sessions, so the multi-project path was not used for distilled memory at all.Scope
This PR is intentionally read-path only. It does not change how dream rows are written, does not migrate stored project names, and does not inject any unscoped global
dreamnamespace.Risk
The main risk is over-weighting old distilled rows and crowding out fresh raw context. The fix keeps that bounded by preserving a recent raw fallback and by leaving the rendered project label unchanged even though the underlying query list expands.
Verification / Test plan
bun test tests/utils/project-name.test.ts— 18 passed, 2 failed on the pre-existing Windows~expectations that currently expectC:\Users\Rodinstead of the actual basenameRod; the new dream-namespace assertions are green.bun test tests/hooks/file-context.test.ts— 9 passed; file-context requests now carry both the dream namespace and the raw project name.bun test tests/worker/http/routes/search-routes-welcome-hint.test.ts— 4 passed; existing multi-project query handling is unchanged.npm run build— passed; regeneratedplugin/scripts/context-generator.cjsandplugin/scripts/transcript-watcher.cjsfrom the shared project-context/query changes.npm run lint:hook-io && npm run lint:spawn-env— passed.npm run strip-comments:check— fails on the existing repo-wide baseline (Changed: 301in check mode), unrelated to this branch.Closes #2834