codesearch-mcp 0.2.2-alpha → 0.3.0-alpha
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/CHANGELOG.md +65 -1
- package/README.md +60 -33
- package/dist/app.js +46 -22
- package/dist/src/chunking/AstChunker.d.ts +12 -0
- package/dist/src/chunking/AstChunker.js +30 -0
- package/dist/src/chunking/CharacterChunkStrategy.d.ts +8 -0
- package/dist/src/chunking/CharacterChunkStrategy.js +15 -0
- package/dist/src/chunking/DeclarationChunkStrategy.d.ts +15 -0
- package/dist/src/chunking/DeclarationChunkStrategy.js +87 -0
- package/dist/src/chunking/FragmentMerger.d.ts +11 -0
- package/dist/src/chunking/FragmentMerger.js +61 -0
- package/dist/src/chunking/ImportOnlyFilter.d.ts +5 -0
- package/dist/src/chunking/ImportOnlyFilter.js +14 -0
- package/dist/src/chunking/LangchainTextSplitter.d.ts +21 -0
- package/dist/src/chunking/LangchainTextSplitter.js +133 -0
- package/dist/src/chunking/MinSizeSplitPolicy.d.ts +9 -0
- package/dist/src/chunking/MinSizeSplitPolicy.js +18 -0
- package/dist/src/chunking/RunPacker.d.ts +12 -0
- package/dist/src/chunking/RunPacker.js +84 -0
- package/dist/src/chunking/create-chunker.d.ts +3 -0
- package/dist/src/chunking/create-chunker.js +15 -0
- package/dist/src/chunking/interfaces.d.ts +27 -0
- package/dist/src/chunking/interfaces.js +2 -0
- package/dist/src/commands/ConfigCommand.js +1 -9
- package/dist/src/commands/EvalCommand.d.ts +11 -0
- package/dist/src/commands/EvalCommand.js +264 -0
- package/dist/src/commands/IndexCommand.js +70 -66
- package/dist/src/commands/McpCommand.js +2 -8
- package/dist/src/commands/WebCommand.js +2 -5
- package/dist/src/config-error.d.ts +0 -4
- package/dist/src/config-error.js +0 -4
- package/dist/src/config-store.d.ts +1 -54
- package/dist/src/config-store.js +8 -69
- package/dist/src/config.d.ts +8 -17
- package/dist/src/config.js +35 -34
- package/dist/src/constants.d.ts +2 -28
- package/dist/src/constants.js +6 -28
- package/dist/src/container.d.ts +6 -0
- package/dist/src/container.js +12 -3
- package/dist/src/db/index.d.ts +1 -1
- package/dist/src/db/index.js +1 -2
- package/dist/src/db/schema.d.ts +22 -29
- package/dist/src/db/schema.js +3 -14
- package/dist/src/declarations/DeclarationTree.d.ts +19 -0
- package/dist/src/declarations/DeclarationTree.js +66 -0
- package/dist/src/declarations/DeclarationTreeBuilder.d.ts +22 -0
- package/dist/src/declarations/DeclarationTreeBuilder.js +179 -0
- package/dist/src/declarations/SourceLines.d.ts +37 -0
- package/dist/src/declarations/SourceLines.js +415 -0
- package/dist/src/dependency-traversal.d.ts +10 -0
- package/dist/src/dependency-traversal.js +39 -0
- package/dist/src/enriched-prompt.d.ts +0 -5
- package/dist/src/enriched-prompt.js +0 -5
- package/dist/src/error-record.d.ts +12 -0
- package/dist/src/error-record.js +248 -0
- package/dist/src/eval-corpus.d.ts +16 -0
- package/dist/src/eval-corpus.js +169 -0
- package/dist/src/eval-results.d.ts +15 -0
- package/dist/src/eval-results.js +397 -0
- package/dist/src/file-utils.d.ts +10 -0
- package/dist/src/file-utils.js +19 -1
- package/dist/src/graph.d.ts +0 -25
- package/dist/src/graph.js +0 -28
- package/dist/src/help.js +4 -1
- package/dist/src/hnsw-settings.d.ts +3 -0
- package/dist/src/hnsw-settings.js +24 -0
- package/dist/src/interfaces/IAstParser.d.ts +5 -30
- package/dist/src/interfaces/IChunker.d.ts +3 -12
- package/dist/src/interfaces/ICorpusInspector.d.ts +7 -0
- package/dist/src/interfaces/ICorpusInspector.js +2 -0
- package/dist/src/interfaces/IDatabase.d.ts +2 -36
- package/dist/src/interfaces/IEmbedder.d.ts +0 -9
- package/dist/src/interfaces/ILogger.d.ts +1 -11
- package/dist/src/interfaces/IMcpToolHandler.d.ts +0 -5
- package/dist/src/interfaces/IMonorepoResolver.d.ts +0 -22
- package/dist/src/interfaces/IProjectDiscovery.d.ts +0 -17
- package/dist/src/interfaces/IRetrievalEvaluator.d.ts +216 -0
- package/dist/src/interfaces/IRetrievalEvaluator.js +2 -0
- package/dist/src/interfaces/ISearcher.d.ts +26 -20
- package/dist/src/interfaces/index.d.ts +1 -0
- package/dist/src/interrupt.js +0 -2
- package/dist/src/owner-path.d.ts +9 -10
- package/dist/src/owner-path.js +11 -23
- package/dist/src/project-scope.d.ts +7 -0
- package/dist/src/project-scope.js +37 -0
- package/dist/src/project-selector.d.ts +1 -0
- package/dist/src/project-selector.js +13 -6
- package/dist/src/retrieval-eval.d.ts +24 -0
- package/dist/src/retrieval-eval.js +500 -0
- package/dist/src/search/result-shaping.d.ts +4 -0
- package/dist/src/search/result-shaping.js +19 -0
- package/dist/src/services/AstParserService.d.ts +28 -23
- package/dist/src/services/AstParserService.js +391 -98
- package/dist/src/services/DatabaseService.d.ts +2 -19
- package/dist/src/services/DatabaseService.js +44 -81
- package/dist/src/services/EmbedderFactory.d.ts +0 -4
- package/dist/src/services/EmbedderFactory.js +0 -5
- package/dist/src/services/IndexerService.d.ts +2 -10
- package/dist/src/services/IndexerService.js +29 -45
- package/dist/src/services/InfinityEmbedder.d.ts +0 -21
- package/dist/src/services/InfinityEmbedder.js +0 -15
- package/dist/src/services/LoggerService.d.ts +7 -5
- package/dist/src/services/LoggerService.js +37 -41
- package/dist/src/services/McpServer.d.ts +25 -10
- package/dist/src/services/McpServer.js +101 -64
- package/dist/src/services/MonorepoAwareDiscoveryService.d.ts +1 -45
- package/dist/src/services/MonorepoAwareDiscoveryService.js +1 -51
- package/dist/src/services/NxMonorepoResolver.d.ts +0 -29
- package/dist/src/services/NxMonorepoResolver.js +5 -56
- package/dist/src/services/OpenAICompatibleEmbedder.d.ts +0 -6
- package/dist/src/services/OpenAICompatibleEmbedder.js +1 -14
- package/dist/src/services/ProjectDiscoveryService.d.ts +0 -4
- package/dist/src/services/ProjectDiscoveryService.js +0 -4
- package/dist/src/services/SearcherService.d.ts +127 -70
- package/dist/src/services/SearcherService.js +526 -305
- package/dist/src/services/VoyageEmbedder.d.ts +0 -6
- package/dist/src/services/VoyageEmbedder.js +0 -6
- package/dist/src/services/WebServerService.d.ts +1 -53
- package/dist/src/services/WebServerService.js +11 -57
- package/dist/src/services/http-retry.d.ts +0 -7
- package/dist/src/services/http-retry.js +1 -10
- package/dist/src/services/infinity-provisioning.d.ts +0 -74
- package/dist/src/services/infinity-provisioning.js +5 -88
- package/dist/src/services/legacy-ollama-index.d.ts +0 -16
- package/dist/src/services/legacy-ollama-index.js +0 -23
- package/dist/src/services/reranker.d.ts +0 -9
- package/dist/src/services/reranker.js +46 -12
- package/dist/src/setup.d.ts +11 -23
- package/dist/src/setup.js +98 -71
- package/dist/src/symbol-name.d.ts +0 -12
- package/dist/src/symbol-name.js +0 -13
- package/dist/src/symbol-rows.d.ts +2 -11
- package/dist/src/symbol-rows.js +5 -13
- package/dist/src/tool-call-log.d.ts +2 -0
- package/dist/src/tool-call-log.js +24 -0
- package/dist/src/tools/FindSymbolTool.js +14 -5
- package/dist/src/tools/GetCallersTool.d.ts +3 -1
- package/dist/src/tools/GetCallersTool.js +16 -6
- package/dist/src/tools/GetDependenciesTool.d.ts +3 -1
- package/dist/src/tools/GetDependenciesTool.js +15 -8
- package/dist/src/tools/GetDependentsTool.d.ts +3 -1
- package/dist/src/tools/GetDependentsTool.js +31 -16
- package/dist/src/tools/ListFilesTool.d.ts +3 -1
- package/dist/src/tools/ListFilesTool.js +14 -12
- package/dist/src/tools/ListProjectsTool.js +5 -1
- package/dist/src/tools/ReadFileRangeTool.d.ts +3 -1
- package/dist/src/tools/ReadFileRangeTool.js +12 -11
- package/dist/src/tools/ReadFileTool.d.ts +3 -1
- package/dist/src/tools/ReadFileTool.js +12 -10
- package/dist/src/tools/SearchCodebaseTool.js +7 -2
- package/dist/src/tools/format-helpers.d.ts +10 -1
- package/dist/src/tools/format-helpers.js +145 -8
- package/dist/src/web/dashboard.d.ts +0 -8
- package/dist/src/web/dashboard.js +7 -10
- package/package.json +10 -9
- package/dist/src/services/AstChunker.d.ts +0 -42
- package/dist/src/services/AstChunker.js +0 -158
- package/docs/web-dashboard.md +0 -206
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DeclarationChunkStrategy = void 0;
|
|
4
|
+
const FragmentMerger_1 = require("./FragmentMerger");
|
|
5
|
+
const RunPacker_1 = require("./RunPacker");
|
|
6
|
+
class DeclarationChunkStrategy {
|
|
7
|
+
policy;
|
|
8
|
+
packer;
|
|
9
|
+
constructor(policy, packer) {
|
|
10
|
+
this.policy = policy;
|
|
11
|
+
this.packer = packer;
|
|
12
|
+
}
|
|
13
|
+
async chunk(ctx) {
|
|
14
|
+
const roots = ctx.declarations.roots;
|
|
15
|
+
const removed = DeclarationChunkStrategy.gaps({ start: 1, end: ctx.lines.count }, roots)
|
|
16
|
+
.flatMap(gap => ctx.lines.importRegions(gap.start, gap.end));
|
|
17
|
+
if (removed.length > 0 && DeclarationChunkStrategy.isShortPrologue(removed[0].start - 1, ctx.lines)) {
|
|
18
|
+
removed[0] = { start: 1, end: removed[0].end };
|
|
19
|
+
}
|
|
20
|
+
ctx.removed.push(...removed);
|
|
21
|
+
return this.splitLevel({ start: 1, end: ctx.lines.count }, roots, null, removed, ctx);
|
|
22
|
+
}
|
|
23
|
+
async splitNode(node, ctx) {
|
|
24
|
+
if (ctx.lines.length(node.start, node.end) <= ctx.chunkSize)
|
|
25
|
+
return RunPacker_1.RunPacker.piece(node, ctx.lines);
|
|
26
|
+
let children = node.children;
|
|
27
|
+
while (children.length === 1 && this.coversParent(children[0], node, ctx))
|
|
28
|
+
children = children[0].children;
|
|
29
|
+
return this.splitLevel(node, children, node, [], ctx);
|
|
30
|
+
}
|
|
31
|
+
coversParent(child, parent, ctx) {
|
|
32
|
+
if (child.end !== parent.end || child.start < parent.start)
|
|
33
|
+
return false;
|
|
34
|
+
for (let n = parent.start; n < child.start; n++) {
|
|
35
|
+
if (!ctx.lines.isBlank(n) && !ctx.lines.isCommentOnly(n))
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
async splitLevel(range, children, boundary, removed, ctx) {
|
|
41
|
+
const splitPoints = children.filter(c => this.policy.isSplitPoint(c, children, boundary, ctx.lines));
|
|
42
|
+
const packed = children.filter(c => !splitPoints.includes(c));
|
|
43
|
+
ctx.splitPoints.push(...splitPoints);
|
|
44
|
+
const pieces = [];
|
|
45
|
+
let cursor = range.start;
|
|
46
|
+
for (const sp of splitPoints) {
|
|
47
|
+
if (cursor < sp.start)
|
|
48
|
+
pieces.push(...await this.packRuns({ start: cursor, end: sp.start - 1 }, packed, boundary, removed, ctx));
|
|
49
|
+
pieces.push(...await this.splitNode(sp, ctx));
|
|
50
|
+
cursor = sp.end + 1;
|
|
51
|
+
}
|
|
52
|
+
if (cursor <= range.end)
|
|
53
|
+
pieces.push(...await this.packRuns({ start: cursor, end: range.end }, packed, boundary, removed, ctx));
|
|
54
|
+
return pieces;
|
|
55
|
+
}
|
|
56
|
+
async packRuns(span, children, owner, removed, ctx) {
|
|
57
|
+
const pieces = [];
|
|
58
|
+
for (const run of DeclarationChunkStrategy.gaps(span, removed)) {
|
|
59
|
+
pieces.push(...await this.packer.pack(run, children, ctx.lines, ctx.chunkSize, ctx.characterSplit, owner));
|
|
60
|
+
}
|
|
61
|
+
return pieces;
|
|
62
|
+
}
|
|
63
|
+
static isShortPrologue(end, lines) {
|
|
64
|
+
if (end < 1)
|
|
65
|
+
return false;
|
|
66
|
+
for (let n = lines.line(1).startsWith('#!') ? 2 : 1; n <= end; n++) {
|
|
67
|
+
if (!lines.isBlank(n) && !lines.isCommentOnly(n) && !lines.isDirective(n))
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
return lines.slice(1, end).replace(/\s+/g, '').length < FragmentMerger_1.MIN_FRAGMENT_CHARS;
|
|
71
|
+
}
|
|
72
|
+
static gaps(span, taken) {
|
|
73
|
+
const out = [];
|
|
74
|
+
let cursor = span.start;
|
|
75
|
+
for (const t of [...taken].sort((a, b) => a.start - b.start)) {
|
|
76
|
+
if (t.end < cursor || t.start > span.end)
|
|
77
|
+
continue;
|
|
78
|
+
if (cursor < t.start)
|
|
79
|
+
out.push({ start: cursor, end: t.start - 1 });
|
|
80
|
+
cursor = Math.max(cursor, t.end + 1);
|
|
81
|
+
}
|
|
82
|
+
if (cursor <= span.end)
|
|
83
|
+
out.push({ start: cursor, end: span.end });
|
|
84
|
+
return out;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
exports.DeclarationChunkStrategy = DeclarationChunkStrategy;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ChunkPiece } from '../interfaces/IChunker';
|
|
2
|
+
import type { ChunkContext, IChunkPostProcessor } from './interfaces';
|
|
3
|
+
export declare const MIN_FRAGMENT_CHARS = 60;
|
|
4
|
+
export declare class FragmentMerger implements IChunkPostProcessor {
|
|
5
|
+
process(pieces: ChunkPiece[], ctx: ChunkContext): ChunkPiece[];
|
|
6
|
+
private isFragment;
|
|
7
|
+
private canMerge;
|
|
8
|
+
private static scope;
|
|
9
|
+
private static within;
|
|
10
|
+
private static merge;
|
|
11
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FragmentMerger = exports.MIN_FRAGMENT_CHARS = void 0;
|
|
4
|
+
const owner_path_1 = require("../owner-path");
|
|
5
|
+
exports.MIN_FRAGMENT_CHARS = 60;
|
|
6
|
+
class FragmentMerger {
|
|
7
|
+
process(pieces, ctx) {
|
|
8
|
+
const queue = [...pieces].sort((a, b) => a.startLine - b.startLine);
|
|
9
|
+
const out = [];
|
|
10
|
+
for (let i = 0; i < queue.length; i++) {
|
|
11
|
+
const piece = queue[i];
|
|
12
|
+
if (!this.isFragment(piece, ctx)) {
|
|
13
|
+
out.push(piece);
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
const scope = FragmentMerger.scope(piece, ctx);
|
|
17
|
+
const prev = out[out.length - 1];
|
|
18
|
+
if (prev && FragmentMerger.within(prev, scope) && this.canMerge(prev, piece, ctx)) {
|
|
19
|
+
out[out.length - 1] = FragmentMerger.merge(prev, piece, ctx);
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
const next = queue[i + 1];
|
|
23
|
+
if (next && FragmentMerger.within(next, scope) && this.canMerge(piece, next, ctx)) {
|
|
24
|
+
queue[i + 1] = FragmentMerger.merge(piece, next, ctx);
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
out.push(piece);
|
|
28
|
+
}
|
|
29
|
+
return out;
|
|
30
|
+
}
|
|
31
|
+
isFragment(piece, ctx) {
|
|
32
|
+
return ctx.lines.significantLength(piece.startLine, piece.endLine) < exports.MIN_FRAGMENT_CHARS
|
|
33
|
+
&& (0, owner_path_1.ownedLines)(piece, ctx.declarations, ctx.lines).length === 0;
|
|
34
|
+
}
|
|
35
|
+
canMerge(first, second, ctx) {
|
|
36
|
+
const start = Math.min(first.startLine, second.startLine);
|
|
37
|
+
const end = Math.max(first.endLine, second.endLine);
|
|
38
|
+
if (ctx.removed.some(r => r.start > first.endLine && r.end < second.startLine))
|
|
39
|
+
return false;
|
|
40
|
+
return ctx.lines.length(start, end) <= ctx.chunkSize;
|
|
41
|
+
}
|
|
42
|
+
static scope(piece, ctx) {
|
|
43
|
+
let best = null;
|
|
44
|
+
for (const sp of [...ctx.splitPoints, ...ctx.characterSplit]) {
|
|
45
|
+
if (sp.start > piece.startLine || sp.end < piece.endLine)
|
|
46
|
+
continue;
|
|
47
|
+
if (!best || sp.end - sp.start < best.end - best.start)
|
|
48
|
+
best = sp;
|
|
49
|
+
}
|
|
50
|
+
return best;
|
|
51
|
+
}
|
|
52
|
+
static within(piece, scope) {
|
|
53
|
+
return !scope || (scope.start <= piece.startLine && piece.endLine <= scope.end);
|
|
54
|
+
}
|
|
55
|
+
static merge(first, second, ctx) {
|
|
56
|
+
const startLine = Math.min(first.startLine, second.startLine);
|
|
57
|
+
const endLine = Math.max(first.endLine, second.endLine);
|
|
58
|
+
return { content: ctx.lines.slice(startLine, endLine), startLine, endLine };
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
exports.FragmentMerger = FragmentMerger;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ChunkPiece } from '../interfaces/IChunker';
|
|
2
|
+
import type { ChunkContext, IChunkPostProcessor } from './interfaces';
|
|
3
|
+
export declare class ImportOnlyFilter implements IChunkPostProcessor {
|
|
4
|
+
process(pieces: ChunkPiece[], ctx: ChunkContext): ChunkPiece[];
|
|
5
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ImportOnlyFilter = void 0;
|
|
4
|
+
class ImportOnlyFilter {
|
|
5
|
+
process(pieces, ctx) {
|
|
6
|
+
return pieces.filter((p) => {
|
|
7
|
+
if (!ctx.lines.isImportOnly(p.startLine, p.endLine))
|
|
8
|
+
return true;
|
|
9
|
+
ctx.removed.push({ start: p.startLine, end: p.endLine });
|
|
10
|
+
return false;
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
exports.ImportOnlyFilter = ImportOnlyFilter;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Config } from '../config';
|
|
2
|
+
import type { ChunkPiece } from '../interfaces/IChunker';
|
|
3
|
+
import type { ITextSplitter, KeepWindow } from './interfaces';
|
|
4
|
+
export interface SplitterOptions {
|
|
5
|
+
chunkSize: number;
|
|
6
|
+
chunkOverlap: number;
|
|
7
|
+
separators: string[];
|
|
8
|
+
}
|
|
9
|
+
export declare class LangchainTextSplitter implements ITextSplitter {
|
|
10
|
+
private readonly opts;
|
|
11
|
+
constructor(opts: SplitterOptions);
|
|
12
|
+
static forJs(config: Config): LangchainTextSplitter;
|
|
13
|
+
static forSchema(config: Config): LangchainTextSplitter;
|
|
14
|
+
split(text: string, firstLine: number, keep?: KeepWindow): Promise<ChunkPiece[]>;
|
|
15
|
+
private splitSpan;
|
|
16
|
+
private static splitOn;
|
|
17
|
+
private static joinKept;
|
|
18
|
+
private merge;
|
|
19
|
+
private static trim;
|
|
20
|
+
private static newlines;
|
|
21
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LangchainTextSplitter = void 0;
|
|
4
|
+
const textsplitters_1 = require("@langchain/textsplitters");
|
|
5
|
+
class LangchainTextSplitter {
|
|
6
|
+
opts;
|
|
7
|
+
constructor(opts) {
|
|
8
|
+
this.opts = opts;
|
|
9
|
+
if (opts.chunkOverlap >= opts.chunkSize)
|
|
10
|
+
throw new Error('Cannot have chunkOverlap >= chunkSize');
|
|
11
|
+
}
|
|
12
|
+
static forJs(config) {
|
|
13
|
+
return new LangchainTextSplitter({
|
|
14
|
+
chunkSize: config.indexer.chunkSize,
|
|
15
|
+
chunkOverlap: config.indexer.chunkOverlap,
|
|
16
|
+
separators: textsplitters_1.RecursiveCharacterTextSplitter.getSeparatorsForLanguage('js'),
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
static forSchema(config) {
|
|
20
|
+
return new LangchainTextSplitter({
|
|
21
|
+
chunkSize: config.indexer.chunkSize,
|
|
22
|
+
chunkOverlap: config.indexer.chunkOverlap,
|
|
23
|
+
separators: ['\n\n', '\n', ' '],
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
async split(text, firstLine, keep = { from: 0, to: 0 }) {
|
|
27
|
+
const pieces = [];
|
|
28
|
+
let offset = 0;
|
|
29
|
+
let line = firstLine;
|
|
30
|
+
for (const span of this.splitSpan(text, { start: 0, end: text.length }, this.opts.separators, keep)) {
|
|
31
|
+
line += LangchainTextSplitter.newlines(text, offset, span.start);
|
|
32
|
+
offset = span.start;
|
|
33
|
+
const content = text.slice(span.start, span.end);
|
|
34
|
+
pieces.push({ content, startLine: line, endLine: line + LangchainTextSplitter.newlines(content, 0, content.length) });
|
|
35
|
+
}
|
|
36
|
+
return pieces;
|
|
37
|
+
}
|
|
38
|
+
splitSpan(text, span, separators, keep) {
|
|
39
|
+
const sub = text.slice(span.start, span.end);
|
|
40
|
+
let separator = separators[separators.length - 1];
|
|
41
|
+
let next;
|
|
42
|
+
for (let i = 0; i < separators.length; i++) {
|
|
43
|
+
if (separators[i] === '') {
|
|
44
|
+
separator = '';
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
if (sub.includes(separators[i])) {
|
|
48
|
+
separator = separators[i];
|
|
49
|
+
next = separators.slice(i + 1);
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const out = [];
|
|
54
|
+
let good = [];
|
|
55
|
+
const splits = LangchainTextSplitter.splitOn(sub, separator, span.start);
|
|
56
|
+
for (const s of separator ? LangchainTextSplitter.joinKept(splits, keep) : splits) {
|
|
57
|
+
if (s.end - s.start < this.opts.chunkSize) {
|
|
58
|
+
good.push(s);
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (good.length) {
|
|
62
|
+
out.push(...this.merge(text, good));
|
|
63
|
+
good = [];
|
|
64
|
+
}
|
|
65
|
+
out.push(...(next ? this.splitSpan(text, s, next, keep) : [s]));
|
|
66
|
+
}
|
|
67
|
+
if (good.length)
|
|
68
|
+
out.push(...this.merge(text, good));
|
|
69
|
+
return out;
|
|
70
|
+
}
|
|
71
|
+
static splitOn(sub, separator, base) {
|
|
72
|
+
const parts = separator
|
|
73
|
+
? sub.split(new RegExp(`(?=${separator.replace(/[/\-\\^$*+?.()|[\]{}]/g, '\\$&')})`))
|
|
74
|
+
: sub.split('');
|
|
75
|
+
const spans = [];
|
|
76
|
+
let at = base;
|
|
77
|
+
for (const p of parts) {
|
|
78
|
+
if (p !== '')
|
|
79
|
+
spans.push({ start: at, end: at + p.length });
|
|
80
|
+
at += p.length;
|
|
81
|
+
}
|
|
82
|
+
return spans;
|
|
83
|
+
}
|
|
84
|
+
static joinKept(splits, keep) {
|
|
85
|
+
const out = [];
|
|
86
|
+
for (const s of splits) {
|
|
87
|
+
if (out.length && s.start > keep.from && s.start <= keep.to)
|
|
88
|
+
out[out.length - 1] = { start: out[out.length - 1].start, end: s.end };
|
|
89
|
+
else
|
|
90
|
+
out.push(s);
|
|
91
|
+
}
|
|
92
|
+
return out;
|
|
93
|
+
}
|
|
94
|
+
merge(text, splits) {
|
|
95
|
+
const { chunkSize, chunkOverlap } = this.opts;
|
|
96
|
+
const docs = [];
|
|
97
|
+
const current = [];
|
|
98
|
+
let total = 0;
|
|
99
|
+
const flush = () => {
|
|
100
|
+
const doc = LangchainTextSplitter.trim(text, { start: current[0].start, end: current[current.length - 1].end });
|
|
101
|
+
if (doc)
|
|
102
|
+
docs.push(doc);
|
|
103
|
+
};
|
|
104
|
+
for (const d of splits) {
|
|
105
|
+
const len = d.end - d.start;
|
|
106
|
+
if (total + len > chunkSize && current.length > 0) {
|
|
107
|
+
flush();
|
|
108
|
+
while (total > chunkOverlap || (total + len > chunkSize && total > 0)) {
|
|
109
|
+
total -= current[0].end - current[0].start;
|
|
110
|
+
current.shift();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
current.push(d);
|
|
114
|
+
total += len;
|
|
115
|
+
}
|
|
116
|
+
if (current.length > 0)
|
|
117
|
+
flush();
|
|
118
|
+
return docs;
|
|
119
|
+
}
|
|
120
|
+
static trim(text, span) {
|
|
121
|
+
let { start, end } = span;
|
|
122
|
+
while (start < end && /\s/.test(text[start]))
|
|
123
|
+
start++;
|
|
124
|
+
while (end > start && /\s/.test(text[end - 1]))
|
|
125
|
+
end--;
|
|
126
|
+
return start < end ? { start, end } : null;
|
|
127
|
+
}
|
|
128
|
+
static newlines(text, from, to) {
|
|
129
|
+
const count = (a, b) => (text.slice(a, b).match(/\n/g) ?? []).length;
|
|
130
|
+
return to >= from ? count(from, to) : -count(to, from);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
exports.LangchainTextSplitter = LangchainTextSplitter;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { DeclarationNode } from '../declarations/DeclarationTree';
|
|
2
|
+
import type { SourceLines } from '../declarations/SourceLines';
|
|
3
|
+
import type { ISplitPolicy } from './interfaces';
|
|
4
|
+
export declare const MIN_MEMBER_CHARS = 200;
|
|
5
|
+
export declare class MinSizeSplitPolicy implements ISplitPolicy {
|
|
6
|
+
private readonly minChars;
|
|
7
|
+
constructor(minChars?: number);
|
|
8
|
+
isSplitPoint(child: DeclarationNode, siblings: DeclarationNode[], parent: DeclarationNode | null, lines: SourceLines): boolean;
|
|
9
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MinSizeSplitPolicy = exports.MIN_MEMBER_CHARS = void 0;
|
|
4
|
+
exports.MIN_MEMBER_CHARS = 200;
|
|
5
|
+
class MinSizeSplitPolicy {
|
|
6
|
+
minChars;
|
|
7
|
+
constructor(minChars = exports.MIN_MEMBER_CHARS) {
|
|
8
|
+
this.minChars = minChars;
|
|
9
|
+
}
|
|
10
|
+
isSplitPoint(child, siblings, parent, lines) {
|
|
11
|
+
if (lines.length(child.start, child.end) < this.minChars)
|
|
12
|
+
return false;
|
|
13
|
+
if (parent && (child.start <= parent.nameLine || child.end >= parent.end))
|
|
14
|
+
return false;
|
|
15
|
+
return !siblings.some(s => s !== child && s.start <= child.end && child.start <= s.end);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
exports.MinSizeSplitPolicy = MinSizeSplitPolicy;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ChunkPiece } from '../interfaces/IChunker';
|
|
2
|
+
import type { DeclarationNode } from '../declarations/DeclarationTree';
|
|
3
|
+
import type { LineRange, SourceLines } from '../declarations/SourceLines';
|
|
4
|
+
import type { ITextSplitter } from './interfaces';
|
|
5
|
+
export declare class RunPacker {
|
|
6
|
+
private readonly splitter;
|
|
7
|
+
constructor(splitter: ITextSplitter);
|
|
8
|
+
pack(run: LineRange, children: DeclarationNode[], lines: SourceLines, chunkSize: number, characterSplit?: LineRange[], owner?: DeclarationNode | null): Promise<ChunkPiece[]>;
|
|
9
|
+
private static leadWindow;
|
|
10
|
+
static units(run: LineRange, children: DeclarationNode[]): LineRange[];
|
|
11
|
+
static piece(range: LineRange, lines: SourceLines): ChunkPiece[];
|
|
12
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RunPacker = void 0;
|
|
4
|
+
class RunPacker {
|
|
5
|
+
splitter;
|
|
6
|
+
constructor(splitter) {
|
|
7
|
+
this.splitter = splitter;
|
|
8
|
+
}
|
|
9
|
+
async pack(run, children, lines, chunkSize, characterSplit = [], owner = null) {
|
|
10
|
+
const pieces = [];
|
|
11
|
+
let current = null;
|
|
12
|
+
const flush = () => {
|
|
13
|
+
if (current)
|
|
14
|
+
pieces.push(...RunPacker.piece(current, lines));
|
|
15
|
+
current = null;
|
|
16
|
+
};
|
|
17
|
+
for (const unit of RunPacker.units(run, children)) {
|
|
18
|
+
if (lines.length(unit.start, unit.end) > chunkSize) {
|
|
19
|
+
flush();
|
|
20
|
+
characterSplit.push(unit);
|
|
21
|
+
const keep = RunPacker.leadWindow(unit, [owner, ...children], lines, chunkSize);
|
|
22
|
+
pieces.push(...await this.splitter.split(lines.slice(unit.start, unit.end), unit.start, keep));
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (current && lines.length(current.start, unit.end) <= chunkSize) {
|
|
26
|
+
current.end = unit.end;
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
flush();
|
|
30
|
+
current = { ...unit };
|
|
31
|
+
}
|
|
32
|
+
flush();
|
|
33
|
+
return pieces;
|
|
34
|
+
}
|
|
35
|
+
static leadWindow(unit, nodes, lines, chunkSize) {
|
|
36
|
+
const lead = nodes.find(n => n !== null && n.start === unit.start && n.nameLine > unit.start);
|
|
37
|
+
if (!lead)
|
|
38
|
+
return undefined;
|
|
39
|
+
const to = lines.length(unit.start, lead.nameLine - 1);
|
|
40
|
+
if (lines.length(unit.start, lead.nameLine) < chunkSize)
|
|
41
|
+
return { from: 0, to };
|
|
42
|
+
let first = unit.start;
|
|
43
|
+
while (first < lead.nameLine && (lines.isBlank(first) || lines.isCommentOnly(first)))
|
|
44
|
+
first++;
|
|
45
|
+
if (first === lead.nameLine || 1 + lines.length(first, lead.nameLine) >= chunkSize)
|
|
46
|
+
return undefined;
|
|
47
|
+
return { from: lines.length(unit.start, first - 1), to };
|
|
48
|
+
}
|
|
49
|
+
static units(run, children) {
|
|
50
|
+
const inside = children
|
|
51
|
+
.filter(c => c.end >= run.start && c.start <= run.end)
|
|
52
|
+
.sort((a, b) => a.start - b.start);
|
|
53
|
+
const units = [];
|
|
54
|
+
let cursor = run.start;
|
|
55
|
+
for (let i = 0; i < inside.length;) {
|
|
56
|
+
const start = Math.max(inside[i].start, run.start);
|
|
57
|
+
let end = Math.min(inside[i].end, run.end);
|
|
58
|
+
let j = i + 1;
|
|
59
|
+
while (j < inside.length && inside[j].start <= end) {
|
|
60
|
+
end = Math.min(Math.max(end, inside[j].end), run.end);
|
|
61
|
+
j++;
|
|
62
|
+
}
|
|
63
|
+
if (cursor < start)
|
|
64
|
+
units.push({ start: cursor, end: start - 1 });
|
|
65
|
+
units.push({ start, end });
|
|
66
|
+
cursor = end + 1;
|
|
67
|
+
i = j;
|
|
68
|
+
}
|
|
69
|
+
if (cursor <= run.end)
|
|
70
|
+
units.push({ start: cursor, end: run.end });
|
|
71
|
+
return units;
|
|
72
|
+
}
|
|
73
|
+
static piece(range, lines) {
|
|
74
|
+
let { start, end } = range;
|
|
75
|
+
while (start <= end && lines.isBlank(start))
|
|
76
|
+
start++;
|
|
77
|
+
while (end >= start && lines.isBlank(end))
|
|
78
|
+
end--;
|
|
79
|
+
if (start > end)
|
|
80
|
+
return [];
|
|
81
|
+
return [{ content: lines.slice(start, end), startLine: start, endLine: end }];
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
exports.RunPacker = RunPacker;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createChunker = createChunker;
|
|
4
|
+
const AstChunker_1 = require("./AstChunker");
|
|
5
|
+
const CharacterChunkStrategy_1 = require("./CharacterChunkStrategy");
|
|
6
|
+
const DeclarationChunkStrategy_1 = require("./DeclarationChunkStrategy");
|
|
7
|
+
const FragmentMerger_1 = require("./FragmentMerger");
|
|
8
|
+
const ImportOnlyFilter_1 = require("./ImportOnlyFilter");
|
|
9
|
+
const LangchainTextSplitter_1 = require("./LangchainTextSplitter");
|
|
10
|
+
const MinSizeSplitPolicy_1 = require("./MinSizeSplitPolicy");
|
|
11
|
+
const RunPacker_1 = require("./RunPacker");
|
|
12
|
+
function createChunker(config) {
|
|
13
|
+
const jsSplitter = LangchainTextSplitter_1.LangchainTextSplitter.forJs(config);
|
|
14
|
+
return new AstChunker_1.AstChunker(new DeclarationChunkStrategy_1.DeclarationChunkStrategy(new MinSizeSplitPolicy_1.MinSizeSplitPolicy(), new RunPacker_1.RunPacker(jsSplitter)), new CharacterChunkStrategy_1.CharacterChunkStrategy(jsSplitter, LangchainTextSplitter_1.LangchainTextSplitter.forSchema(config)), [new ImportOnlyFilter_1.ImportOnlyFilter()], [new FragmentMerger_1.FragmentMerger()], config);
|
|
15
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ChunkOpts, ChunkPiece } from '../interfaces/IChunker';
|
|
2
|
+
import type { DeclarationNode, DeclarationTree } from '../declarations/DeclarationTree';
|
|
3
|
+
import type { LineRange, SourceLines } from '../declarations/SourceLines';
|
|
4
|
+
export interface ChunkContext {
|
|
5
|
+
lines: SourceLines;
|
|
6
|
+
declarations: DeclarationTree;
|
|
7
|
+
chunkSize: number;
|
|
8
|
+
removed: LineRange[];
|
|
9
|
+
splitPoints: LineRange[];
|
|
10
|
+
characterSplit: LineRange[];
|
|
11
|
+
}
|
|
12
|
+
export interface IChunkStrategy {
|
|
13
|
+
chunk(ctx: ChunkContext, opts: ChunkOpts): Promise<ChunkPiece[]>;
|
|
14
|
+
}
|
|
15
|
+
export interface ISplitPolicy {
|
|
16
|
+
isSplitPoint(child: DeclarationNode, siblings: DeclarationNode[], parent: DeclarationNode | null, lines: SourceLines): boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface KeepWindow {
|
|
19
|
+
from: number;
|
|
20
|
+
to: number;
|
|
21
|
+
}
|
|
22
|
+
export interface ITextSplitter {
|
|
23
|
+
split(text: string, firstLine: number, keep?: KeepWindow): Promise<ChunkPiece[]>;
|
|
24
|
+
}
|
|
25
|
+
export interface IChunkPostProcessor {
|
|
26
|
+
process(pieces: ChunkPiece[], ctx: ChunkContext): ChunkPiece[];
|
|
27
|
+
}
|
|
@@ -72,7 +72,6 @@ class ConfigCommand {
|
|
|
72
72
|
console.log(`No config found at ${config_store_1.CONFIG_FILE}. Run rag-setup.`);
|
|
73
73
|
return;
|
|
74
74
|
}
|
|
75
|
-
// redact password for display
|
|
76
75
|
const display = JSON.parse(JSON.stringify(cfg));
|
|
77
76
|
if (display.db?.password !== undefined)
|
|
78
77
|
display.db.password = '***';
|
|
@@ -131,24 +130,18 @@ class ConfigCommand {
|
|
|
131
130
|
}
|
|
132
131
|
}
|
|
133
132
|
edit() {
|
|
134
|
-
// Ensure config + schema exist so the editor has something to open and
|
|
135
|
-
// resolve the schema against.
|
|
136
133
|
try {
|
|
137
134
|
if (!fs.existsSync(config_store_1.CONFIG_FILE)) {
|
|
138
135
|
(0, config_store_1.writeConfigJson)({});
|
|
139
136
|
}
|
|
140
137
|
else {
|
|
141
138
|
(0, config_store_1.writeSchemaFile)();
|
|
142
|
-
// Migrate existing configs: re-add the "$schema" reference if absent
|
|
143
|
-
// (rewrite through writeConfigJson) so editors bind to the schema.
|
|
144
|
-
// Skip silently if the file is currently invalid — the user will fix
|
|
145
|
-
// it in the editor and validation runs on save.
|
|
146
139
|
try {
|
|
147
140
|
const cfg = (0, config_store_1.readConfigJson)();
|
|
148
141
|
if (cfg)
|
|
149
142
|
(0, config_store_1.writeConfigJson)(cfg);
|
|
150
143
|
}
|
|
151
|
-
catch {
|
|
144
|
+
catch { }
|
|
152
145
|
}
|
|
153
146
|
}
|
|
154
147
|
catch (e) {
|
|
@@ -164,7 +157,6 @@ class ConfigCommand {
|
|
|
164
157
|
console.error('Set $EDITOR or edit the file directly: ' + config_store_1.CONFIG_FILE);
|
|
165
158
|
process.exit(1);
|
|
166
159
|
}
|
|
167
|
-
// Validate what the user saved; readConfigJson throws with a helpful message.
|
|
168
160
|
try {
|
|
169
161
|
(0, config_store_1.readConfigJson)();
|
|
170
162
|
console.log('Config OK');
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Container } from '../container';
|
|
2
|
+
import type { ICommand } from './ICommand';
|
|
3
|
+
import type { ICorpusInspector } from '../interfaces/ICorpusInspector';
|
|
4
|
+
export declare class EvalCommand implements ICommand {
|
|
5
|
+
private container;
|
|
6
|
+
private argv1;
|
|
7
|
+
private corpusInspector;
|
|
8
|
+
private resultsDir;
|
|
9
|
+
constructor(container: Container, argv1: string, corpusInspector?: ICorpusInspector, resultsDir?: string);
|
|
10
|
+
execute(): Promise<void>;
|
|
11
|
+
}
|