mirror of
https://github.com/thedotmack/claude-mem
synced 2026-04-25 17:15:04 +02:00
feat(worktree): query plumbing surfaces merged rows under parent project
ObservationCompiler.queryObservationsMulti and querySummariesMulti WHERE clause extended with OR merged_into_project IN (...), so a parent-project read pulls in rows originally written under any child worktree's composite name once merged. SearchManager wraps the Chroma project filter in \$or so semantic search behaves identically. ChromaSync baseMetadata now carries merged_into_project on new embeddings; existing rows are patched retroactively by the adoption engine. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -141,7 +141,8 @@ export function queryObservationsMulti(
|
||||
o.project
|
||||
FROM observations o
|
||||
LEFT JOIN sdk_sessions s ON o.memory_session_id = s.memory_session_id
|
||||
WHERE o.project IN (${projectPlaceholders})
|
||||
WHERE (o.project IN (${projectPlaceholders})
|
||||
OR o.merged_into_project IN (${projectPlaceholders}))
|
||||
AND type IN (${typePlaceholders})
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM json_each(o.concepts)
|
||||
@@ -151,6 +152,7 @@ export function queryObservationsMulti(
|
||||
ORDER BY o.created_at_epoch DESC
|
||||
LIMIT ?
|
||||
`).all(
|
||||
...projects,
|
||||
...projects,
|
||||
...typeArray,
|
||||
...conceptArray,
|
||||
@@ -189,11 +191,12 @@ export function querySummariesMulti(
|
||||
ss.project
|
||||
FROM session_summaries ss
|
||||
LEFT JOIN sdk_sessions s ON ss.memory_session_id = s.memory_session_id
|
||||
WHERE ss.project IN (${projectPlaceholders})
|
||||
WHERE (ss.project IN (${projectPlaceholders})
|
||||
OR ss.merged_into_project IN (${projectPlaceholders}))
|
||||
${platformSource ? "AND COALESCE(s.platform_source, 'claude') = ?" : ''}
|
||||
ORDER BY ss.created_at_epoch DESC
|
||||
LIMIT ?
|
||||
`).all(...projects, ...(platformSource ? [platformSource] : []), config.sessionCount + SUMMARY_LOOKAHEAD) as SessionSummary[];
|
||||
`).all(...projects, ...projects, ...(platformSource ? [platformSource] : []), config.sessionCount + SUMMARY_LOOKAHEAD) as SessionSummary[];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -28,6 +28,7 @@ interface StoredObservation {
|
||||
id: number;
|
||||
memory_session_id: string;
|
||||
project: string;
|
||||
merged_into_project: string | null;
|
||||
text: string | null;
|
||||
type: string;
|
||||
title: string | null;
|
||||
@@ -47,6 +48,7 @@ interface StoredSummary {
|
||||
id: number;
|
||||
memory_session_id: string;
|
||||
project: string;
|
||||
merged_into_project: string | null;
|
||||
request: string | null;
|
||||
investigated: string | null;
|
||||
learned: string | null;
|
||||
@@ -129,11 +131,12 @@ export class ChromaSync {
|
||||
const files_read = parseFileList(obs.files_read);
|
||||
const files_modified = parseFileList(obs.files_modified);
|
||||
|
||||
const baseMetadata: Record<string, string | number> = {
|
||||
const baseMetadata: Record<string, string | number | null> = {
|
||||
sqlite_id: obs.id,
|
||||
doc_type: 'observation',
|
||||
memory_session_id: obs.memory_session_id,
|
||||
project: obs.project,
|
||||
merged_into_project: obs.merged_into_project ?? null,
|
||||
created_at_epoch: obs.created_at_epoch,
|
||||
type: obs.type || 'discovery',
|
||||
title: obs.title || 'Untitled'
|
||||
@@ -190,11 +193,12 @@ export class ChromaSync {
|
||||
private formatSummaryDocs(summary: StoredSummary): ChromaDocument[] {
|
||||
const documents: ChromaDocument[] = [];
|
||||
|
||||
const baseMetadata: Record<string, string | number> = {
|
||||
const baseMetadata: Record<string, string | number | null> = {
|
||||
sqlite_id: summary.id,
|
||||
doc_type: 'session_summary',
|
||||
memory_session_id: summary.memory_session_id,
|
||||
project: summary.project,
|
||||
merged_into_project: summary.merged_into_project ?? null,
|
||||
created_at_epoch: summary.created_at_epoch,
|
||||
prompt_number: summary.prompt_number || 0
|
||||
};
|
||||
@@ -346,6 +350,7 @@ export class ChromaSync {
|
||||
id: observationId,
|
||||
memory_session_id: memorySessionId,
|
||||
project: project,
|
||||
merged_into_project: null,
|
||||
text: null, // Legacy field, not used
|
||||
type: obs.type,
|
||||
title: obs.title,
|
||||
@@ -390,6 +395,7 @@ export class ChromaSync {
|
||||
id: summaryId,
|
||||
memory_session_id: memorySessionId,
|
||||
project: project,
|
||||
merged_into_project: null,
|
||||
request: summary.request,
|
||||
investigated: summary.investigated,
|
||||
learned: summary.learned,
|
||||
|
||||
@@ -170,8 +170,16 @@ export class SearchManager {
|
||||
// Include project in the Chroma where clause to scope vector search.
|
||||
// Without this, larger projects dominate the top-N results and smaller
|
||||
// projects get crowded out before the post-hoc SQLite filter.
|
||||
// Match both native-provenance rows (project) and adopted merged-worktree
|
||||
// rows (merged_into_project) so a parent-project query surfaces its
|
||||
// merged children's observations too.
|
||||
if (options.project) {
|
||||
const projectFilter = { project: options.project };
|
||||
const projectFilter = {
|
||||
$or: [
|
||||
{ project: options.project },
|
||||
{ merged_into_project: options.project }
|
||||
]
|
||||
};
|
||||
whereFilter = whereFilter
|
||||
? { $and: [whereFilter, projectFilter] }
|
||||
: projectFilter;
|
||||
|
||||
Reference in New Issue
Block a user