codesift-mcp 0.17.0 → 0.19.2
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/dist/cli/commands-daemon.d.ts.map +1 -1
- package/dist/cli/commands-daemon.js +32 -0
- package/dist/cli/commands-daemon.js.map +1 -1
- package/dist/cli/commands-maintenance.d.ts.map +1 -1
- package/dist/cli/commands-maintenance.js +173 -3
- package/dist/cli/commands-maintenance.js.map +1 -1
- package/dist/cli/hooks/pre-compact.d.ts.map +1 -1
- package/dist/cli/hooks/pre-compact.js +4 -0
- package/dist/cli/hooks/pre-compact.js.map +1 -1
- package/dist/cli/hooks/session.d.ts.map +1 -1
- package/dist/cli/hooks/session.js +5 -0
- package/dist/cli/hooks/session.js.map +1 -1
- package/dist/cli/hooks/wiki.d.ts +13 -0
- package/dist/cli/hooks/wiki.d.ts.map +1 -1
- package/dist/cli/hooks/wiki.js +19 -2
- package/dist/cli/hooks/wiki.js.map +1 -1
- package/dist/cli/owner-only-file.d.ts +9 -0
- package/dist/cli/owner-only-file.d.ts.map +1 -1
- package/dist/cli/owner-only-file.js +40 -8
- package/dist/cli/owner-only-file.js.map +1 -1
- package/dist/cli/service.d.ts.map +1 -1
- package/dist/cli/service.js +7 -1
- package/dist/cli/service.js.map +1 -1
- package/dist/cli/setup/claude.js +3 -3
- package/dist/cli/setup/claude.js.map +1 -1
- package/dist/cli/setup/codex.js +4 -4
- package/dist/cli/setup/codex.js.map +1 -1
- package/dist/cli/setup/fs.d.ts +2 -0
- package/dist/cli/setup/fs.d.ts.map +1 -1
- package/dist/cli/setup/fs.js +4 -1
- package/dist/cli/setup/fs.js.map +1 -1
- package/dist/cli/setup/gemini.js +4 -4
- package/dist/cli/setup/gemini.js.map +1 -1
- package/dist/cli/setup/hooks.d.ts +10 -0
- package/dist/cli/setup/hooks.d.ts.map +1 -1
- package/dist/cli/setup/hooks.js +25 -3
- package/dist/cli/setup/hooks.js.map +1 -1
- package/dist/instructions.d.ts +22 -1
- package/dist/instructions.d.ts.map +1 -1
- package/dist/instructions.js +61 -1
- package/dist/instructions.js.map +1 -1
- package/dist/lsp/lsp-client.d.ts +1 -1
- package/dist/lsp/lsp-client.d.ts.map +1 -1
- package/dist/lsp/lsp-client.js +2 -1
- package/dist/lsp/lsp-client.js.map +1 -1
- package/dist/lsp/lsp-manager.d.ts.map +1 -1
- package/dist/lsp/lsp-manager.js +10 -2
- package/dist/lsp/lsp-manager.js.map +1 -1
- package/dist/lsp/lsp-servers.d.ts +7 -0
- package/dist/lsp/lsp-servers.d.ts.map +1 -1
- package/dist/lsp/lsp-servers.js +78 -0
- package/dist/lsp/lsp-servers.js.map +1 -1
- package/dist/parser/parser-manager.d.ts.map +1 -1
- package/dist/parser/parser-manager.js +8 -2
- package/dist/parser/parser-manager.js.map +1 -1
- package/dist/register-tool-groups/core/symbols.d.ts.map +1 -1
- package/dist/register-tool-groups/core/symbols.js +71 -6
- package/dist/register-tool-groups/core/symbols.js.map +1 -1
- package/dist/register-tools/discovery.d.ts +7 -0
- package/dist/register-tools/discovery.d.ts.map +1 -1
- package/dist/register-tools/discovery.js +8 -1
- package/dist/register-tools/discovery.js.map +1 -1
- package/dist/search/bm25-store.d.ts +10 -0
- package/dist/search/bm25-store.d.ts.map +1 -1
- package/dist/search/bm25-store.js +140 -10
- package/dist/search/bm25-store.js.map +1 -1
- package/dist/search/bm25.d.ts +22 -0
- package/dist/search/bm25.d.ts.map +1 -1
- package/dist/search/bm25.js +43 -0
- package/dist/search/bm25.js.map +1 -1
- package/dist/server-helpers/cache-report.d.ts +36 -0
- package/dist/server-helpers/cache-report.d.ts.map +1 -0
- package/dist/server-helpers/cache-report.js +26 -0
- package/dist/server-helpers/cache-report.js.map +1 -0
- package/dist/server-helpers/health-vitals.d.ts.map +1 -1
- package/dist/server-helpers/health-vitals.js +19 -11
- package/dist/server-helpers/health-vitals.js.map +1 -1
- package/dist/server-helpers/response-budget.d.ts +24 -0
- package/dist/server-helpers/response-budget.d.ts.map +1 -0
- package/dist/server-helpers/response-budget.js +29 -0
- package/dist/server-helpers/response-budget.js.map +1 -0
- package/dist/server-helpers/response-hints.d.ts.map +1 -1
- package/dist/server-helpers/response-hints.js +43 -0
- package/dist/server-helpers/response-hints.js.map +1 -1
- package/dist/server-helpers/shown-source.d.ts +59 -0
- package/dist/server-helpers/shown-source.d.ts.map +1 -0
- package/dist/server-helpers/shown-source.js +175 -0
- package/dist/server-helpers/shown-source.js.map +1 -0
- package/dist/server-helpers/stdio-envelope.d.ts +31 -0
- package/dist/server-helpers/stdio-envelope.d.ts.map +1 -0
- package/dist/server-helpers/stdio-envelope.js +67 -0
- package/dist/server-helpers/stdio-envelope.js.map +1 -0
- package/dist/server-helpers.d.ts +7 -0
- package/dist/server-helpers.d.ts.map +1 -1
- package/dist/server-helpers.js +51 -10
- package/dist/server-helpers.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +107 -45
- package/dist/server.js.map +1 -1
- package/dist/storage/_shared.d.ts +25 -0
- package/dist/storage/_shared.d.ts.map +1 -1
- package/dist/storage/_shared.js +39 -6
- package/dist/storage/_shared.js.map +1 -1
- package/dist/storage/session-state.d.ts +7 -0
- package/dist/storage/session-state.d.ts.map +1 -1
- package/dist/storage/session-state.js +3 -0
- package/dist/storage/session-state.js.map +1 -1
- package/dist/storage/shared-embedding-cache.d.ts.map +1 -1
- package/dist/storage/shared-embedding-cache.js +153 -2
- package/dist/storage/shared-embedding-cache.js.map +1 -1
- package/dist/storage/usage-tracker.d.ts +11 -0
- package/dist/storage/usage-tracker.d.ts.map +1 -1
- package/dist/storage/usage-tracker.js +18 -0
- package/dist/storage/usage-tracker.js.map +1 -1
- package/dist/tools/conversation-cache.d.ts +23 -3
- package/dist/tools/conversation-cache.d.ts.map +1 -1
- package/dist/tools/conversation-cache.js +141 -4
- package/dist/tools/conversation-cache.js.map +1 -1
- package/dist/tools/conversation-index-tools.d.ts +12 -0
- package/dist/tools/conversation-index-tools.d.ts.map +1 -1
- package/dist/tools/conversation-index-tools.js +315 -4
- package/dist/tools/conversation-index-tools.js.map +1 -1
- package/dist/tools/conversation-search-tools.d.ts +0 -5
- package/dist/tools/conversation-search-tools.d.ts.map +1 -1
- package/dist/tools/conversation-search-tools.js +77 -6
- package/dist/tools/conversation-search-tools.js.map +1 -1
- package/dist/tools/explore-tools.d.ts +9 -0
- package/dist/tools/explore-tools.d.ts.map +1 -0
- package/dist/tools/explore-tools.js +177 -0
- package/dist/tools/explore-tools.js.map +1 -0
- package/dist/tools/graph-tools.d.ts +7 -0
- package/dist/tools/graph-tools.d.ts.map +1 -1
- package/dist/tools/graph-tools.js +36 -0
- package/dist/tools/graph-tools.js.map +1 -1
- package/dist/tools/index-tools/state.d.ts +15 -1
- package/dist/tools/index-tools/state.d.ts.map +1 -1
- package/dist/tools/index-tools/state.js +25 -39
- package/dist/tools/index-tools/state.js.map +1 -1
- package/dist/tools/insights-tools.d.ts.map +1 -1
- package/dist/tools/insights-tools.js +6 -3
- package/dist/tools/insights-tools.js.map +1 -1
- package/dist/utils/import-graph/edge-cache.d.ts.map +1 -1
- package/dist/utils/import-graph/edge-cache.js +9 -1
- package/dist/utils/import-graph/edge-cache.js.map +1 -1
- package/package.json +3 -3
- package/rules/codesift.md +19 -0
- package/rules/codesift.mdc +19 -0
- package/rules/codex.md +19 -0
- package/rules/gemini.md +19 -0
|
@@ -1,6 +1,26 @@
|
|
|
1
|
-
import type
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { type BM25Index } from "../search/bm25.js";
|
|
2
|
+
/**
|
|
3
|
+
* Newest index mtime this cache entry is known to cover, or 0 when unknown.
|
|
4
|
+
*
|
|
5
|
+
* Passed in by the caller because the cache does not know where a conversation repo's index lives;
|
|
6
|
+
* an entry built without one is never considered stale, which is the pre-existing behaviour and the
|
|
7
|
+
* conservative direction for a caller that cannot tell.
|
|
8
|
+
*/
|
|
9
|
+
export declare function getConversationBM25Index(repoName: string, freshAsOfMs?: number): BM25Index | null;
|
|
10
|
+
/**
|
|
11
|
+
* Whether an entry exists at all, without touching recency or freshness.
|
|
12
|
+
*
|
|
13
|
+
* Lets the caller pay for a freshness read ONLY when there is something to invalidate. Asking
|
|
14
|
+
* unconditionally put a `loadIndexSummary` in front of every repo on the pass where all of them miss.
|
|
15
|
+
*/
|
|
16
|
+
export declare function hasConversationBM25Index(repoName: string): boolean;
|
|
17
|
+
export declare function setConversationBM25Index(repoName: string, index: BM25Index, builtAtMs?: number): void;
|
|
18
|
+
/** Entry count and priced bytes, for the cache report on /health. */
|
|
19
|
+
export declare function conversationCacheStats(): {
|
|
20
|
+
bm25: number;
|
|
21
|
+
bm25_bytes: number;
|
|
22
|
+
embeddings: number;
|
|
23
|
+
};
|
|
4
24
|
export declare function loadConversationEmbeddingsCached(embeddingPath: string): Promise<Map<string, Float32Array>>;
|
|
5
25
|
export declare function clearConversationEmbeddingsCacheForTesting(): void;
|
|
6
26
|
//# sourceMappingURL=conversation-cache.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation-cache.d.ts","sourceRoot":"","sources":["../../src/tools/conversation-cache.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"conversation-cache.d.ts","sourceRoot":"","sources":["../../src/tools/conversation-cache.ts"],"names":[],"mappings":"AACA,OAAO,EAA4C,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAqD7F;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,SAAI,GAAG,SAAS,GAAG,IAAI,CAa5F;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAElE;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,SAAa,GAAG,IAAI,CAKzG;AA2CD,qEAAqE;AACrE,wBAAgB,sBAAsB,IAAI;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,CAIA;AAED,wBAAsB,gCAAgC,CACpD,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAwBpC;AAED,wBAAgB,0CAA0C,IAAI,IAAI,CAIjE"}
|
|
@@ -1,11 +1,136 @@
|
|
|
1
1
|
import { stat } from "node:fs/promises";
|
|
2
|
+
import { bm25CacheBudgetBytes, bm25FootprintBytes } from "../search/bm25.js";
|
|
3
|
+
/**
|
|
4
|
+
* BM25 indexes for conversation repos.
|
|
5
|
+
*
|
|
6
|
+
* This is the SECOND cache of BM25 indexes in the process, and it had none of what the first one
|
|
7
|
+
* got: no LRU, no budget, no entry cap, and — unlike its sibling — not even the accidental eviction
|
|
8
|
+
* that used to keep that one small. Nothing has ever removed an entry from it.
|
|
9
|
+
*
|
|
10
|
+
* Its size is not bounded by how many conversation indexes exist on disk either, because
|
|
11
|
+
* `loadConversationIndex` BUILDS the index from symbols rather than reading a persisted one: only 3
|
|
12
|
+
* of 1,258 conversation repos here have a `.bm25.ndjson` at all. What bounds it is how many repos get
|
|
13
|
+
* searched, and `searchAllConversations` searches every one of them in a single `Promise.all`.
|
|
14
|
+
*
|
|
15
|
+
* Measured 2026-09-27, one `search_all_conversations` call on this install:
|
|
16
|
+
*
|
|
17
|
+
* projects_searched 1,258 · 53.7 s · heapUsed 5 MB -> 3,262 MB
|
|
18
|
+
* RETAINED after an explicit GC: 2,784 MB
|
|
19
|
+
* a second identical call: 0.6 s — proving all of it is still referenced
|
|
20
|
+
*
|
|
21
|
+
* The fan-out comment in `searchAllConversations` says "with ~20+ conversation repos". That was true
|
|
22
|
+
* when it was written. Pricing and budget come from `search/bm25.js` so this cache and the code one
|
|
23
|
+
* cannot drift apart on what an index costs.
|
|
24
|
+
*/
|
|
2
25
|
const bm25Indexes = new Map();
|
|
26
|
+
/**
|
|
27
|
+
* Index freshness, so a long-lived process stops answering from a snapshot.
|
|
28
|
+
*
|
|
29
|
+
* The lookup was `if (!bm25) build`, with no revalidation anywhere — so the first search in a process
|
|
30
|
+
* fixed the answer for the life of that process. In the daemon, which had been up 27 hours when this
|
|
31
|
+
* was found, conversation search could not see a single conversation recorded since its first call.
|
|
32
|
+
* That is a correctness defect the memory bound would otherwise have hidden, since eviction also
|
|
33
|
+
* happens to refresh.
|
|
34
|
+
*/
|
|
35
|
+
const indexedAt = new Map();
|
|
3
36
|
const embeddingsCache = new Map();
|
|
4
|
-
|
|
5
|
-
|
|
37
|
+
/**
|
|
38
|
+
* How many conversation embedding maps stay resident.
|
|
39
|
+
*
|
|
40
|
+
* Each load is individually capped by `embeddingMemBudgetBytes()`, which bounds one entry and says
|
|
41
|
+
* nothing about their number — the same "count is not size" mistake ADR-004 fixed for the index
|
|
42
|
+
* cache, inverted. Conversation embeddings are small here (0.03 GB on disk across 1,258 repos), so a
|
|
43
|
+
* modest entry cap is enough; it exists so the failure mode is bounded rather than proportional to
|
|
44
|
+
* how many projects the machine has ever had.
|
|
45
|
+
*/
|
|
46
|
+
const MAX_EMBEDDING_ENTRIES = 64;
|
|
47
|
+
/**
|
|
48
|
+
* Newest index mtime this cache entry is known to cover, or 0 when unknown.
|
|
49
|
+
*
|
|
50
|
+
* Passed in by the caller because the cache does not know where a conversation repo's index lives;
|
|
51
|
+
* an entry built without one is never considered stale, which is the pre-existing behaviour and the
|
|
52
|
+
* conservative direction for a caller that cannot tell.
|
|
53
|
+
*/
|
|
54
|
+
export function getConversationBM25Index(repoName, freshAsOfMs = 0) {
|
|
55
|
+
const index = bm25Indexes.get(repoName);
|
|
56
|
+
if (!index)
|
|
57
|
+
return null;
|
|
58
|
+
const builtAt = indexedAt.get(repoName) ?? 0;
|
|
59
|
+
if (freshAsOfMs > 0 && builtAt > 0 && freshAsOfMs > builtAt) {
|
|
60
|
+
bm25Indexes.delete(repoName);
|
|
61
|
+
indexedAt.delete(repoName);
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
// Re-insert so iteration order is least-recently-used first.
|
|
65
|
+
bm25Indexes.delete(repoName);
|
|
66
|
+
bm25Indexes.set(repoName, index);
|
|
67
|
+
return index;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Whether an entry exists at all, without touching recency or freshness.
|
|
71
|
+
*
|
|
72
|
+
* Lets the caller pay for a freshness read ONLY when there is something to invalidate. Asking
|
|
73
|
+
* unconditionally put a `loadIndexSummary` in front of every repo on the pass where all of them miss.
|
|
74
|
+
*/
|
|
75
|
+
export function hasConversationBM25Index(repoName) {
|
|
76
|
+
return bm25Indexes.has(repoName);
|
|
6
77
|
}
|
|
7
|
-
export function setConversationBM25Index(repoName, index) {
|
|
78
|
+
export function setConversationBM25Index(repoName, index, builtAtMs = Date.now()) {
|
|
79
|
+
bm25Indexes.delete(repoName);
|
|
8
80
|
bm25Indexes.set(repoName, index);
|
|
81
|
+
indexedAt.set(repoName, builtAtMs);
|
|
82
|
+
evictOverBudget(repoName);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Drop least-recently-used entries until the cache fits its budget.
|
|
86
|
+
*
|
|
87
|
+
* The repo being served is never evicted, even alone over budget: otherwise a single large
|
|
88
|
+
* conversation corpus would rebuild and discard its own index on every call.
|
|
89
|
+
*/
|
|
90
|
+
/**
|
|
91
|
+
* Share of the BM25 budget this cache may hold.
|
|
92
|
+
*
|
|
93
|
+
* A quarter, not the whole tier. Conversation search is a secondary retrieval path, and giving it the
|
|
94
|
+
* same budget as the code BM25 cache would put four full-tier budgets in one process (indexes, code
|
|
95
|
+
* BM25, embeddings, conversations) — 4 GB of deliberate residency on a machine this size, which is
|
|
96
|
+
* how a process with correct individual bounds still walks into its heap ceiling.
|
|
97
|
+
*
|
|
98
|
+
* It costs little: a conversation index here averages ~2.2 MB (2,784 MB across 1,258 repos), so a
|
|
99
|
+
* quarter-tier still holds around a hundred of them — the recently-active projects — and a miss costs
|
|
100
|
+
* a rebuild, never an error. `CODESIFT_MAX_CONVERSATION_BM25_CACHE_MB` overrides directly.
|
|
101
|
+
*/
|
|
102
|
+
function conversationBudgetBytes() {
|
|
103
|
+
const raw = process.env["CODESIFT_MAX_CONVERSATION_BM25_CACHE_MB"];
|
|
104
|
+
if (raw !== undefined) {
|
|
105
|
+
const parsed = Number.parseInt(raw, 10);
|
|
106
|
+
if (Number.isFinite(parsed) && parsed > 0)
|
|
107
|
+
return parsed * 1024 * 1024;
|
|
108
|
+
}
|
|
109
|
+
return Math.floor(bm25CacheBudgetBytes() / 4);
|
|
110
|
+
}
|
|
111
|
+
function evictOverBudget(pinned) {
|
|
112
|
+
const budget = conversationBudgetBytes();
|
|
113
|
+
let total = 0;
|
|
114
|
+
for (const index of bm25Indexes.values())
|
|
115
|
+
total += bm25FootprintBytes(index);
|
|
116
|
+
if (total <= budget)
|
|
117
|
+
return;
|
|
118
|
+
for (const [name, index] of bm25Indexes) {
|
|
119
|
+
if (total <= budget)
|
|
120
|
+
break;
|
|
121
|
+
if (name === pinned)
|
|
122
|
+
continue;
|
|
123
|
+
total -= bm25FootprintBytes(index);
|
|
124
|
+
bm25Indexes.delete(name);
|
|
125
|
+
indexedAt.delete(name);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/** Entry count and priced bytes, for the cache report on /health. */
|
|
129
|
+
export function conversationCacheStats() {
|
|
130
|
+
let bytes = 0;
|
|
131
|
+
for (const index of bm25Indexes.values())
|
|
132
|
+
bytes += bm25FootprintBytes(index);
|
|
133
|
+
return { bm25: bm25Indexes.size, bm25_bytes: bytes, embeddings: embeddingsCache.size };
|
|
9
134
|
}
|
|
10
135
|
export async function loadConversationEmbeddingsCached(embeddingPath) {
|
|
11
136
|
let mtimeMs = -1;
|
|
@@ -16,15 +141,27 @@ export async function loadConversationEmbeddingsCached(embeddingPath) {
|
|
|
16
141
|
// Missing files load as an empty embedding map.
|
|
17
142
|
}
|
|
18
143
|
const cached = embeddingsCache.get(embeddingPath);
|
|
19
|
-
if (cached?.mtimeMs === mtimeMs)
|
|
144
|
+
if (cached?.mtimeMs === mtimeMs) {
|
|
145
|
+
embeddingsCache.delete(embeddingPath);
|
|
146
|
+
embeddingsCache.set(embeddingPath, cached);
|
|
20
147
|
return cached.embeddings;
|
|
148
|
+
}
|
|
21
149
|
const { loadEmbeddings } = await import("../storage/embedding-store.js");
|
|
22
150
|
const { embeddingMemBudgetBytes } = await import("../config.js");
|
|
23
151
|
const embeddings = await loadEmbeddings(embeddingPath, embeddingMemBudgetBytes());
|
|
152
|
+
embeddingsCache.delete(embeddingPath);
|
|
24
153
|
embeddingsCache.set(embeddingPath, { mtimeMs, embeddings });
|
|
154
|
+
while (embeddingsCache.size > MAX_EMBEDDING_ENTRIES) {
|
|
155
|
+
const oldest = embeddingsCache.keys().next().value;
|
|
156
|
+
if (oldest === undefined)
|
|
157
|
+
break;
|
|
158
|
+
embeddingsCache.delete(oldest);
|
|
159
|
+
}
|
|
25
160
|
return embeddings;
|
|
26
161
|
}
|
|
27
162
|
export function clearConversationEmbeddingsCacheForTesting() {
|
|
28
163
|
embeddingsCache.clear();
|
|
164
|
+
bm25Indexes.clear();
|
|
165
|
+
indexedAt.clear();
|
|
29
166
|
}
|
|
30
167
|
//# sourceMappingURL=conversation-cache.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation-cache.js","sourceRoot":"","sources":["../../src/tools/conversation-cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"conversation-cache.js","sourceRoot":"","sources":["../../src/tools/conversation-cache.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,6 +9,18 @@ export interface IndexConversationsResult {
|
|
|
9
9
|
compacted_sessions: number;
|
|
10
10
|
/** Wall-clock time for the entire operation (ms). */
|
|
11
11
|
elapsed_ms: number;
|
|
12
|
+
/**
|
|
13
|
+
* True when nothing was re-read because every `.jsonl` matched its recorded mtime.
|
|
14
|
+
*
|
|
15
|
+
* Additive and optional so a caller that does not know about it still reads the counts. It exists
|
|
16
|
+
* because a skip cannot report `compacted_sessions` — that is not stored — and a silent 0 there
|
|
17
|
+
* would be indistinguishable from "scanned, found none".
|
|
18
|
+
*/
|
|
19
|
+
/** True when only the changed sessions were re-extracted rather than the whole directory. */
|
|
20
|
+
incremental?: boolean;
|
|
21
|
+
/** How many sessions were re-extracted or dropped on an incremental pass. */
|
|
22
|
+
changed_sessions?: number;
|
|
23
|
+
unchanged?: boolean;
|
|
12
24
|
}
|
|
13
25
|
/**
|
|
14
26
|
* Index all JSONL conversation session files found in `projectPath`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation-index-tools.d.ts","sourceRoot":"","sources":["../../src/tools/conversation-index-tools.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"conversation-index-tools.d.ts","sourceRoot":"","sources":["../../src/tools/conversation-index-tools.ts"],"names":[],"mappings":"AA0BA,MAAM,WAAW,wBAAwB;IACvC,yDAAyD;IACzD,cAAc,EAAE,MAAM,CAAC;IACvB,mEAAmE;IACnE,aAAa,EAAE,MAAM,CAAC;IACtB,4DAA4D;IAC5D,qBAAqB,EAAE,MAAM,CAAC;IAC9B,6DAA6D;IAC7D,kBAAkB,EAAE,MAAM,CAAC;IAC3B,qDAAqD;IACrD,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;;OAMG;IACH,6FAA6F;IAC7F,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,6EAA6E;IAC7E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAGD;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CACtC,WAAW,CAAC,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAC5B,OAAO,CAAC,wBAAwB,CAAC,CA4EnC;AAgWD;;;;;GAKG;AACH,wBAAsB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE9E;AAED;;;;;;;GAOG;AACH,wBAAsB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB1E"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { readdir, stat, readFile } from "node:fs/promises";
|
|
2
2
|
import { join, relative, basename } from "node:path";
|
|
3
3
|
import { extractConversationSymbols } from "../parser/symbol-extractor.js";
|
|
4
|
-
import { saveIndex, getIndexPath } from "../storage/index-store.js";
|
|
4
|
+
import { saveIndex, getIndexPath, loadIndex, loadIndexSummary, saveIncremental, removeFileFromIndex, } from "../storage/index-store.js";
|
|
5
5
|
import { registerRepo } from "../storage/registry.js";
|
|
6
|
-
import { buildBM25IndexYielding } from "../search/bm25.js";
|
|
6
|
+
import { buildBM25IndexYielding, updateBM25ForFile } from "../search/bm25.js";
|
|
7
|
+
import { loadBM25Index, saveBM25Index } from "../search/bm25-store.js";
|
|
7
8
|
import { loadConfig } from "../config.js";
|
|
8
9
|
import { embedSymbols } from "./index-tools.js";
|
|
9
10
|
import { setConversationBM25Index } from "./conversation-cache.js";
|
|
@@ -24,9 +25,63 @@ export async function indexConversations(projectPath, options) {
|
|
|
24
25
|
// Derive repo name: "conversations/<folder>"
|
|
25
26
|
const repoName = `conversations/${basename(rootPath)}`;
|
|
26
27
|
const indexPath = getIndexPath(config.dataDir, rootPath);
|
|
28
|
+
// Nothing detected change, so every call did everything: read every .jsonl, re-extract every turn,
|
|
29
|
+
// rebuild the BM25 index. `autoDiscoverConversations` runs this on server start, and the largest
|
|
30
|
+
// conversation directory here is 160,626 turns / 72 MB of source whose BM25 build alone measures
|
|
31
|
+
// 35.8 s — paid on every spawn, for a directory that usually gained one session or nothing.
|
|
32
|
+
//
|
|
33
|
+
// It is also what made persisting the index pointless: `persistConversationIndex` stamps
|
|
34
|
+
// `updated_at: Date.now()`, so an unconditional rescan invalidated its own cache every time.
|
|
35
|
+
// `embed` is the ONE thing a skip cannot stand in for. Embedding is opt-in and only an explicit
|
|
36
|
+
// `index_conversations` asks for it, so skipping on "the files did not change" silently drops the
|
|
37
|
+
// work the caller invoked the tool to get — the directory being unchanged says nothing about
|
|
38
|
+
// whether its vectors exist. Found by the cross-model review of this release; it is a regression
|
|
39
|
+
// the fast paths introduced, not pre-existing behaviour.
|
|
40
|
+
const wantsEmbed = options?.embed ?? true;
|
|
41
|
+
const unchanged = wantsEmbed ? null : await conversationsUnchanged(rootPath, indexPath);
|
|
42
|
+
if (unchanged) {
|
|
43
|
+
return {
|
|
44
|
+
sessions_found: unchanged.sessions,
|
|
45
|
+
turns_indexed: unchanged.turns,
|
|
46
|
+
skipped_noise_records: 0,
|
|
47
|
+
compacted_sessions: 0,
|
|
48
|
+
elapsed_ms: Date.now() - startTime,
|
|
49
|
+
unchanged: true,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
// Re-extract only the sessions that moved.
|
|
53
|
+
//
|
|
54
|
+
// The skip above covers a directory nothing touched, which is every project except the one being
|
|
55
|
+
// worked in. The ACTIVE project's directory changes on every turn, so for it the skip can never
|
|
56
|
+
// fire — and a full pass over the largest one here measures 156 s (211 sessions, 164,500 turns).
|
|
57
|
+
// `autoDiscoverConversations` runs on every server spawn, so that was paid per session, on one
|
|
58
|
+
// thread, in the process whose event loop is the bottleneck.
|
|
59
|
+
//
|
|
60
|
+
// A conversation log is append-only and sessions are independent files, which is the case
|
|
61
|
+
// `updateBM25ForFile` already exists for: swap the changed file's symbols in place rather than
|
|
62
|
+
// rebuilding the vocabulary for all 164,500 turns.
|
|
63
|
+
// Same reason the skip is gated above: `incrementalConversationUpdate` already refuses when embedding
|
|
64
|
+
// was asked for (its first guard), and this makes that refusal visible at the call site rather than
|
|
65
|
+
// only inside the callee.
|
|
66
|
+
const incremental = wantsEmbed
|
|
67
|
+
? null
|
|
68
|
+
: await incrementalConversationUpdate(rootPath, repoName, indexPath, options);
|
|
69
|
+
if (incremental) {
|
|
70
|
+
return {
|
|
71
|
+
sessions_found: incremental.sessions,
|
|
72
|
+
turns_indexed: incremental.turns,
|
|
73
|
+
skipped_noise_records: 0,
|
|
74
|
+
// Recomputed from the merged symbols rather than reported as 0. It is one pass over symbols this
|
|
75
|
+
// function already holds, and a silent 0 is indistinguishable from "scanned, found none".
|
|
76
|
+
compacted_sessions: incremental.compacted,
|
|
77
|
+
elapsed_ms: Date.now() - startTime,
|
|
78
|
+
incremental: true,
|
|
79
|
+
changed_sessions: incremental.changed,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
27
82
|
const scan = await scanConversationFiles(rootPath, repoName);
|
|
28
83
|
// Explicit call embeds by default; auto-discovery passes embed:false (see below).
|
|
29
|
-
await persistConversationIndex(rootPath, repoName, indexPath, scan, { embed:
|
|
84
|
+
await persistConversationIndex(rootPath, repoName, indexPath, scan, { embed: wantsEmbed });
|
|
30
85
|
return {
|
|
31
86
|
sessions_found: scan.sessions,
|
|
32
87
|
turns_indexed: scan.turns,
|
|
@@ -35,6 +90,249 @@ export async function indexConversations(projectPath, options) {
|
|
|
35
90
|
elapsed_ms: Date.now() - startTime,
|
|
36
91
|
};
|
|
37
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* Counts from the stored index when the directory is byte-for-byte the same, otherwise null.
|
|
95
|
+
*
|
|
96
|
+
* Compares the SET of `.jsonl` files and each one's mtime against what the index recorded. A
|
|
97
|
+
* conversation log is append-only, so an appended turn moves the mtime; a new session adds a path;
|
|
98
|
+
* a deleted one removes it. Any of those, or a summary that cannot be read, means rescan — the
|
|
99
|
+
* conservative direction, since the cost of rescanning is time and the cost of skipping wrongly is
|
|
100
|
+
* a search that cannot see a conversation.
|
|
101
|
+
*
|
|
102
|
+
* `compacted_sessions` is not stored and cannot be recovered here, so a skip reports 0 for it rather
|
|
103
|
+
* than a number it would have to invent; `unchanged: true` in the result says which kind of answer
|
|
104
|
+
* this is.
|
|
105
|
+
*/
|
|
106
|
+
async function conversationsUnchanged(rootPath, indexPath) {
|
|
107
|
+
let summary;
|
|
108
|
+
try {
|
|
109
|
+
summary = await loadIndexSummary(indexPath);
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
if (!summary || summary.files.length === 0)
|
|
115
|
+
return null;
|
|
116
|
+
let entries;
|
|
117
|
+
try {
|
|
118
|
+
entries = (await readdir(rootPath)).filter((name) => name.endsWith(".jsonl"));
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
if (entries.length !== summary.files.length)
|
|
124
|
+
return null;
|
|
125
|
+
const recorded = new Map();
|
|
126
|
+
for (const file of summary.files) {
|
|
127
|
+
const mtime = file.mtime_ms ?? 0;
|
|
128
|
+
// An index written before mtimes were recorded cannot be compared — rescan rather than guess.
|
|
129
|
+
if (mtime === 0)
|
|
130
|
+
return null;
|
|
131
|
+
recorded.set(file.path, mtime);
|
|
132
|
+
}
|
|
133
|
+
for (const name of entries) {
|
|
134
|
+
const expected = recorded.get(name);
|
|
135
|
+
if (expected === undefined)
|
|
136
|
+
return null;
|
|
137
|
+
try {
|
|
138
|
+
if ((await stat(join(rootPath, name))).mtimeMs !== expected)
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
// Indexed SYMBOLS, which is turns plus one `conversation_summary` per compacted session. The split
|
|
146
|
+
// is not stored per file, and loading every symbol to recover it would cost more than this whole
|
|
147
|
+
// skip saves — so the number is named honestly on `unchanged` rather than silently differing from a
|
|
148
|
+
// scanned pass by the compacted count.
|
|
149
|
+
let symbols = 0;
|
|
150
|
+
for (const file of summary.files)
|
|
151
|
+
symbols += file.symbol_count;
|
|
152
|
+
return { sessions: summary.files.length, turns: symbols };
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Swap the changed sessions into the stored index, or null when that cannot be done safely.
|
|
156
|
+
*
|
|
157
|
+
* Returns null — meaning "fall back to a full pass" — whenever anything is not certainly known: no
|
|
158
|
+
* stored index, an index written before mtimes were recorded, no persisted BM25 index to amend, or
|
|
159
|
+
* too much of the directory changed for amending to be cheaper than rebuilding. Falling back is
|
|
160
|
+
* always correct; amending on a wrong assumption produces an index that searches cleanly and is
|
|
161
|
+
* missing turns.
|
|
162
|
+
*
|
|
163
|
+
* Embeddings deliberately stay on the full path. They are opt-in, they are the expensive part when
|
|
164
|
+
* enabled, and an incremental embed needs its own per-symbol accounting rather than a file-level one.
|
|
165
|
+
*/
|
|
166
|
+
/**
|
|
167
|
+
* Largest share of a conversation directory that is still worth amending file by file.
|
|
168
|
+
*
|
|
169
|
+
* Measured 2026-09-27 on a 15,838-symbol / 788-session index, amending against one clean
|
|
170
|
+
* `buildBM25Index` (4,211 ms):
|
|
171
|
+
*
|
|
172
|
+
* 5% 39 files 183 ms amend wins x22.96
|
|
173
|
+
* 25% 197 files 200 ms amend wins x21.00
|
|
174
|
+
* 50% 394 files 1,639 ms amend wins x2.57
|
|
175
|
+
* 75% 591 files 14,037 ms REBUILD wins x0.30
|
|
176
|
+
* 100% 788 files 22,888 ms REBUILD wins x0.18
|
|
177
|
+
*
|
|
178
|
+
* The crossover is between 50% and 75%, and the amend cost grows SUPERLINEARLY — each amended file is
|
|
179
|
+
* a remove-then-add over the postings maps every other file shares, so the churn compounds. That is
|
|
180
|
+
* why the bound is conservative rather than set at the crossover: past it the penalty is not a few
|
|
181
|
+
* percent, it is 5x.
|
|
182
|
+
*
|
|
183
|
+
* `centrality` is NOT a reason for this bound, though an earlier version of this comment said it was:
|
|
184
|
+
* a conversation index has **zero** centrality entries (measured on two of them), because there is no
|
|
185
|
+
* import graph in a chat log. `compacted_sessions` is not a reason either any more — it is recomputed
|
|
186
|
+
* from the merged symbols.
|
|
187
|
+
*/
|
|
188
|
+
const CONVERSATION_AMEND_MAX_SHARE = 0.5;
|
|
189
|
+
async function incrementalConversationUpdate(rootPath, repoName, indexPath, options) {
|
|
190
|
+
if (options?.embed)
|
|
191
|
+
return null;
|
|
192
|
+
let stored;
|
|
193
|
+
try {
|
|
194
|
+
stored = await loadIndex(indexPath);
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
if (!stored || stored.files.length === 0 || stored.symbols.length === 0)
|
|
200
|
+
return null;
|
|
201
|
+
let entries;
|
|
202
|
+
try {
|
|
203
|
+
entries = (await readdir(rootPath)).filter((name) => name.endsWith(".jsonl"));
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
const recorded = new Map();
|
|
209
|
+
for (const file of stored.files) {
|
|
210
|
+
if ((file.mtime_ms ?? 0) === 0)
|
|
211
|
+
return null;
|
|
212
|
+
recorded.set(file.path, file);
|
|
213
|
+
}
|
|
214
|
+
const present = new Set(entries);
|
|
215
|
+
const removed = [...recorded.keys()].filter((path) => !present.has(path));
|
|
216
|
+
const changed = [];
|
|
217
|
+
for (const name of entries) {
|
|
218
|
+
let mtimeMs;
|
|
219
|
+
try {
|
|
220
|
+
mtimeMs = (await stat(join(rootPath, name))).mtimeMs;
|
|
221
|
+
}
|
|
222
|
+
catch {
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
if (recorded.get(name)?.mtime_ms !== mtimeMs)
|
|
226
|
+
changed.push({ path: name, mtimeMs });
|
|
227
|
+
}
|
|
228
|
+
if (changed.length === 0 && removed.length === 0)
|
|
229
|
+
return null; // the caller's skip already handled this
|
|
230
|
+
// Past this share of the directory, amending stops being cheaper than one clean pass: every amended
|
|
231
|
+
// file costs a remove-then-add over the shared postings maps, which churns the vocabulary, while a
|
|
232
|
+
// full build ingests each symbol once. The bound is measured, not guessed — see
|
|
233
|
+
// CONVERSATION_AMEND_MAX_SHARE.
|
|
234
|
+
if (changed.length + removed.length > Math.max(1, Math.floor(entries.length * CONVERSATION_AMEND_MAX_SHARE))) {
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
const bm25 = await loadBM25Index(indexPath, stored);
|
|
238
|
+
if (!bm25)
|
|
239
|
+
return null;
|
|
240
|
+
const symbolsByFile = new Map();
|
|
241
|
+
for (const symbol of stored.symbols) {
|
|
242
|
+
const list = symbolsByFile.get(symbol.file);
|
|
243
|
+
if (list)
|
|
244
|
+
list.push(symbol);
|
|
245
|
+
else
|
|
246
|
+
symbolsByFile.set(symbol.file, [symbol]);
|
|
247
|
+
}
|
|
248
|
+
const files = new Map(recorded);
|
|
249
|
+
for (const path of removed) {
|
|
250
|
+
updateBM25ForFile(bm25, path, []);
|
|
251
|
+
symbolsByFile.delete(path);
|
|
252
|
+
files.delete(path);
|
|
253
|
+
}
|
|
254
|
+
for (const { path, mtimeMs } of changed) {
|
|
255
|
+
let source;
|
|
256
|
+
try {
|
|
257
|
+
source = await readFile(join(rootPath, path), "utf-8");
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
262
|
+
const symbols = extractConversationSymbols(source, path, repoName);
|
|
263
|
+
updateBM25ForFile(bm25, path, symbols);
|
|
264
|
+
symbolsByFile.set(path, symbols);
|
|
265
|
+
files.set(path, {
|
|
266
|
+
path,
|
|
267
|
+
language: "conversation",
|
|
268
|
+
symbol_count: symbols.length,
|
|
269
|
+
last_modified: mtimeMs,
|
|
270
|
+
mtime_ms: mtimeMs,
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
const mergedSymbols = [];
|
|
274
|
+
let compacted = 0;
|
|
275
|
+
let turns = 0;
|
|
276
|
+
for (const list of symbolsByFile.values()) {
|
|
277
|
+
mergedSymbols.push(...list);
|
|
278
|
+
// `turns_indexed` counts TURNS, and a compacted session also carries one `conversation_summary`
|
|
279
|
+
// symbol. Reporting `mergedSymbols.length` over-counted by exactly the number of compacted
|
|
280
|
+
// sessions — 15,894 against the full path's 15,887 on this machine, with compacted = 7.
|
|
281
|
+
for (const symbol of list) {
|
|
282
|
+
if (symbol.kind === "conversation_turn")
|
|
283
|
+
turns++;
|
|
284
|
+
else if (symbol.kind === "conversation_summary")
|
|
285
|
+
compacted++;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
const mergedFiles = [...files.values()];
|
|
289
|
+
// Write only the rows that moved. `saveIndex` rewrites every symbol of the repo: measured on a
|
|
290
|
+
// 15,838-symbol conversation index, 1,494 ms against **0-1 ms** for `saveIncremental` on one file —
|
|
291
|
+
// and the whole point of this path is that two sessions changed. Deletions go through
|
|
292
|
+
// `removeFileFromIndex`, which also drops the `files[]` row; `saveIncremental` would leave it.
|
|
293
|
+
for (const path of removed)
|
|
294
|
+
await removeFileFromIndex(indexPath, path);
|
|
295
|
+
for (const { path } of changed) {
|
|
296
|
+
await saveIncremental(indexPath, path, symbolsByFile.get(path) ?? [], files.get(path));
|
|
297
|
+
}
|
|
298
|
+
// Both writers stamp `updated_at` themselves, so the value has to be read back rather than assumed:
|
|
299
|
+
// the BM25 header must carry what the database now says, or every later search rejects the file and
|
|
300
|
+
// rebuilds — the exact state this path exists to leave behind.
|
|
301
|
+
let updatedAt = Date.now();
|
|
302
|
+
try {
|
|
303
|
+
updatedAt = (await loadIndexSummary(indexPath))?.updated_at ?? updatedAt;
|
|
304
|
+
}
|
|
305
|
+
catch {
|
|
306
|
+
return null; // cannot prove what the index says; a full pass will rewrite both consistently
|
|
307
|
+
}
|
|
308
|
+
const codeIndex = {
|
|
309
|
+
repo: repoName,
|
|
310
|
+
root: rootPath,
|
|
311
|
+
symbols: mergedSymbols,
|
|
312
|
+
files: mergedFiles,
|
|
313
|
+
created_at: stored.created_at,
|
|
314
|
+
updated_at: updatedAt,
|
|
315
|
+
symbol_count: mergedSymbols.length,
|
|
316
|
+
file_count: mergedFiles.length,
|
|
317
|
+
};
|
|
318
|
+
await saveBM25Index(indexPath, bm25, codeIndex);
|
|
319
|
+
setConversationBM25Index(repoName, bm25, codeIndex.updated_at);
|
|
320
|
+
const meta = {
|
|
321
|
+
name: repoName,
|
|
322
|
+
root: rootPath,
|
|
323
|
+
index_path: indexPath,
|
|
324
|
+
symbol_count: codeIndex.symbol_count,
|
|
325
|
+
file_count: codeIndex.file_count,
|
|
326
|
+
updated_at: codeIndex.updated_at,
|
|
327
|
+
};
|
|
328
|
+
await registerRepo(loadConfig().registryPath, meta);
|
|
329
|
+
return {
|
|
330
|
+
sessions: mergedFiles.length,
|
|
331
|
+
turns,
|
|
332
|
+
changed: changed.length + removed.length,
|
|
333
|
+
compacted,
|
|
334
|
+
};
|
|
335
|
+
}
|
|
38
336
|
async function scanConversationFiles(rootPath, repoName) {
|
|
39
337
|
let entries;
|
|
40
338
|
try {
|
|
@@ -48,7 +346,9 @@ async function scanConversationFiles(rootPath, repoName) {
|
|
|
48
346
|
const filePath = join(rootPath, fileName);
|
|
49
347
|
// Read and extract
|
|
50
348
|
let source;
|
|
349
|
+
let mtimeMs = 0;
|
|
51
350
|
try {
|
|
351
|
+
mtimeMs = (await stat(filePath)).mtimeMs;
|
|
52
352
|
source = await readFile(filePath, "utf-8");
|
|
53
353
|
}
|
|
54
354
|
catch {
|
|
@@ -67,7 +367,12 @@ async function scanConversationFiles(rootPath, repoName) {
|
|
|
67
367
|
path: relPath,
|
|
68
368
|
language: "conversation",
|
|
69
369
|
symbol_count: symbols.length,
|
|
70
|
-
|
|
370
|
+
// The FILE's mtime, not the scan's clock. This was `Date.now()`, which records when the
|
|
371
|
+
// scanner ran and therefore cannot be compared against anything on disk — so a stored
|
|
372
|
+
// conversation index could never be shown to be current, and every scan was a full rescan.
|
|
373
|
+
// `mtime_ms` is the field the type already documents as "for incremental skip".
|
|
374
|
+
last_modified: mtimeMs,
|
|
375
|
+
mtime_ms: mtimeMs,
|
|
71
376
|
};
|
|
72
377
|
scan.files.push(entry);
|
|
73
378
|
}
|
|
@@ -88,6 +393,12 @@ async function persistConversationIndex(rootPath, repoName, indexPath, scan, opt
|
|
|
88
393
|
file_count: scan.files.length,
|
|
89
394
|
};
|
|
90
395
|
await saveIndex(indexPath, codeIndex);
|
|
396
|
+
// Persist the BM25 index beside the code index, with the SAME `codeIndex` object that was just
|
|
397
|
+
// written — `saveBM25Index` stamps its header from it, and `loadBM25Index` refuses a header that
|
|
398
|
+
// disagrees. Writing it here rather than from the search path is what lets a search LOAD the index
|
|
399
|
+
// (4.3x to 20x faster than rebuilding, measured on this machine's three largest conversation
|
|
400
|
+
// directories) instead of tokenising the whole corpus again.
|
|
401
|
+
await saveBM25Index(indexPath, bm25, codeIndex);
|
|
91
402
|
// Embedding conversations is OPT-IN. This used to fire unconditionally and
|
|
92
403
|
// unawaited on every server start (autoDiscoverConversations → here), so each
|
|
93
404
|
// of N concurrent MCP servers began embedding the whole ~/.claude/projects
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation-index-tools.js","sourceRoot":"","sources":["../../src/tools/conversation-index-tools.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"conversation-index-tools.js","sourceRoot":"","sources":["../../src/tools/conversation-index-tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -25,11 +25,6 @@ export declare function searchConversations(query: string, projectPath?: string,
|
|
|
25
25
|
* query once instead of once per conversation repo. */
|
|
26
26
|
queryVec?: Float32Array;
|
|
27
27
|
}): Promise<SearchConversationsResult>;
|
|
28
|
-
/**
|
|
29
|
-
* Search ALL indexed conversation projects at once.
|
|
30
|
-
* Iterates over all `conversations/*` repos in the registry,
|
|
31
|
-
* searches each, merges and re-ranks results.
|
|
32
|
-
*/
|
|
33
28
|
export declare function searchAllConversations(query: string, limit?: number): Promise<SearchConversationsResult & {
|
|
34
29
|
projects_searched: number;
|
|
35
30
|
}>;
|