claude-local-docs 1.0.13 → 1.0.15
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/.mcp.json +2 -1
- package/README.md +124 -58
- package/commands/fetch-docs.md +54 -28
- package/commands/index-codebase.md +53 -0
- package/dist/code-indexer.d.ts +14 -0
- package/dist/code-indexer.js +519 -0
- package/dist/code-indexer.js.map +1 -0
- package/dist/code-search.d.ts +14 -0
- package/dist/code-search.js +155 -0
- package/dist/code-search.js.map +1 -0
- package/dist/code-store.d.ts +39 -0
- package/dist/code-store.js +206 -0
- package/dist/code-store.js.map +1 -0
- package/dist/code.test.d.ts +7 -0
- package/dist/code.test.js +197 -0
- package/dist/code.test.js.map +1 -0
- package/dist/discovery.js +56 -4
- package/dist/discovery.js.map +1 -1
- package/dist/docs.test.d.ts +7 -0
- package/dist/docs.test.js +105 -0
- package/dist/docs.test.js.map +1 -0
- package/dist/file-walker.d.ts +34 -0
- package/dist/file-walker.js +199 -0
- package/dist/file-walker.js.map +1 -0
- package/dist/index.js +321 -22
- package/dist/index.js.map +1 -1
- package/dist/indexer.js +4 -23
- package/dist/indexer.js.map +1 -1
- package/dist/integration.test.d.ts +3 -2
- package/dist/integration.test.js +461 -11
- package/dist/integration.test.js.map +1 -1
- package/dist/reranker.d.ts +2 -2
- package/dist/reranker.js +10 -12
- package/dist/reranker.js.map +1 -1
- package/dist/rrf.d.ts +17 -0
- package/dist/rrf.js +25 -0
- package/dist/rrf.js.map +1 -0
- package/dist/search.d.ts +2 -0
- package/dist/search.js +30 -52
- package/dist/search.js.map +1 -1
- package/dist/sfc-extractor.d.ts +14 -0
- package/dist/sfc-extractor.js +70 -0
- package/dist/sfc-extractor.js.map +1 -0
- package/dist/store.d.ts +2 -0
- package/dist/store.js +39 -24
- package/dist/store.js.map +1 -1
- package/dist/tei-client.d.ts +70 -0
- package/dist/tei-client.js +153 -0
- package/dist/tei-client.js.map +1 -0
- package/dist/types.d.ts +49 -0
- package/dist/types.js +4 -1
- package/dist/types.js.map +1 -1
- package/dist/unit.test.d.ts +8 -0
- package/dist/unit.test.js +1241 -0
- package/dist/unit.test.js.map +1 -0
- package/docker-compose.nvidia.yml +7 -0
- package/docker-compose.yml +9 -0
- package/package.json +8 -2
- package/scripts/ensure-tei.sh +93 -19
- package/start-tei.sh +17 -3
package/dist/reranker.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reranker.js","sourceRoot":"","sources":["../src/reranker.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,
|
|
1
|
+
{"version":3,"file":"reranker.js","sourceRoot":"","sources":["../src/reranker.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAa/C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,KAAa,EACb,UAA6B;IAE7B,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEvC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAEvD,MAAM,OAAO,GAAmB,EAAE,CAAC;IACnC,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC;YAChD,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,GAAG,CAAC,CAAC,aAAa,CAAC,CAAC;AACnE,CAAC"}
|
package/dist/rrf.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reciprocal Rank Fusion — merge N ranked lists into a single fused ranking.
|
|
3
|
+
* score = sum( weight_r / (k + rank_r) ) for each ranker r.
|
|
4
|
+
* k=60 is the standard default (Azure, Weaviate, OpenSearch).
|
|
5
|
+
*/
|
|
6
|
+
export interface RankedDoc {
|
|
7
|
+
id: number;
|
|
8
|
+
text: string;
|
|
9
|
+
[key: string]: any;
|
|
10
|
+
}
|
|
11
|
+
export interface FusedResult extends RankedDoc {
|
|
12
|
+
rrfScore: number;
|
|
13
|
+
}
|
|
14
|
+
export declare function reciprocalRankFusion(rankedLists: {
|
|
15
|
+
docs: RankedDoc[];
|
|
16
|
+
weight: number;
|
|
17
|
+
}[], k?: number): FusedResult[];
|
package/dist/rrf.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reciprocal Rank Fusion — merge N ranked lists into a single fused ranking.
|
|
3
|
+
* score = sum( weight_r / (k + rank_r) ) for each ranker r.
|
|
4
|
+
* k=60 is the standard default (Azure, Weaviate, OpenSearch).
|
|
5
|
+
*/
|
|
6
|
+
export function reciprocalRankFusion(rankedLists, k = 60) {
|
|
7
|
+
const scoreMap = new Map();
|
|
8
|
+
for (const { docs, weight } of rankedLists) {
|
|
9
|
+
for (let rank = 0; rank < docs.length; rank++) {
|
|
10
|
+
const doc = docs[rank];
|
|
11
|
+
const score = weight / (k + rank + 1);
|
|
12
|
+
const existing = scoreMap.get(doc.id);
|
|
13
|
+
if (existing) {
|
|
14
|
+
existing.rrfScore += score;
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
scoreMap.set(doc.id, { ...doc, rrfScore: score });
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
const results = Array.from(scoreMap.values());
|
|
22
|
+
results.sort((a, b) => b.rrfScore - a.rrfScore);
|
|
23
|
+
return results;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=rrf.js.map
|
package/dist/rrf.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rrf.js","sourceRoot":"","sources":["../src/rrf.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAYH,MAAM,UAAU,oBAAoB,CAClC,WAAoD,EACpD,IAAY,EAAE;IAEd,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAuB,CAAC;IAEhD,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,WAAW,EAAE,CAAC;QAC3C,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC;YAC9C,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;YACvB,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC;YACtC,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACtC,IAAI,QAAQ,EAAE,CAAC;gBACb,QAAQ,CAAC,QAAQ,IAAI,KAAK,CAAC;YAC7B,CAAC;iBAAM,CAAC;gBACN,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,GAAG,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;YACpD,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC;IAChD,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
package/dist/search.d.ts
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
* 2. BM25 search (LanceDB native FTS) — keyword/exact match
|
|
5
5
|
* 3. Reciprocal Rank Fusion — merge both ranked lists
|
|
6
6
|
* 4. Cross-encoder rerank — rescore top candidates
|
|
7
|
+
*
|
|
8
|
+
* TEI containers must be running — no fallback mode.
|
|
7
9
|
*/
|
|
8
10
|
import type { SearchResult } from "./types.js";
|
|
9
11
|
import type { DocStore } from "./store.js";
|
package/dist/search.js
CHANGED
|
@@ -4,49 +4,16 @@
|
|
|
4
4
|
* 2. BM25 search (LanceDB native FTS) — keyword/exact match
|
|
5
5
|
* 3. Reciprocal Rank Fusion — merge both ranked lists
|
|
6
6
|
* 4. Cross-encoder rerank — rescore top candidates
|
|
7
|
+
*
|
|
8
|
+
* TEI containers must be running — no fallback mode.
|
|
7
9
|
*/
|
|
8
10
|
import { embedTexts } from "./indexer.js";
|
|
9
11
|
import { rerank } from "./reranker.js";
|
|
10
|
-
|
|
11
|
-
* RRF: score = sum( weight_r / (k + rank_r) ) for each ranker r.
|
|
12
|
-
* k=60 is the standard default (Azure, Weaviate, OpenSearch).
|
|
13
|
-
*/
|
|
14
|
-
function reciprocalRankFusion(vectorRanked, bm25Ranked, options) {
|
|
15
|
-
const { k, vectorWeight, bm25Weight } = options;
|
|
16
|
-
const scoreMap = new Map();
|
|
17
|
-
// Score from vector search (rank is 1-based)
|
|
18
|
-
for (let rank = 0; rank < vectorRanked.length; rank++) {
|
|
19
|
-
const doc = vectorRanked[rank];
|
|
20
|
-
const score = vectorWeight / (k + rank + 1);
|
|
21
|
-
const existing = scoreMap.get(doc.id);
|
|
22
|
-
if (existing) {
|
|
23
|
-
existing.rrfScore += score;
|
|
24
|
-
}
|
|
25
|
-
else {
|
|
26
|
-
scoreMap.set(doc.id, { ...doc, rrfScore: score });
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
// Score from BM25 search
|
|
30
|
-
for (let rank = 0; rank < bm25Ranked.length; rank++) {
|
|
31
|
-
const doc = bm25Ranked[rank];
|
|
32
|
-
const score = bm25Weight / (k + rank + 1);
|
|
33
|
-
const existing = scoreMap.get(doc.id);
|
|
34
|
-
if (existing) {
|
|
35
|
-
existing.rrfScore += score;
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
scoreMap.set(doc.id, { ...doc, rrfScore: score });
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
// Sort by fused score
|
|
42
|
-
const results = Array.from(scoreMap.values());
|
|
43
|
-
results.sort((a, b) => b.rrfScore - a.rrfScore);
|
|
44
|
-
return results;
|
|
45
|
-
}
|
|
12
|
+
import { reciprocalRankFusion } from "./rrf.js";
|
|
46
13
|
// --- Main search pipeline ---
|
|
47
14
|
export async function searchDocs(query, store, options) {
|
|
48
15
|
const topK = options?.topK ?? 10;
|
|
49
|
-
const candidateCount = 50
|
|
16
|
+
const candidateCount = Math.max(50, topK * 3); // scale with topK
|
|
50
17
|
// Step 1: Vector search via LanceDB
|
|
51
18
|
const [queryVector] = await embedTexts([query], "search_query");
|
|
52
19
|
const vectorHits = await store.vectorSearch(queryVector, candidateCount, options?.library);
|
|
@@ -66,27 +33,38 @@ export async function searchDocs(query, store, options) {
|
|
|
66
33
|
}));
|
|
67
34
|
// Step 3: RRF fusion (k=60, BM25 weighted higher — trust exact keyword matches for
|
|
68
35
|
// framework-specific queries like "Next.js middleware" vs "NestJS middleware")
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
36
|
+
const rrfInputs = [];
|
|
37
|
+
if (vectorRanked.length > 0) {
|
|
38
|
+
rrfInputs.push({ docs: vectorRanked, weight: 0.7 });
|
|
39
|
+
}
|
|
40
|
+
if (bm25Ranked.length > 0) {
|
|
41
|
+
rrfInputs.push({ docs: bm25Ranked, weight: 1.0 });
|
|
42
|
+
}
|
|
43
|
+
if (rrfInputs.length === 0)
|
|
44
|
+
return [];
|
|
45
|
+
const fused = reciprocalRankFusion(rrfInputs);
|
|
74
46
|
// Step 4: Cross-encoder rerank top 50 candidates
|
|
75
47
|
const rerankCandidates = fused
|
|
76
48
|
.slice(0, 50)
|
|
77
|
-
.map((f) => ({
|
|
78
|
-
id: f.id,
|
|
79
|
-
text: f.text,
|
|
80
|
-
library: f.library,
|
|
81
|
-
headingPath: f.headingPath,
|
|
82
|
-
rrfScore: f.rrfScore,
|
|
83
|
-
}));
|
|
49
|
+
.map((f) => ({ ...f }));
|
|
84
50
|
const reranked = await rerank(query, rerankCandidates);
|
|
85
|
-
|
|
86
|
-
|
|
51
|
+
const finalResults = reranked.slice(0, topK).map((r) => ({
|
|
52
|
+
id: r.id,
|
|
87
53
|
score: Math.round(r.rerankerScore * 1000) / 1000,
|
|
88
54
|
library: r.library,
|
|
89
|
-
headingPath:
|
|
55
|
+
headingPath: r.headingPath,
|
|
56
|
+
text: r.text,
|
|
57
|
+
}));
|
|
58
|
+
// Step 5: Format and return top-K
|
|
59
|
+
return finalResults.map((r) => ({
|
|
60
|
+
score: r.score,
|
|
61
|
+
library: r.library,
|
|
62
|
+
headingPath: (() => { try {
|
|
63
|
+
return JSON.parse(r.headingPath);
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return [];
|
|
67
|
+
} })(),
|
|
90
68
|
content: r.text,
|
|
91
69
|
chunkId: r.id,
|
|
92
70
|
}));
|
package/dist/search.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.js","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SFC (Single File Component) script extractor for Vue, Svelte, and Astro.
|
|
3
|
+
* Extracts <script> blocks and frontmatter so they can be parsed by tree-sitter.
|
|
4
|
+
*/
|
|
5
|
+
export interface SfcExtractResult {
|
|
6
|
+
scriptContent: string;
|
|
7
|
+
language: string;
|
|
8
|
+
lineOffset: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Extract script blocks from a single-file component.
|
|
12
|
+
* Returns an array of script blocks with their language and line offset.
|
|
13
|
+
*/
|
|
14
|
+
export declare function extractScriptBlocks(source: string, fileExtension: string): SfcExtractResult[];
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SFC (Single File Component) script extractor for Vue, Svelte, and Astro.
|
|
3
|
+
* Extracts <script> blocks and frontmatter so they can be parsed by tree-sitter.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Extract script blocks from a single-file component.
|
|
7
|
+
* Returns an array of script blocks with their language and line offset.
|
|
8
|
+
*/
|
|
9
|
+
export function extractScriptBlocks(source, fileExtension) {
|
|
10
|
+
const ext = fileExtension.toLowerCase().replace(/^\./, "");
|
|
11
|
+
switch (ext) {
|
|
12
|
+
case "vue":
|
|
13
|
+
case "svelte":
|
|
14
|
+
return extractScriptTags(source);
|
|
15
|
+
case "astro":
|
|
16
|
+
return extractAstroScripts(source);
|
|
17
|
+
default:
|
|
18
|
+
return [];
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Shared helper: extract all <script> tags from source, detecting lang attribute.
|
|
23
|
+
* Used by Vue and Svelte (identical extraction logic).
|
|
24
|
+
*/
|
|
25
|
+
function extractScriptTags(source, defaultLang) {
|
|
26
|
+
const results = [];
|
|
27
|
+
const scriptRe = /<script(\s[^>]*)?>([\s\S]*?)<\/script>/gi;
|
|
28
|
+
let match;
|
|
29
|
+
while ((match = scriptRe.exec(source)) !== null) {
|
|
30
|
+
const attrs = match[1] ?? "";
|
|
31
|
+
const content = match[2];
|
|
32
|
+
// Determine language from lang attribute, or use default
|
|
33
|
+
let language;
|
|
34
|
+
if (defaultLang) {
|
|
35
|
+
language = defaultLang;
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
const langMatch = attrs.match(/lang\s*=\s*["'](\w+)["']/i);
|
|
39
|
+
const lang = langMatch?.[1];
|
|
40
|
+
language = (lang === "ts" || lang === "typescript") ? "typescript" : "javascript";
|
|
41
|
+
}
|
|
42
|
+
// Calculate line offset: count newlines before the match content starts
|
|
43
|
+
const tagEnd = match.index + match[0].indexOf(">") + 1;
|
|
44
|
+
const lineOffset = source.slice(0, tagEnd).split("\n").length - 1;
|
|
45
|
+
if (content.trim().length > 0) {
|
|
46
|
+
results.push({ scriptContent: content, language, lineOffset });
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return results;
|
|
50
|
+
}
|
|
51
|
+
// --- Astro ---
|
|
52
|
+
// Frontmatter is between --- delimiters (always TypeScript), plus optional <script> tags
|
|
53
|
+
function extractAstroScripts(source) {
|
|
54
|
+
const results = [];
|
|
55
|
+
// Frontmatter: content between --- ... ---
|
|
56
|
+
const frontmatterRe = /^---\r?\n([\s\S]*?)\r?\n---/m;
|
|
57
|
+
const fmMatch = source.match(frontmatterRe);
|
|
58
|
+
if (fmMatch && fmMatch[1].trim().length > 0) {
|
|
59
|
+
// Frontmatter starts at line 1 (after the opening ---)
|
|
60
|
+
results.push({
|
|
61
|
+
scriptContent: fmMatch[1],
|
|
62
|
+
language: "typescript", // Astro frontmatter is always TypeScript
|
|
63
|
+
lineOffset: 1,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
// Also extract <script> tags (for client-side scripts) — Astro scripts are always TypeScript
|
|
67
|
+
results.push(...extractScriptTags(source, "typescript"));
|
|
68
|
+
return results;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=sfc-extractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sfc-extractor.js","sourceRoot":"","sources":["../src/sfc-extractor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAc,EAAE,aAAqB;IACvE,MAAM,GAAG,GAAG,aAAa,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAE3D,QAAQ,GAAG,EAAE,CAAC;QACZ,KAAK,KAAK,CAAC;QACX,KAAK,QAAQ;YACX,OAAO,iBAAiB,CAAC,MAAM,CAAC,CAAC;QACnC,KAAK,OAAO;YACV,OAAO,mBAAmB,CAAC,MAAM,CAAC,CAAC;QACrC;YACE,OAAO,EAAE,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,iBAAiB,CAAC,MAAc,EAAE,WAAoB;IAC7D,MAAM,OAAO,GAAuB,EAAE,CAAC;IACvC,MAAM,QAAQ,GAAG,0CAA0C,CAAC;IAE5D,IAAI,KAA6B,CAAC;IAClC,OAAO,CAAC,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAChD,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAEzB,yDAAyD;QACzD,IAAI,QAAgB,CAAC;QACrB,IAAI,WAAW,EAAE,CAAC;YAChB,QAAQ,GAAG,WAAW,CAAC;QACzB,CAAC;aAAM,CAAC;YACN,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;YAC3D,MAAM,IAAI,GAAG,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC;YAC5B,QAAQ,GAAG,CAAC,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC;QACpF,CAAC;QAED,wEAAwE;QACxE,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACvD,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;QAElE,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9B,OAAO,CAAC,IAAI,CAAC,EAAE,aAAa,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;QACjE,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,gBAAgB;AAChB,yFAAyF;AACzF,SAAS,mBAAmB,CAAC,MAAc;IACzC,MAAM,OAAO,GAAuB,EAAE,CAAC;IAEvC,2CAA2C;IAC3C,MAAM,aAAa,GAAG,8BAA8B,CAAC;IACrD,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IAC5C,IAAI,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5C,uDAAuD;QACvD,OAAO,CAAC,IAAI,CAAC;YACX,aAAa,EAAE,OAAO,CAAC,CAAC,CAAC;YACzB,QAAQ,EAAE,YAAY,EAAE,yCAAyC;YACjE,UAAU,EAAE,CAAC;SACd,CAAC,CAAC;IACL,CAAC;IAED,6FAA6F;IAC7F,OAAO,CAAC,IAAI,CAAC,GAAG,iBAAiB,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;IAEzD,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
package/dist/store.d.ts
CHANGED
package/dist/store.js
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import { readFile, writeFile, mkdir } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
import { sqlEscapeString } from "./types.js";
|
|
5
|
+
// npm package name validation pattern
|
|
6
|
+
const NPM_NAME_RE = /^(@[a-z0-9\-~][a-z0-9\-._~]*\/)?[a-z0-9\-~][a-z0-9\-._~]*$/;
|
|
7
|
+
/** Build a safe library filter expression. Throws on invalid names. */
|
|
8
|
+
function libraryFilter(library) {
|
|
9
|
+
if (!NPM_NAME_RE.test(library)) {
|
|
10
|
+
throw new Error(`Invalid library name: ${library}`);
|
|
11
|
+
}
|
|
12
|
+
return `library = '${sqlEscapeString(library)}'`;
|
|
13
|
+
}
|
|
7
14
|
export class DocStore {
|
|
8
15
|
docsDir;
|
|
9
16
|
dbPath;
|
|
@@ -11,6 +18,8 @@ export class DocStore {
|
|
|
11
18
|
rawDir;
|
|
12
19
|
metadata = null;
|
|
13
20
|
nextId = 1;
|
|
21
|
+
dbInstance = null;
|
|
22
|
+
tableInstance = null;
|
|
14
23
|
constructor(projectRoot) {
|
|
15
24
|
this.docsDir = join(projectRoot, ".claude", "docs");
|
|
16
25
|
this.dbPath = join(this.docsDir, "lancedb");
|
|
@@ -21,23 +30,23 @@ export class DocStore {
|
|
|
21
30
|
await mkdir(this.rawDir, { recursive: true });
|
|
22
31
|
}
|
|
23
32
|
async getTable() {
|
|
24
|
-
if (tableInstance)
|
|
25
|
-
return tableInstance;
|
|
33
|
+
if (this.tableInstance)
|
|
34
|
+
return this.tableInstance;
|
|
26
35
|
const lancedb = await import("@lancedb/lancedb");
|
|
27
|
-
dbInstance = await lancedb.connect(this.dbPath);
|
|
36
|
+
this.dbInstance = await lancedb.connect(this.dbPath);
|
|
28
37
|
try {
|
|
29
|
-
tableInstance = await dbInstance.openTable("docs");
|
|
38
|
+
this.tableInstance = await this.dbInstance.openTable("docs");
|
|
30
39
|
// Find max existing ID
|
|
31
|
-
const rows = await tableInstance.query().select(["id"]).toArray();
|
|
40
|
+
const rows = await this.tableInstance.query().select(["id"]).toArray();
|
|
32
41
|
if (rows.length > 0) {
|
|
33
42
|
this.nextId = Math.max(...rows.map((r) => r.id)) + 1;
|
|
34
43
|
}
|
|
35
44
|
}
|
|
36
45
|
catch {
|
|
37
46
|
// Table doesn't exist yet — will be created on first insert
|
|
38
|
-
tableInstance = null;
|
|
47
|
+
this.tableInstance = null;
|
|
39
48
|
}
|
|
40
|
-
return tableInstance;
|
|
49
|
+
return this.tableInstance;
|
|
41
50
|
}
|
|
42
51
|
async loadMetadata() {
|
|
43
52
|
if (this.metadata)
|
|
@@ -64,19 +73,19 @@ export class DocStore {
|
|
|
64
73
|
async addLibrary(library, version, sourceUrl, chunks) {
|
|
65
74
|
await this.ensureDir();
|
|
66
75
|
const lancedb = await import("@lancedb/lancedb");
|
|
67
|
-
if (!dbInstance) {
|
|
68
|
-
dbInstance = await lancedb.connect(this.dbPath);
|
|
76
|
+
if (!this.dbInstance) {
|
|
77
|
+
this.dbInstance = await lancedb.connect(this.dbPath);
|
|
69
78
|
}
|
|
79
|
+
// Get or create table (before assigning IDs so nextId is up-to-date)
|
|
80
|
+
let table = await this.getTable();
|
|
70
81
|
// Assign IDs
|
|
71
82
|
const rows = chunks.map((chunk) => ({
|
|
72
83
|
...chunk,
|
|
73
84
|
id: this.nextId++,
|
|
74
85
|
}));
|
|
75
|
-
// Get or create table
|
|
76
|
-
let table = await this.getTable();
|
|
77
86
|
if (table) {
|
|
78
87
|
// Delete existing rows for this library, then add new ones
|
|
79
|
-
await table.delete(
|
|
88
|
+
await table.delete(libraryFilter(library));
|
|
80
89
|
if (rows.length > 0) {
|
|
81
90
|
await table.add(rows);
|
|
82
91
|
}
|
|
@@ -84,10 +93,13 @@ export class DocStore {
|
|
|
84
93
|
else {
|
|
85
94
|
// Create table with first batch of rows
|
|
86
95
|
if (rows.length > 0) {
|
|
87
|
-
table = await dbInstance.createTable("docs", rows);
|
|
88
|
-
tableInstance = table;
|
|
96
|
+
table = await this.dbInstance.createTable("docs", rows);
|
|
97
|
+
this.tableInstance = table;
|
|
89
98
|
}
|
|
90
99
|
}
|
|
100
|
+
// Rebuild FTS index BEFORE saving metadata — if FTS fails, metadata
|
|
101
|
+
// won't claim the library is indexed
|
|
102
|
+
await this.createFtsIndex();
|
|
91
103
|
// Update metadata
|
|
92
104
|
const metadata = await this.loadMetadata();
|
|
93
105
|
const existing = metadata.libraries.findIndex((l) => l.library === library);
|
|
@@ -105,8 +117,6 @@ export class DocStore {
|
|
|
105
117
|
metadata.libraries.push(libMeta);
|
|
106
118
|
}
|
|
107
119
|
await this.saveMetadata(metadata);
|
|
108
|
-
// Rebuild FTS index after adding new rows
|
|
109
|
-
await this.createFtsIndex();
|
|
110
120
|
// Count total rows
|
|
111
121
|
const totalRows = table
|
|
112
122
|
? (await table.countRows())
|
|
@@ -123,7 +133,7 @@ export class DocStore {
|
|
|
123
133
|
return [];
|
|
124
134
|
let query = table.vectorSearch(queryVector).limit(limit);
|
|
125
135
|
if (library) {
|
|
126
|
-
query = query.where(
|
|
136
|
+
query = query.where(libraryFilter(library));
|
|
127
137
|
}
|
|
128
138
|
return await query.toArray();
|
|
129
139
|
}
|
|
@@ -134,7 +144,7 @@ export class DocStore {
|
|
|
134
144
|
return [];
|
|
135
145
|
let query = table.query();
|
|
136
146
|
if (library) {
|
|
137
|
-
query = query.where(
|
|
147
|
+
query = query.where(libraryFilter(library));
|
|
138
148
|
}
|
|
139
149
|
return await query.toArray();
|
|
140
150
|
}
|
|
@@ -150,8 +160,13 @@ export class DocStore {
|
|
|
150
160
|
const chunks = await this.getChunks(library);
|
|
151
161
|
const lowerHeading = heading.toLowerCase();
|
|
152
162
|
return chunks.filter((c) => {
|
|
153
|
-
|
|
154
|
-
|
|
163
|
+
try {
|
|
164
|
+
const path = JSON.parse(c.headingPath);
|
|
165
|
+
return path.some((h) => h.toLowerCase().includes(lowerHeading));
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
155
170
|
});
|
|
156
171
|
}
|
|
157
172
|
/** Create BM25 full-text search index on the text column. Safe to call repeatedly (replace=true). */
|
|
@@ -173,7 +188,7 @@ export class DocStore {
|
|
|
173
188
|
try {
|
|
174
189
|
let q = table.query().fullTextSearch(query, { columns: ["text"] }).limit(limit);
|
|
175
190
|
if (library) {
|
|
176
|
-
q = q.where(
|
|
191
|
+
q = q.where(libraryFilter(library));
|
|
177
192
|
}
|
|
178
193
|
return await q.toArray();
|
|
179
194
|
}
|
package/dist/store.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared TEI (Text Embeddings Inference) HTTP client with retry, timeout, and batching.
|
|
3
|
+
* Centralizes all TEI communication so embed, rerank, and code-embed share
|
|
4
|
+
* consistent error handling and diagnostics.
|
|
5
|
+
*/
|
|
6
|
+
export interface TeiClientOptions {
|
|
7
|
+
baseUrl: string;
|
|
8
|
+
timeoutMs?: number;
|
|
9
|
+
maxRetries?: number;
|
|
10
|
+
retryDelayMs?: number;
|
|
11
|
+
maxBatchSize?: number;
|
|
12
|
+
}
|
|
13
|
+
export declare class TeiClient {
|
|
14
|
+
readonly baseUrl: string;
|
|
15
|
+
private timeoutMs;
|
|
16
|
+
private maxRetries;
|
|
17
|
+
private retryDelayMs;
|
|
18
|
+
private maxBatchSize;
|
|
19
|
+
constructor(options: TeiClientOptions);
|
|
20
|
+
/**
|
|
21
|
+
* Embed texts, automatically splitting into batches.
|
|
22
|
+
* Returns one embedding vector per input text.
|
|
23
|
+
*/
|
|
24
|
+
embed(inputs: string[], options?: {
|
|
25
|
+
truncate?: boolean;
|
|
26
|
+
}): Promise<number[][]>;
|
|
27
|
+
/**
|
|
28
|
+
* Rerank texts against a query, automatically splitting into batches.
|
|
29
|
+
* Returns scored results sorted by score descending.
|
|
30
|
+
*/
|
|
31
|
+
rerank(query: string, texts: string[]): Promise<{
|
|
32
|
+
index: number;
|
|
33
|
+
score: number;
|
|
34
|
+
}[]>;
|
|
35
|
+
/**
|
|
36
|
+
* Check if the TEI endpoint is healthy.
|
|
37
|
+
*/
|
|
38
|
+
checkHealth(): Promise<{
|
|
39
|
+
healthy: boolean;
|
|
40
|
+
error?: string;
|
|
41
|
+
}>;
|
|
42
|
+
private fetchWithRetry;
|
|
43
|
+
}
|
|
44
|
+
export declare const docEmbedClient: TeiClient;
|
|
45
|
+
export declare const rerankClient: TeiClient;
|
|
46
|
+
export declare const codeEmbedClient: TeiClient;
|
|
47
|
+
/**
|
|
48
|
+
* Truncate vectors to `dim` dimensions and L2-normalize.
|
|
49
|
+
* Shared by doc embeddings (Matryoshka 384-dim) and code embeddings (1536-dim).
|
|
50
|
+
*/
|
|
51
|
+
export declare function truncateAndNormalize(vectors: number[][], dim: number): number[][];
|
|
52
|
+
/**
|
|
53
|
+
* Check health of all 3 TEI endpoints.
|
|
54
|
+
* Returns per-endpoint status and an overall allHealthy flag.
|
|
55
|
+
*/
|
|
56
|
+
export declare function checkAllTeiHealth(): Promise<{
|
|
57
|
+
allHealthy: boolean;
|
|
58
|
+
embed: {
|
|
59
|
+
healthy: boolean;
|
|
60
|
+
error?: string;
|
|
61
|
+
};
|
|
62
|
+
rerank: {
|
|
63
|
+
healthy: boolean;
|
|
64
|
+
error?: string;
|
|
65
|
+
};
|
|
66
|
+
codeEmbed: {
|
|
67
|
+
healthy: boolean;
|
|
68
|
+
error?: string;
|
|
69
|
+
};
|
|
70
|
+
}>;
|