@mars167/git-ai 2.3.0
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/LICENSE +22 -0
- package/README.md +364 -0
- package/README.zh-CN.md +361 -0
- package/assets/hooks/post-checkout +28 -0
- package/assets/hooks/post-merge +28 -0
- package/assets/hooks/pre-commit +17 -0
- package/assets/hooks/pre-push +29 -0
- package/dist/bin/git-ai.js +62 -0
- package/dist/src/commands/ai.js +30 -0
- package/dist/src/commands/checkIndex.js +19 -0
- package/dist/src/commands/dsr.js +156 -0
- package/dist/src/commands/graph.js +203 -0
- package/dist/src/commands/hooks.js +125 -0
- package/dist/src/commands/index.js +92 -0
- package/dist/src/commands/pack.js +31 -0
- package/dist/src/commands/query.js +139 -0
- package/dist/src/commands/semantic.js +134 -0
- package/dist/src/commands/serve.js +14 -0
- package/dist/src/commands/status.js +78 -0
- package/dist/src/commands/trae.js +75 -0
- package/dist/src/commands/unpack.js +28 -0
- package/dist/src/core/archive.js +91 -0
- package/dist/src/core/astGraph.js +127 -0
- package/dist/src/core/astGraphQuery.js +142 -0
- package/dist/src/core/cozo.js +266 -0
- package/dist/src/core/cpg/astLayer.js +56 -0
- package/dist/src/core/cpg/callGraph.js +483 -0
- package/dist/src/core/cpg/cfgLayer.js +490 -0
- package/dist/src/core/cpg/dfgLayer.js +237 -0
- package/dist/src/core/cpg/index.js +80 -0
- package/dist/src/core/cpg/types.js +108 -0
- package/dist/src/core/crypto.js +10 -0
- package/dist/src/core/dsr/generate.js +308 -0
- package/dist/src/core/dsr/gitContext.js +74 -0
- package/dist/src/core/dsr/indexMaterialize.js +106 -0
- package/dist/src/core/dsr/paths.js +26 -0
- package/dist/src/core/dsr/query.js +73 -0
- package/dist/src/core/dsr/snapshotParser.js +73 -0
- package/dist/src/core/dsr/state.js +27 -0
- package/dist/src/core/dsr/types.js +2 -0
- package/dist/src/core/embedding/fusion.js +52 -0
- package/dist/src/core/embedding/index.js +43 -0
- package/dist/src/core/embedding/parser.js +14 -0
- package/dist/src/core/embedding/semantic.js +254 -0
- package/dist/src/core/embedding/structural.js +97 -0
- package/dist/src/core/embedding/symbolic.js +117 -0
- package/dist/src/core/embedding/tokenizer.js +91 -0
- package/dist/src/core/embedding/types.js +2 -0
- package/dist/src/core/embedding.js +36 -0
- package/dist/src/core/git.js +49 -0
- package/dist/src/core/gitDiff.js +73 -0
- package/dist/src/core/indexCheck.js +131 -0
- package/dist/src/core/indexer.js +185 -0
- package/dist/src/core/indexerIncremental.js +303 -0
- package/dist/src/core/indexing/config.js +51 -0
- package/dist/src/core/indexing/hnsw.js +568 -0
- package/dist/src/core/indexing/index.js +17 -0
- package/dist/src/core/indexing/monitor.js +82 -0
- package/dist/src/core/indexing/parallel.js +252 -0
- package/dist/src/core/lancedb.js +111 -0
- package/dist/src/core/lfs.js +27 -0
- package/dist/src/core/log.js +62 -0
- package/dist/src/core/manifest.js +88 -0
- package/dist/src/core/parser/adapter.js +2 -0
- package/dist/src/core/parser/c.js +93 -0
- package/dist/src/core/parser/chunkRelations.js +178 -0
- package/dist/src/core/parser/chunker.js +274 -0
- package/dist/src/core/parser/go.js +98 -0
- package/dist/src/core/parser/java.js +80 -0
- package/dist/src/core/parser/markdown.js +76 -0
- package/dist/src/core/parser/python.js +81 -0
- package/dist/src/core/parser/rust.js +103 -0
- package/dist/src/core/parser/typescript.js +98 -0
- package/dist/src/core/parser/utils.js +62 -0
- package/dist/src/core/parser/yaml.js +53 -0
- package/dist/src/core/parser.js +75 -0
- package/dist/src/core/paths.js +10 -0
- package/dist/src/core/repoMap.js +164 -0
- package/dist/src/core/retrieval/cache.js +31 -0
- package/dist/src/core/retrieval/classifier.js +74 -0
- package/dist/src/core/retrieval/expander.js +80 -0
- package/dist/src/core/retrieval/fuser.js +40 -0
- package/dist/src/core/retrieval/index.js +32 -0
- package/dist/src/core/retrieval/reranker.js +304 -0
- package/dist/src/core/retrieval/types.js +2 -0
- package/dist/src/core/retrieval/weights.js +42 -0
- package/dist/src/core/search.js +41 -0
- package/dist/src/core/sq8.js +65 -0
- package/dist/src/core/symbolSearch.js +143 -0
- package/dist/src/core/types.js +2 -0
- package/dist/src/core/workspace.js +116 -0
- package/dist/src/mcp/server.js +794 -0
- package/docs/README.md +44 -0
- package/docs/cross-encoder.md +157 -0
- package/docs/embedding.md +158 -0
- package/docs/logo.png +0 -0
- package/docs/windows-setup.md +67 -0
- package/docs/zh-CN/DESIGN.md +102 -0
- package/docs/zh-CN/README.md +46 -0
- package/docs/zh-CN/advanced.md +26 -0
- package/docs/zh-CN/architecture_explained.md +116 -0
- package/docs/zh-CN/cli.md +109 -0
- package/docs/zh-CN/dsr.md +91 -0
- package/docs/zh-CN/graph_scenarios.md +173 -0
- package/docs/zh-CN/hooks.md +14 -0
- package/docs/zh-CN/manifests.md +136 -0
- package/docs/zh-CN/mcp.md +205 -0
- package/docs/zh-CN/quickstart.md +35 -0
- package/docs/zh-CN/rules.md +7 -0
- package/docs/zh-CN/technical-details.md +454 -0
- package/docs/zh-CN/troubleshooting.md +19 -0
- package/docs/zh-CN/windows-setup.md +67 -0
- package/install.sh +183 -0
- package/package.json +97 -0
- package/skills/git-ai-mcp/SKILL.md +86 -0
- package/skills/git-ai-mcp/references/constraints.md +143 -0
- package/skills/git-ai-mcp/references/tools.md +263 -0
- package/templates/agents/common/documents/Fix EISDIR error and enable multi-language indexing.md +14 -0
- package/templates/agents/common/documents/Fix git-ai index error in CodaGraph directory.md +13 -0
- package/templates/agents/common/skills/git-ai-mcp/SKILL.md +86 -0
- package/templates/agents/common/skills/git-ai-mcp/references/constraints.md +143 -0
- package/templates/agents/common/skills/git-ai-mcp/references/tools.md +263 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.generateRepoMap = generateRepoMap;
|
|
7
|
+
exports.formatRepoMap = formatRepoMap;
|
|
8
|
+
const astGraphQuery_1 = require("./astGraphQuery");
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
11
|
+
async function generateRepoMap(options) {
|
|
12
|
+
const { repoRoot, maxFiles = 20, maxSymbolsPerFile = 5, wikiDir } = options;
|
|
13
|
+
const symbolsQuery = `?[ref_id, file, name, kind, signature, start_line, end_line] := *ast_symbol{ref_id, file, name, kind, signature, start_line, end_line}`;
|
|
14
|
+
const symbolsRes = await (0, astGraphQuery_1.runAstGraphQuery)(repoRoot, symbolsQuery);
|
|
15
|
+
const symbolsRaw = Array.isArray(symbolsRes?.rows) ? symbolsRes.rows : [];
|
|
16
|
+
const symbolMap = new Map();
|
|
17
|
+
for (const row of symbolsRaw) {
|
|
18
|
+
symbolMap.set(row[0], {
|
|
19
|
+
id: row[0],
|
|
20
|
+
file: row[1],
|
|
21
|
+
name: row[2],
|
|
22
|
+
kind: row[3],
|
|
23
|
+
signature: row[4],
|
|
24
|
+
start_line: row[5],
|
|
25
|
+
end_line: row[6],
|
|
26
|
+
inDegree: 0,
|
|
27
|
+
outEdges: new Set(),
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
const relationsQuery = `
|
|
31
|
+
?[from_id, to_id] := *ast_call_name{caller_id: from_id, callee_name: name}, *ast_symbol{ref_id: to_id, name}
|
|
32
|
+
?[from_id, to_id] := *ast_ref_name{from_id, name}, *ast_symbol{ref_id: to_id, name}
|
|
33
|
+
`;
|
|
34
|
+
const relationsRes = await (0, astGraphQuery_1.runAstGraphQuery)(repoRoot, relationsQuery);
|
|
35
|
+
const relationsRaw = Array.isArray(relationsRes?.rows) ? relationsRes.rows : [];
|
|
36
|
+
for (const [fromId, toId] of relationsRaw) {
|
|
37
|
+
if (symbolMap.has(fromId) && symbolMap.has(toId) && fromId !== toId) {
|
|
38
|
+
const fromNode = symbolMap.get(fromId);
|
|
39
|
+
const toNode = symbolMap.get(toId);
|
|
40
|
+
if (!fromNode.outEdges.has(toId)) {
|
|
41
|
+
fromNode.outEdges.add(toId);
|
|
42
|
+
toNode.inDegree += 1;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const nodes = Array.from(symbolMap.values());
|
|
47
|
+
const N = nodes.length;
|
|
48
|
+
if (N === 0)
|
|
49
|
+
return [];
|
|
50
|
+
let ranks = new Map();
|
|
51
|
+
nodes.forEach(n => ranks.set(n.id, 1 / N));
|
|
52
|
+
const damping = 0.85;
|
|
53
|
+
const iterations = 10;
|
|
54
|
+
for (let i = 0; i < iterations; i++) {
|
|
55
|
+
const newRanks = new Map();
|
|
56
|
+
nodes.forEach(n => newRanks.set(n.id, (1 - damping) / N));
|
|
57
|
+
for (const node of nodes) {
|
|
58
|
+
const currentRank = ranks.get(node.id);
|
|
59
|
+
if (node.outEdges.size > 0) {
|
|
60
|
+
const share = (currentRank * damping) / node.outEdges.size;
|
|
61
|
+
for (const targetId of node.outEdges) {
|
|
62
|
+
newRanks.set(targetId, newRanks.get(targetId) + share);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
const share = (currentRank * damping) / N;
|
|
67
|
+
for (const n2 of nodes) {
|
|
68
|
+
newRanks.set(n2.id, newRanks.get(n2.id) + share);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
ranks = newRanks;
|
|
73
|
+
}
|
|
74
|
+
const fileMap = new Map();
|
|
75
|
+
for (const node of nodes) {
|
|
76
|
+
const rank = ranks.get(node.id);
|
|
77
|
+
if (!fileMap.has(node.file)) {
|
|
78
|
+
fileMap.set(node.file, { rank: 0, symbols: [] });
|
|
79
|
+
}
|
|
80
|
+
const fileInfo = fileMap.get(node.file);
|
|
81
|
+
fileInfo.rank += rank;
|
|
82
|
+
fileInfo.symbols.push({
|
|
83
|
+
id: node.id,
|
|
84
|
+
name: node.name,
|
|
85
|
+
kind: node.kind,
|
|
86
|
+
file: node.file,
|
|
87
|
+
rank: rank,
|
|
88
|
+
signature: node.signature,
|
|
89
|
+
start_line: node.start_line,
|
|
90
|
+
end_line: node.end_line,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
let wikiPages = [];
|
|
94
|
+
if (wikiDir && fs_extra_1.default.existsSync(wikiDir)) {
|
|
95
|
+
const files = fs_extra_1.default.readdirSync(wikiDir).filter(f => f.endsWith('.md') && f !== 'index.md');
|
|
96
|
+
wikiPages = files.map(f => ({
|
|
97
|
+
file: f,
|
|
98
|
+
content: fs_extra_1.default.readFileSync(path_1.default.join(wikiDir, f), 'utf8').toLowerCase(),
|
|
99
|
+
}));
|
|
100
|
+
}
|
|
101
|
+
const result = Array.from(fileMap.entries())
|
|
102
|
+
.map(([filePath, info]) => {
|
|
103
|
+
const sortedSymbols = info.symbols
|
|
104
|
+
.sort((a, b) => b.rank - a.rank)
|
|
105
|
+
.slice(0, maxSymbolsPerFile);
|
|
106
|
+
let wikiLink;
|
|
107
|
+
const baseName = path_1.default.basename(filePath, path_1.default.extname(filePath)).toLowerCase();
|
|
108
|
+
const matchedByFile = wikiPages.find(p => p.file.toLowerCase().includes(baseName));
|
|
109
|
+
if (matchedByFile) {
|
|
110
|
+
wikiLink = matchedByFile.file;
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
const mentioner = wikiPages.find(p => p.content.includes(baseName) ||
|
|
114
|
+
sortedSymbols.some(s => s.name.length > 3 && p.content.includes(s.name.toLowerCase())));
|
|
115
|
+
if (mentioner) {
|
|
116
|
+
wikiLink = mentioner.file;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return {
|
|
120
|
+
path: filePath,
|
|
121
|
+
rank: info.rank,
|
|
122
|
+
symbols: sortedSymbols,
|
|
123
|
+
wikiLink,
|
|
124
|
+
};
|
|
125
|
+
})
|
|
126
|
+
.sort((a, b) => b.rank - a.rank)
|
|
127
|
+
.slice(0, maxFiles);
|
|
128
|
+
return result;
|
|
129
|
+
}
|
|
130
|
+
function formatRepoMap(fileRanks) {
|
|
131
|
+
if (fileRanks.length === 0)
|
|
132
|
+
return 'No symbols found to map.';
|
|
133
|
+
let output = 'Repository Map (ranked by importance)\n';
|
|
134
|
+
output += '====================================\n\n';
|
|
135
|
+
for (const file of fileRanks) {
|
|
136
|
+
output += `${file.path} (score: ${(file.rank * 100).toFixed(2)})\n`;
|
|
137
|
+
if (file.wikiLink) {
|
|
138
|
+
output += ` wiki: ${file.wikiLink}\n`;
|
|
139
|
+
}
|
|
140
|
+
for (const sym of file.symbols) {
|
|
141
|
+
const indent = ' ';
|
|
142
|
+
const kindIcon = getKindIcon(sym.kind);
|
|
143
|
+
output += `${indent}${kindIcon} ${sym.name} [L${sym.start_line}]\n`;
|
|
144
|
+
}
|
|
145
|
+
output += '\n';
|
|
146
|
+
}
|
|
147
|
+
return output;
|
|
148
|
+
}
|
|
149
|
+
function getKindIcon(kind) {
|
|
150
|
+
switch (kind.toLowerCase()) {
|
|
151
|
+
case 'function':
|
|
152
|
+
case 'method':
|
|
153
|
+
return 'ƒ';
|
|
154
|
+
case 'class':
|
|
155
|
+
return '©';
|
|
156
|
+
case 'interface':
|
|
157
|
+
return 'ɪ';
|
|
158
|
+
case 'variable':
|
|
159
|
+
case 'constant':
|
|
160
|
+
return 'ν';
|
|
161
|
+
default:
|
|
162
|
+
return '•';
|
|
163
|
+
}
|
|
164
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LruCache = void 0;
|
|
4
|
+
class LruCache {
|
|
5
|
+
constructor(maxSize) {
|
|
6
|
+
this.maxSize = Math.max(1, maxSize);
|
|
7
|
+
this.map = new Map();
|
|
8
|
+
}
|
|
9
|
+
get(key) {
|
|
10
|
+
const value = this.map.get(key);
|
|
11
|
+
if (!value)
|
|
12
|
+
return undefined;
|
|
13
|
+
this.map.delete(key);
|
|
14
|
+
this.map.set(key, value);
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
set(key, value) {
|
|
18
|
+
if (this.map.has(key))
|
|
19
|
+
this.map.delete(key);
|
|
20
|
+
this.map.set(key, value);
|
|
21
|
+
if (this.map.size > this.maxSize) {
|
|
22
|
+
const first = this.map.keys().next().value;
|
|
23
|
+
if (first)
|
|
24
|
+
this.map.delete(first);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
clear() {
|
|
28
|
+
this.map.clear();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.LruCache = LruCache;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.classifyQuery = classifyQuery;
|
|
4
|
+
const STRUCTURAL_HINTS = ['callers', 'callees', 'call chain', 'inherit', 'extends', 'implements', 'graph', 'references', 'refs', 'ast'];
|
|
5
|
+
const HISTORICAL_HINTS = ['history', 'commit', 'diff', 'changed', 'evolution', 'dsr', 'timeline', 'version', 'previous'];
|
|
6
|
+
const SYMBOL_HINTS = ['function', 'class', 'method', 'symbol', 'identifier'];
|
|
7
|
+
const FILE_PATTERN = /(\S+\.(?:ts|tsx|js|jsx|java|py|go|rs|c|h|md|mdx|yaml|yml))/i;
|
|
8
|
+
const SYMBOL_PATTERN = /\b([A-Za-z_][A-Za-z0-9_$.]*)\b/g;
|
|
9
|
+
function scoreHints(query, hints) {
|
|
10
|
+
const q = query.toLowerCase();
|
|
11
|
+
let score = 0;
|
|
12
|
+
for (const h of hints) {
|
|
13
|
+
if (q.includes(h))
|
|
14
|
+
score += 1;
|
|
15
|
+
}
|
|
16
|
+
return score;
|
|
17
|
+
}
|
|
18
|
+
function extractEntities(query) {
|
|
19
|
+
const entities = [];
|
|
20
|
+
const fileMatch = query.match(FILE_PATTERN);
|
|
21
|
+
if (fileMatch?.[1]) {
|
|
22
|
+
entities.push({ type: 'file', value: fileMatch[1], confidence: 0.8 });
|
|
23
|
+
}
|
|
24
|
+
const symbols = new Set();
|
|
25
|
+
let m;
|
|
26
|
+
SYMBOL_PATTERN.lastIndex = 0;
|
|
27
|
+
while ((m = SYMBOL_PATTERN.exec(query)) !== null) {
|
|
28
|
+
const token = m[1];
|
|
29
|
+
if (!token)
|
|
30
|
+
continue;
|
|
31
|
+
if (token.length < 3)
|
|
32
|
+
continue;
|
|
33
|
+
if (/^(the|and|for|with|from|into|over|when|where|what|show)$/i.test(token))
|
|
34
|
+
continue;
|
|
35
|
+
symbols.add(token);
|
|
36
|
+
}
|
|
37
|
+
for (const s of symbols)
|
|
38
|
+
entities.push({ type: 'symbol', value: s, confidence: 0.5 });
|
|
39
|
+
if (symbols.size === 0 && query.trim()) {
|
|
40
|
+
entities.push({ type: 'keyword', value: query.trim(), confidence: 0.3 });
|
|
41
|
+
}
|
|
42
|
+
return entities;
|
|
43
|
+
}
|
|
44
|
+
function pickPrimary(scores) {
|
|
45
|
+
const entries = Object.entries(scores);
|
|
46
|
+
entries.sort((a, b) => b[1] - a[1]);
|
|
47
|
+
const top = entries[0];
|
|
48
|
+
const second = entries[1];
|
|
49
|
+
if (!top)
|
|
50
|
+
return { primary: 'semantic', confidence: 0.25 };
|
|
51
|
+
const confidence = top[1] <= 0 ? 0.25 : Math.min(0.95, 0.4 + top[1] * 0.2 - (second?.[1] ?? 0) * 0.1);
|
|
52
|
+
return { primary: top[0], confidence };
|
|
53
|
+
}
|
|
54
|
+
function classifyQuery(query) {
|
|
55
|
+
const q = String(query ?? '').trim();
|
|
56
|
+
const scores = {
|
|
57
|
+
semantic: 0.5,
|
|
58
|
+
structural: scoreHints(q, STRUCTURAL_HINTS),
|
|
59
|
+
historical: scoreHints(q, HISTORICAL_HINTS),
|
|
60
|
+
hybrid: 0,
|
|
61
|
+
};
|
|
62
|
+
const hasSymbols = scoreHints(q, SYMBOL_HINTS) > 0 || FILE_PATTERN.test(q);
|
|
63
|
+
if (hasSymbols)
|
|
64
|
+
scores.structural += 1;
|
|
65
|
+
if (scores.structural > 0 && scores.historical > 0) {
|
|
66
|
+
scores.hybrid = Math.max(scores.structural, scores.historical) + 1;
|
|
67
|
+
}
|
|
68
|
+
const primary = pickPrimary(scores);
|
|
69
|
+
return {
|
|
70
|
+
primary: primary.primary,
|
|
71
|
+
confidence: primary.confidence,
|
|
72
|
+
entities: extractEntities(q),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.expandQuery = expandQuery;
|
|
4
|
+
const ABBREVIATIONS = {
|
|
5
|
+
cfg: 'configuration',
|
|
6
|
+
auth: 'authentication',
|
|
7
|
+
repo: 'repository',
|
|
8
|
+
svc: 'service',
|
|
9
|
+
impl: 'implementation',
|
|
10
|
+
dep: 'dependency',
|
|
11
|
+
deps: 'dependencies',
|
|
12
|
+
doc: 'documentation',
|
|
13
|
+
docs: 'documentation',
|
|
14
|
+
api: 'interface',
|
|
15
|
+
ui: 'user interface',
|
|
16
|
+
ux: 'user experience',
|
|
17
|
+
};
|
|
18
|
+
const SYNONYMS = {
|
|
19
|
+
bug: ['issue', 'error', 'fault'],
|
|
20
|
+
fix: ['resolve', 'repair', 'patch'],
|
|
21
|
+
config: ['configuration', 'settings'],
|
|
22
|
+
search: ['lookup', 'find', 'query'],
|
|
23
|
+
history: ['timeline', 'evolution', 'past'],
|
|
24
|
+
commit: ['revision', 'changeset'],
|
|
25
|
+
graph: ['relations', 'edges', 'call graph'],
|
|
26
|
+
symbol: ['identifier', 'name'],
|
|
27
|
+
};
|
|
28
|
+
const DOMAIN_VOCAB = {
|
|
29
|
+
dsr: ['deterministic semantic record', 'semantic snapshot'],
|
|
30
|
+
lancedb: ['vector database', 'lance db'],
|
|
31
|
+
cozo: ['graph database', 'cozodb'],
|
|
32
|
+
ast: ['syntax tree', 'abstract syntax tree'],
|
|
33
|
+
};
|
|
34
|
+
function tokenize(query) {
|
|
35
|
+
return String(query ?? '')
|
|
36
|
+
.toLowerCase()
|
|
37
|
+
.split(/[^a-z0-9_]+/g)
|
|
38
|
+
.map((t) => t.trim())
|
|
39
|
+
.filter(Boolean);
|
|
40
|
+
}
|
|
41
|
+
function expandToken(token) {
|
|
42
|
+
const expansions = new Set();
|
|
43
|
+
expansions.add(token);
|
|
44
|
+
const abbr = ABBREVIATIONS[token];
|
|
45
|
+
if (abbr)
|
|
46
|
+
expansions.add(abbr);
|
|
47
|
+
const syns = SYNONYMS[token];
|
|
48
|
+
if (syns)
|
|
49
|
+
syns.forEach((s) => expansions.add(s));
|
|
50
|
+
const domain = DOMAIN_VOCAB[token];
|
|
51
|
+
if (domain)
|
|
52
|
+
domain.forEach((s) => expansions.add(s));
|
|
53
|
+
return Array.from(expansions);
|
|
54
|
+
}
|
|
55
|
+
function buildExpansion(query) {
|
|
56
|
+
const tokens = tokenize(query);
|
|
57
|
+
if (tokens.length === 0)
|
|
58
|
+
return [query];
|
|
59
|
+
const expandedTokens = tokens.flatMap((t) => expandToken(t));
|
|
60
|
+
const unique = Array.from(new Set(expandedTokens));
|
|
61
|
+
return unique.length > 0 ? unique : tokens;
|
|
62
|
+
}
|
|
63
|
+
function expandQuery(query, queryType) {
|
|
64
|
+
const base = String(query ?? '').trim();
|
|
65
|
+
if (!base)
|
|
66
|
+
return [];
|
|
67
|
+
const expansions = new Set();
|
|
68
|
+
expansions.add(base);
|
|
69
|
+
for (const token of buildExpansion(base))
|
|
70
|
+
expansions.add(token);
|
|
71
|
+
if (queryType?.primary === 'historical') {
|
|
72
|
+
expansions.add(`${base} history`);
|
|
73
|
+
expansions.add(`${base} commit`);
|
|
74
|
+
}
|
|
75
|
+
if (queryType?.primary === 'structural') {
|
|
76
|
+
expansions.add(`${base} graph`);
|
|
77
|
+
expansions.add(`${base} references`);
|
|
78
|
+
}
|
|
79
|
+
return Array.from(expansions).slice(0, 12);
|
|
80
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fuseResults = fuseResults;
|
|
4
|
+
function normalizeScores(candidates) {
|
|
5
|
+
const bySource = new Map();
|
|
6
|
+
for (const c of candidates) {
|
|
7
|
+
if (!bySource.has(c.source))
|
|
8
|
+
bySource.set(c.source, []);
|
|
9
|
+
bySource.get(c.source).push(c);
|
|
10
|
+
}
|
|
11
|
+
const normalized = new Map();
|
|
12
|
+
for (const [source, items] of bySource.entries()) {
|
|
13
|
+
const scores = items.map((i) => i.score);
|
|
14
|
+
const max = Math.max(...scores, 0.0001);
|
|
15
|
+
for (const item of items) {
|
|
16
|
+
normalized.set(`${source}:${item.id}`, item.score / max);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return normalized;
|
|
20
|
+
}
|
|
21
|
+
function fuseResults(candidates, weights, limit = 50) {
|
|
22
|
+
if (!Array.isArray(candidates) || candidates.length === 0)
|
|
23
|
+
return [];
|
|
24
|
+
const normalized = normalizeScores(candidates);
|
|
25
|
+
const out = candidates.map((c) => {
|
|
26
|
+
const key = `${c.source}:${c.id}`;
|
|
27
|
+
const normalizedScore = normalized.get(key) ?? 0;
|
|
28
|
+
const weight = c.source === 'vector'
|
|
29
|
+
? weights.vectorWeight
|
|
30
|
+
: c.source === 'graph'
|
|
31
|
+
? weights.graphWeight
|
|
32
|
+
: c.source === 'dsr'
|
|
33
|
+
? weights.dsrWeight
|
|
34
|
+
: weights.symbolWeight;
|
|
35
|
+
const fusedScore = normalizedScore * weight;
|
|
36
|
+
return { ...c, normalizedScore, fusedScore, rank: 0 };
|
|
37
|
+
});
|
|
38
|
+
out.sort((a, b) => b.fusedScore - a.fusedScore || b.score - a.score);
|
|
39
|
+
return out.slice(0, limit).map((item, idx) => ({ ...item, rank: idx + 1 }));
|
|
40
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.LruCache = exports.fuseScores = exports.CrossEncoderReranker = exports.rerank = exports.fuseResults = exports.computeWeights = exports.expandQuery = exports.classifyQuery = void 0;
|
|
18
|
+
__exportStar(require("./types"), exports);
|
|
19
|
+
var classifier_1 = require("./classifier");
|
|
20
|
+
Object.defineProperty(exports, "classifyQuery", { enumerable: true, get: function () { return classifier_1.classifyQuery; } });
|
|
21
|
+
var expander_1 = require("./expander");
|
|
22
|
+
Object.defineProperty(exports, "expandQuery", { enumerable: true, get: function () { return expander_1.expandQuery; } });
|
|
23
|
+
var weights_1 = require("./weights");
|
|
24
|
+
Object.defineProperty(exports, "computeWeights", { enumerable: true, get: function () { return weights_1.computeWeights; } });
|
|
25
|
+
var fuser_1 = require("./fuser");
|
|
26
|
+
Object.defineProperty(exports, "fuseResults", { enumerable: true, get: function () { return fuser_1.fuseResults; } });
|
|
27
|
+
var reranker_1 = require("./reranker");
|
|
28
|
+
Object.defineProperty(exports, "rerank", { enumerable: true, get: function () { return reranker_1.rerank; } });
|
|
29
|
+
Object.defineProperty(exports, "CrossEncoderReranker", { enumerable: true, get: function () { return reranker_1.CrossEncoderReranker; } });
|
|
30
|
+
Object.defineProperty(exports, "fuseScores", { enumerable: true, get: function () { return reranker_1.fuseScores; } });
|
|
31
|
+
var cache_1 = require("./cache");
|
|
32
|
+
Object.defineProperty(exports, "LruCache", { enumerable: true, get: function () { return cache_1.LruCache; } });
|