@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,252 @@
|
|
|
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.runParallelIndexing = runParallelIndexing;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const snapshotParser_1 = require("../dsr/snapshotParser");
|
|
10
|
+
const embedding_1 = require("../embedding");
|
|
11
|
+
const sq8_1 = require("../sq8");
|
|
12
|
+
const crypto_1 = require("../crypto");
|
|
13
|
+
const paths_1 = require("../paths");
|
|
14
|
+
const monitor_1 = require("./monitor");
|
|
15
|
+
async function runParallelIndexing(options) {
|
|
16
|
+
const parser = new snapshotParser_1.SnapshotCodeParser();
|
|
17
|
+
const monitor = monitor_1.MemoryMonitor.fromErrorConfig(options.errorHandling, options.indexing.memoryBudgetMb);
|
|
18
|
+
const pendingFiles = options.files.slice();
|
|
19
|
+
const totalFiles = pendingFiles.length;
|
|
20
|
+
let processedFiles = 0;
|
|
21
|
+
let workerCount = Math.max(1, options.indexing.workerCount);
|
|
22
|
+
const batchSize = Math.max(1, options.indexing.batchSize);
|
|
23
|
+
const state = {
|
|
24
|
+
chunkRowsByLang: {},
|
|
25
|
+
refRowsByLang: {},
|
|
26
|
+
astFiles: [],
|
|
27
|
+
astSymbols: [],
|
|
28
|
+
astContains: [],
|
|
29
|
+
astExtendsName: [],
|
|
30
|
+
astImplementsName: [],
|
|
31
|
+
astRefsName: [],
|
|
32
|
+
astCallsName: [],
|
|
33
|
+
};
|
|
34
|
+
const runBatch = async (batchFiles) => {
|
|
35
|
+
const queue = batchFiles.slice();
|
|
36
|
+
const active = new Set();
|
|
37
|
+
const scheduleNext = () => {
|
|
38
|
+
while (active.size < workerCount && queue.length > 0) {
|
|
39
|
+
const file = queue.shift();
|
|
40
|
+
if (!file)
|
|
41
|
+
break;
|
|
42
|
+
const task = processFile(file).catch(() => undefined).then(() => {
|
|
43
|
+
active.delete(task);
|
|
44
|
+
});
|
|
45
|
+
active.add(task);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
scheduleNext();
|
|
49
|
+
while (active.size > 0) {
|
|
50
|
+
await Promise.race(active);
|
|
51
|
+
scheduleNext();
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
const processFile = async (file) => {
|
|
55
|
+
processedFiles++;
|
|
56
|
+
const filePosix = (0, paths_1.toPosixPath)(file);
|
|
57
|
+
options.onProgress?.({ totalFiles, processedFiles, currentFile: filePosix });
|
|
58
|
+
await monitor.throttleIfNeeded();
|
|
59
|
+
const lang = inferIndexLang(filePosix);
|
|
60
|
+
if (!state.chunkRowsByLang[lang])
|
|
61
|
+
state.chunkRowsByLang[lang] = [];
|
|
62
|
+
if (!state.refRowsByLang[lang])
|
|
63
|
+
state.refRowsByLang[lang] = [];
|
|
64
|
+
if (!options.existingChunkIdsByLang[lang])
|
|
65
|
+
options.existingChunkIdsByLang[lang] = new Set();
|
|
66
|
+
const fullPath = path_1.default.join(options.scanRoot, file);
|
|
67
|
+
const stat = await safeStat(fullPath);
|
|
68
|
+
if (!stat?.isFile())
|
|
69
|
+
return;
|
|
70
|
+
const content = await readFileWithGate(fullPath, options.errorHandling);
|
|
71
|
+
if (content == null)
|
|
72
|
+
return;
|
|
73
|
+
const parsed = parseWithFallback(parser, content, fullPath, options.errorHandling);
|
|
74
|
+
const symbols = parsed.symbols;
|
|
75
|
+
const fileRefs = parsed.refs;
|
|
76
|
+
const fileId = (0, crypto_1.sha256Hex)(`file:${filePosix}`);
|
|
77
|
+
state.astFiles.push([fileId, filePosix, lang]);
|
|
78
|
+
const callableScopes = [];
|
|
79
|
+
for (const s of symbols) {
|
|
80
|
+
const text = buildChunkText(filePosix, s);
|
|
81
|
+
const contentHash = (0, crypto_1.sha256Hex)(text);
|
|
82
|
+
const refId = (0, crypto_1.sha256Hex)(`${filePosix}:${s.name}:${s.kind}:${s.startLine}:${s.endLine}:${contentHash}`);
|
|
83
|
+
state.astSymbols.push([refId, filePosix, lang, s.name, s.kind, s.signature, s.startLine, s.endLine]);
|
|
84
|
+
if (s.kind === 'function' || s.kind === 'method') {
|
|
85
|
+
callableScopes.push({ refId, startLine: s.startLine, endLine: s.endLine });
|
|
86
|
+
}
|
|
87
|
+
let parentId = fileId;
|
|
88
|
+
if (s.container) {
|
|
89
|
+
const cText = buildChunkText(filePosix, s.container);
|
|
90
|
+
const cHash = (0, crypto_1.sha256Hex)(cText);
|
|
91
|
+
parentId = (0, crypto_1.sha256Hex)(`${filePosix}:${s.container.name}:${s.container.kind}:${s.container.startLine}:${s.container.endLine}:${cHash}`);
|
|
92
|
+
}
|
|
93
|
+
state.astContains.push([parentId, refId]);
|
|
94
|
+
if (s.kind === 'class') {
|
|
95
|
+
if (s.extends) {
|
|
96
|
+
for (const superName of s.extends)
|
|
97
|
+
state.astExtendsName.push([refId, superName]);
|
|
98
|
+
}
|
|
99
|
+
if (s.implements) {
|
|
100
|
+
for (const ifaceName of s.implements)
|
|
101
|
+
state.astImplementsName.push([refId, ifaceName]);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
const existingChunkIds = options.existingChunkIdsByLang[lang];
|
|
105
|
+
if (!existingChunkIds.has(contentHash)) {
|
|
106
|
+
const vec = (0, embedding_1.hashEmbedding)(text, { dim: options.dim });
|
|
107
|
+
const q = (0, sq8_1.quantizeSQ8)(vec, options.indexing.hnswConfig.quantizationBits);
|
|
108
|
+
state.chunkRowsByLang[lang].push({
|
|
109
|
+
content_hash: contentHash,
|
|
110
|
+
text,
|
|
111
|
+
dim: q.dim,
|
|
112
|
+
scale: q.scale,
|
|
113
|
+
qvec_b64: Buffer.from(q.q).toString('base64'),
|
|
114
|
+
});
|
|
115
|
+
existingChunkIds.add(contentHash);
|
|
116
|
+
}
|
|
117
|
+
state.refRowsByLang[lang].push({
|
|
118
|
+
ref_id: refId,
|
|
119
|
+
content_hash: contentHash,
|
|
120
|
+
file: filePosix,
|
|
121
|
+
symbol: s.name,
|
|
122
|
+
kind: s.kind,
|
|
123
|
+
signature: s.signature,
|
|
124
|
+
start_line: s.startLine,
|
|
125
|
+
end_line: s.endLine,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
const pickScope = (line) => {
|
|
129
|
+
let best = null;
|
|
130
|
+
for (const s of callableScopes) {
|
|
131
|
+
if (line < s.startLine || line > s.endLine)
|
|
132
|
+
continue;
|
|
133
|
+
const span = s.endLine - s.startLine;
|
|
134
|
+
if (!best || span < best.span)
|
|
135
|
+
best = { refId: s.refId, span };
|
|
136
|
+
}
|
|
137
|
+
return best ? best.refId : fileId;
|
|
138
|
+
};
|
|
139
|
+
for (const r of fileRefs) {
|
|
140
|
+
const fromId = pickScope(r.line);
|
|
141
|
+
state.astRefsName.push([fromId, lang, r.name, r.refKind, filePosix, r.line, r.column]);
|
|
142
|
+
if (r.refKind === 'call' || r.refKind === 'new') {
|
|
143
|
+
state.astCallsName.push([fromId, lang, r.name, filePosix, r.line, r.column]);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
const snapshot = monitor.sample();
|
|
147
|
+
workerCount = monitor.adaptWorkerCount(workerCount);
|
|
148
|
+
if (snapshot.critical && workerCount <= 1) {
|
|
149
|
+
options.onThrottle?.({ rssMb: snapshot.rssMb, usageRatio: snapshot.usageRatio });
|
|
150
|
+
await monitor.throttleIfNeeded();
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
options.onProgress?.({ totalFiles, processedFiles: 0 });
|
|
154
|
+
while (pendingFiles.length > 0) {
|
|
155
|
+
const batch = pendingFiles.splice(0, batchSize);
|
|
156
|
+
await runBatch(batch);
|
|
157
|
+
}
|
|
158
|
+
return state;
|
|
159
|
+
}
|
|
160
|
+
async function safeStat(filePath) {
|
|
161
|
+
try {
|
|
162
|
+
return await fs_extra_1.default.stat(filePath);
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
async function readFileWithGate(filePath, config) {
|
|
169
|
+
try {
|
|
170
|
+
const stat = await fs_extra_1.default.stat(filePath);
|
|
171
|
+
if (!stat.isFile())
|
|
172
|
+
return null;
|
|
173
|
+
if (stat.size > config.largeFileThreshold) {
|
|
174
|
+
return readLargeFile(filePath, config.maxChunkSize);
|
|
175
|
+
}
|
|
176
|
+
return await fs_extra_1.default.readFile(filePath, 'utf-8');
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
async function readLargeFile(filePath, maxChars) {
|
|
183
|
+
const buf = await fs_extra_1.default.readFile(filePath, 'utf-8');
|
|
184
|
+
if (buf.length <= maxChars)
|
|
185
|
+
return buf;
|
|
186
|
+
return buf.slice(0, maxChars);
|
|
187
|
+
}
|
|
188
|
+
function parseWithFallback(parser, content, filePath, config) {
|
|
189
|
+
try {
|
|
190
|
+
const result = parser.parseContent(filePath, content);
|
|
191
|
+
// If parser returned empty results and fallback is configured, use fallback
|
|
192
|
+
if (result.symbols.length === 0 && result.refs.length === 0) {
|
|
193
|
+
return fallbackParse(content, filePath, config);
|
|
194
|
+
}
|
|
195
|
+
return result;
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
return fallbackParse(content, filePath, config);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
function fallbackParse(content, filePath, config) {
|
|
202
|
+
if (config.parseFailureFallback === 'skip')
|
|
203
|
+
return { symbols: [], refs: [] };
|
|
204
|
+
if (config.parseFailureFallback === 'text-only') {
|
|
205
|
+
return { symbols: buildTextOnlySymbols(content, filePath), refs: [] };
|
|
206
|
+
}
|
|
207
|
+
if (config.parseFailureFallback === 'line-chunk') {
|
|
208
|
+
return { symbols: buildLineChunkSymbols(content, filePath, config.maxChunkSize), refs: [] };
|
|
209
|
+
}
|
|
210
|
+
return { symbols: [], refs: [] };
|
|
211
|
+
}
|
|
212
|
+
function buildTextOnlySymbols(content, filePath) {
|
|
213
|
+
const lines = content.split(/\r?\n/);
|
|
214
|
+
const name = path_1.default.basename(filePath);
|
|
215
|
+
return [{ name, kind: 'document', startLine: 1, endLine: Math.max(1, lines.length), signature: name }];
|
|
216
|
+
}
|
|
217
|
+
function buildLineChunkSymbols(content, filePath, maxChunkSize) {
|
|
218
|
+
const lines = content.split(/\r?\n/);
|
|
219
|
+
const chunkSize = Math.max(50, Math.min(Math.floor(maxChunkSize / 10), 500));
|
|
220
|
+
const out = [];
|
|
221
|
+
for (let i = 0; i < lines.length; i += chunkSize) {
|
|
222
|
+
const start = i + 1;
|
|
223
|
+
const end = Math.min(lines.length, i + chunkSize);
|
|
224
|
+
const name = `${path_1.default.basename(filePath)}:${start}-${end}`;
|
|
225
|
+
out.push({ name, kind: 'document', startLine: start, endLine: end, signature: name });
|
|
226
|
+
}
|
|
227
|
+
if (out.length === 0) {
|
|
228
|
+
const name = path_1.default.basename(filePath);
|
|
229
|
+
out.push({ name, kind: 'document', startLine: 1, endLine: Math.max(1, lines.length), signature: name });
|
|
230
|
+
}
|
|
231
|
+
return out;
|
|
232
|
+
}
|
|
233
|
+
function buildChunkText(file, symbol) {
|
|
234
|
+
return `file:${file}\nkind:${symbol.kind}\nname:${symbol.name}\nsignature:${symbol.signature}`;
|
|
235
|
+
}
|
|
236
|
+
function inferIndexLang(file) {
|
|
237
|
+
if (file.endsWith('.md') || file.endsWith('.mdx'))
|
|
238
|
+
return 'markdown';
|
|
239
|
+
if (file.endsWith('.yml') || file.endsWith('.yaml'))
|
|
240
|
+
return 'yaml';
|
|
241
|
+
if (file.endsWith('.java'))
|
|
242
|
+
return 'java';
|
|
243
|
+
if (file.endsWith('.c') || file.endsWith('.h'))
|
|
244
|
+
return 'c';
|
|
245
|
+
if (file.endsWith('.go'))
|
|
246
|
+
return 'go';
|
|
247
|
+
if (file.endsWith('.py'))
|
|
248
|
+
return 'python';
|
|
249
|
+
if (file.endsWith('.rs'))
|
|
250
|
+
return 'rust';
|
|
251
|
+
return 'ts';
|
|
252
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.ALL_INDEX_LANGS = void 0;
|
|
40
|
+
exports.openTablesByLang = openTablesByLang;
|
|
41
|
+
exports.defaultDbDir = defaultDbDir;
|
|
42
|
+
const lancedb = __importStar(require("@lancedb/lancedb"));
|
|
43
|
+
const apache_arrow_1 = require("apache-arrow");
|
|
44
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
45
|
+
const path_1 = __importDefault(require("path"));
|
|
46
|
+
exports.ALL_INDEX_LANGS = ['java', 'ts', 'c', 'go', 'python', 'rust', 'markdown', 'yaml'];
|
|
47
|
+
function chunksSchema(dim) {
|
|
48
|
+
return new apache_arrow_1.Schema([
|
|
49
|
+
new apache_arrow_1.Field('content_hash', new apache_arrow_1.Utf8(), false),
|
|
50
|
+
new apache_arrow_1.Field('text', new apache_arrow_1.Utf8(), false),
|
|
51
|
+
new apache_arrow_1.Field('dim', new apache_arrow_1.Int32(), false),
|
|
52
|
+
new apache_arrow_1.Field('scale', new apache_arrow_1.Float32(), false),
|
|
53
|
+
new apache_arrow_1.Field('qvec_b64', new apache_arrow_1.Utf8(), false),
|
|
54
|
+
]);
|
|
55
|
+
}
|
|
56
|
+
function refsSchema() {
|
|
57
|
+
return new apache_arrow_1.Schema([
|
|
58
|
+
new apache_arrow_1.Field('ref_id', new apache_arrow_1.Utf8(), false),
|
|
59
|
+
new apache_arrow_1.Field('content_hash', new apache_arrow_1.Utf8(), false),
|
|
60
|
+
new apache_arrow_1.Field('file', new apache_arrow_1.Utf8(), false),
|
|
61
|
+
new apache_arrow_1.Field('symbol', new apache_arrow_1.Utf8(), false),
|
|
62
|
+
new apache_arrow_1.Field('kind', new apache_arrow_1.Utf8(), false),
|
|
63
|
+
new apache_arrow_1.Field('signature', new apache_arrow_1.Utf8(), false),
|
|
64
|
+
new apache_arrow_1.Field('start_line', new apache_arrow_1.Int32(), false),
|
|
65
|
+
new apache_arrow_1.Field('end_line', new apache_arrow_1.Int32(), false),
|
|
66
|
+
]);
|
|
67
|
+
}
|
|
68
|
+
async function openOrCreateTable(db, name, schema, mode) {
|
|
69
|
+
const tables = await db.tableNames();
|
|
70
|
+
const exists = tables.includes(name);
|
|
71
|
+
if (mode === 'open_only') {
|
|
72
|
+
if (!exists)
|
|
73
|
+
throw new Error(`LanceDB table not found: ${name}`);
|
|
74
|
+
return db.openTable(name);
|
|
75
|
+
}
|
|
76
|
+
if (mode === 'overwrite') {
|
|
77
|
+
if (exists)
|
|
78
|
+
await db.dropTable(name);
|
|
79
|
+
return db.createEmptyTable(name, schema);
|
|
80
|
+
}
|
|
81
|
+
if (exists)
|
|
82
|
+
return db.openTable(name);
|
|
83
|
+
return db.createEmptyTable(name, schema);
|
|
84
|
+
}
|
|
85
|
+
function chunksTableName(lang) {
|
|
86
|
+
return `chunks_${lang}`;
|
|
87
|
+
}
|
|
88
|
+
function refsTableName(lang) {
|
|
89
|
+
return `refs_${lang}`;
|
|
90
|
+
}
|
|
91
|
+
async function openTablesByLang(options) {
|
|
92
|
+
if (options.mode === 'open_only') {
|
|
93
|
+
const exists = await fs_extra_1.default.pathExists(options.dbDir);
|
|
94
|
+
if (!exists)
|
|
95
|
+
throw new Error(`LanceDB directory not found: ${options.dbDir}`);
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
await fs_extra_1.default.ensureDir(options.dbDir);
|
|
99
|
+
}
|
|
100
|
+
const db = await lancedb.connect(options.dbDir);
|
|
101
|
+
const byLang = {};
|
|
102
|
+
for (const lang of options.languages) {
|
|
103
|
+
const chunks = await openOrCreateTable(db, chunksTableName(lang), chunksSchema(options.dim), options.mode);
|
|
104
|
+
const refs = await openOrCreateTable(db, refsTableName(lang), refsSchema(), options.mode);
|
|
105
|
+
byLang[lang] = { lang, chunks, refs };
|
|
106
|
+
}
|
|
107
|
+
return { db, byLang };
|
|
108
|
+
}
|
|
109
|
+
function defaultDbDir(repoRoot) {
|
|
110
|
+
return path_1.default.join(repoRoot, '.git-ai', 'lancedb');
|
|
111
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isGitLfsInstalled = isGitLfsInstalled;
|
|
4
|
+
exports.ensureLfsTracking = ensureLfsTracking;
|
|
5
|
+
const child_process_1 = require("child_process");
|
|
6
|
+
function runGit(args, cwd) {
|
|
7
|
+
const res = (0, child_process_1.spawnSync)('git', args, { cwd, stdio: 'inherit' });
|
|
8
|
+
if (res.status !== 0)
|
|
9
|
+
throw new Error(`git ${args.join(' ')} failed`);
|
|
10
|
+
}
|
|
11
|
+
function isGitRepo(cwd) {
|
|
12
|
+
const res = (0, child_process_1.spawnSync)('git', ['rev-parse', '--show-toplevel'], { cwd, stdio: 'ignore' });
|
|
13
|
+
return res.status === 0;
|
|
14
|
+
}
|
|
15
|
+
function isGitLfsInstalled(cwd) {
|
|
16
|
+
if (!isGitRepo(cwd))
|
|
17
|
+
return false;
|
|
18
|
+
const res = (0, child_process_1.spawnSync)('git', ['lfs', 'version'], { cwd, stdio: 'ignore' });
|
|
19
|
+
return res.status === 0;
|
|
20
|
+
}
|
|
21
|
+
function ensureLfsTracking(cwd, pattern) {
|
|
22
|
+
if (!isGitLfsInstalled(cwd))
|
|
23
|
+
return { tracked: false };
|
|
24
|
+
runGit(['lfs', 'track', pattern], cwd);
|
|
25
|
+
runGit(['add', '.gitattributes'], cwd);
|
|
26
|
+
return { tracked: true };
|
|
27
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createLogger = createLogger;
|
|
4
|
+
const levelOrder = {
|
|
5
|
+
debug: 10,
|
|
6
|
+
info: 20,
|
|
7
|
+
warn: 30,
|
|
8
|
+
error: 40,
|
|
9
|
+
};
|
|
10
|
+
function getConfiguredLevel() {
|
|
11
|
+
const raw = String(process.env.GIT_AI_LOG_LEVEL ?? process.env.LOG_LEVEL ?? '').trim().toLowerCase();
|
|
12
|
+
if (!raw)
|
|
13
|
+
return 'info';
|
|
14
|
+
if (raw === 'silent' || raw === 'off' || raw === 'none' || raw === '0')
|
|
15
|
+
return null;
|
|
16
|
+
if (raw === 'debug' || raw === 'info' || raw === 'warn' || raw === 'error')
|
|
17
|
+
return raw;
|
|
18
|
+
return 'info';
|
|
19
|
+
}
|
|
20
|
+
function serializeError(e) {
|
|
21
|
+
if (!e)
|
|
22
|
+
return undefined;
|
|
23
|
+
if (e instanceof Error)
|
|
24
|
+
return { name: e.name, message: e.message, stack: e.stack };
|
|
25
|
+
return { message: String(e) };
|
|
26
|
+
}
|
|
27
|
+
function createLogger(baseFields = {}) {
|
|
28
|
+
const configured = getConfiguredLevel();
|
|
29
|
+
const threshold = configured ? levelOrder[configured] : Infinity;
|
|
30
|
+
const write = (level, msg, fields) => {
|
|
31
|
+
if (levelOrder[level] < threshold)
|
|
32
|
+
return;
|
|
33
|
+
const rec = {
|
|
34
|
+
ts: new Date().toISOString(),
|
|
35
|
+
level,
|
|
36
|
+
msg,
|
|
37
|
+
...baseFields,
|
|
38
|
+
...(fields ?? {}),
|
|
39
|
+
};
|
|
40
|
+
process.stderr.write(JSON.stringify(rec) + '\n');
|
|
41
|
+
};
|
|
42
|
+
const logger = {
|
|
43
|
+
debug: (msg, fields) => write('debug', msg, fields),
|
|
44
|
+
info: (msg, fields) => write('info', msg, fields),
|
|
45
|
+
warn: (msg, fields) => write('warn', msg, fields),
|
|
46
|
+
error: (msg, fields) => write('error', msg, fields),
|
|
47
|
+
child: (fields) => createLogger({ ...baseFields, ...fields }),
|
|
48
|
+
span: async (name, fields, fn) => {
|
|
49
|
+
const startedAt = Date.now();
|
|
50
|
+
try {
|
|
51
|
+
const out = await fn();
|
|
52
|
+
write('info', name, { ...fields, ok: true, duration_ms: Date.now() - startedAt });
|
|
53
|
+
return out;
|
|
54
|
+
}
|
|
55
|
+
catch (e) {
|
|
56
|
+
write('error', name, { ...fields, ok: false, duration_ms: Date.now() - startedAt, err: serializeError(e) });
|
|
57
|
+
throw e;
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
return logger;
|
|
62
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
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.parseRepoManifestXml = parseRepoManifestXml;
|
|
7
|
+
exports.loadRepoManifestFromManifestsRepo = loadRepoManifestFromManifestsRepo;
|
|
8
|
+
exports.resolveProjectRevision = resolveProjectRevision;
|
|
9
|
+
exports.resolveProjectFetch = resolveProjectFetch;
|
|
10
|
+
exports.buildCloneUrl = buildCloneUrl;
|
|
11
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
12
|
+
const path_1 = __importDefault(require("path"));
|
|
13
|
+
const glob_1 = require("glob");
|
|
14
|
+
function parseAttributes(raw) {
|
|
15
|
+
const attrs = {};
|
|
16
|
+
const re = /(\w+)\s*=\s*"([^"]*)"/g;
|
|
17
|
+
let m;
|
|
18
|
+
while ((m = re.exec(raw)) !== null) {
|
|
19
|
+
attrs[m[1]] = m[2];
|
|
20
|
+
}
|
|
21
|
+
return attrs;
|
|
22
|
+
}
|
|
23
|
+
function parseRepoManifestXml(xml) {
|
|
24
|
+
const remotes = {};
|
|
25
|
+
const projects = [];
|
|
26
|
+
let defaultRemote;
|
|
27
|
+
let defaultRevision;
|
|
28
|
+
for (const m of xml.matchAll(/<remote\b([^>]*?)\/>/g)) {
|
|
29
|
+
const attrs = parseAttributes(m[1] ?? '');
|
|
30
|
+
if (attrs.name) {
|
|
31
|
+
remotes[attrs.name] = { fetch: attrs.fetch };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
for (const m of xml.matchAll(/<default\b([^>]*?)\/>/g)) {
|
|
35
|
+
const attrs = parseAttributes(m[1] ?? '');
|
|
36
|
+
if (attrs.remote)
|
|
37
|
+
defaultRemote = attrs.remote;
|
|
38
|
+
if (attrs.revision)
|
|
39
|
+
defaultRevision = attrs.revision;
|
|
40
|
+
}
|
|
41
|
+
for (const m of xml.matchAll(/<project\b([^>]*?)(?:\/>|>)/g)) {
|
|
42
|
+
const attrs = parseAttributes(m[1] ?? '');
|
|
43
|
+
if (!attrs.name)
|
|
44
|
+
continue;
|
|
45
|
+
projects.push({
|
|
46
|
+
name: attrs.name,
|
|
47
|
+
path: attrs.path ?? attrs.name,
|
|
48
|
+
remote: attrs.remote,
|
|
49
|
+
revision: attrs.revision,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
return { defaultRemote, defaultRevision, remotes, projects };
|
|
53
|
+
}
|
|
54
|
+
async function loadRepoManifestFromManifestsRepo(repoRoot) {
|
|
55
|
+
const defaultXml = path_1.default.join(repoRoot, 'default.xml');
|
|
56
|
+
if (await fs_extra_1.default.pathExists(defaultXml)) {
|
|
57
|
+
const xml = await fs_extra_1.default.readFile(defaultXml, 'utf-8');
|
|
58
|
+
return parseRepoManifestXml(xml);
|
|
59
|
+
}
|
|
60
|
+
const xmlFiles = await (0, glob_1.glob)('*.xml', { cwd: repoRoot, nodir: true });
|
|
61
|
+
for (const f of xmlFiles) {
|
|
62
|
+
const xml = await fs_extra_1.default.readFile(path_1.default.join(repoRoot, f), 'utf-8');
|
|
63
|
+
const parsed = parseRepoManifestXml(xml);
|
|
64
|
+
if (parsed.projects.length > 0)
|
|
65
|
+
return parsed;
|
|
66
|
+
}
|
|
67
|
+
return { remotes: {}, projects: [] };
|
|
68
|
+
}
|
|
69
|
+
function resolveProjectRevision(project, manifest) {
|
|
70
|
+
return project.revision ?? manifest.defaultRevision;
|
|
71
|
+
}
|
|
72
|
+
function resolveProjectFetch(project, manifest) {
|
|
73
|
+
const remoteName = project.remote ?? manifest.defaultRemote;
|
|
74
|
+
return remoteName ? manifest.remotes[remoteName]?.fetch : undefined;
|
|
75
|
+
}
|
|
76
|
+
function buildCloneUrl(fetch, projectName) {
|
|
77
|
+
const base = String(fetch).trim();
|
|
78
|
+
if (base.includes('://')) {
|
|
79
|
+
return base.endsWith('/') ? `${base}${projectName}` : `${base}/${projectName}`;
|
|
80
|
+
}
|
|
81
|
+
if (base.includes(':')) {
|
|
82
|
+
const idx = base.indexOf(':');
|
|
83
|
+
const left = base.slice(0, idx + 1);
|
|
84
|
+
const right = base.slice(idx + 1).replace(/\/+$/, '');
|
|
85
|
+
return `${left}${right}/${projectName}`;
|
|
86
|
+
}
|
|
87
|
+
return base.endsWith('/') ? `${base}${projectName}` : `${base}/${projectName}`;
|
|
88
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
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.CAdapter = void 0;
|
|
7
|
+
const tree_sitter_c_1 = __importDefault(require("tree-sitter-c"));
|
|
8
|
+
const utils_1 = require("./utils");
|
|
9
|
+
class CAdapter {
|
|
10
|
+
getLanguageId() {
|
|
11
|
+
return 'c';
|
|
12
|
+
}
|
|
13
|
+
getTreeSitterLanguage() {
|
|
14
|
+
return tree_sitter_c_1.default;
|
|
15
|
+
}
|
|
16
|
+
getSupportedFileExtensions() {
|
|
17
|
+
return ['.c', '.h'];
|
|
18
|
+
}
|
|
19
|
+
extractSymbolsAndRefs(node) {
|
|
20
|
+
const symbols = [];
|
|
21
|
+
const refs = [];
|
|
22
|
+
const traverse = (n, container) => {
|
|
23
|
+
if (n.type === 'call_expression') {
|
|
24
|
+
const fn = n.childForFieldName('function');
|
|
25
|
+
if (fn)
|
|
26
|
+
(0, utils_1.pushRef)(refs, fn.text, 'call', fn);
|
|
27
|
+
}
|
|
28
|
+
else if (n.type === 'type_identifier') {
|
|
29
|
+
(0, utils_1.pushRef)(refs, n.text, 'type', n);
|
|
30
|
+
}
|
|
31
|
+
let currentContainer = container;
|
|
32
|
+
if (n.type === 'function_definition') {
|
|
33
|
+
const declarator = n.childForFieldName('declarator');
|
|
34
|
+
const nameNode = this.findIdentifier(declarator);
|
|
35
|
+
if (nameNode) {
|
|
36
|
+
const newSymbol = {
|
|
37
|
+
name: nameNode.text,
|
|
38
|
+
kind: 'function',
|
|
39
|
+
startLine: n.startPosition.row + 1,
|
|
40
|
+
endLine: n.endPosition.row + 1,
|
|
41
|
+
signature: this.getSignature(n),
|
|
42
|
+
container: container,
|
|
43
|
+
};
|
|
44
|
+
symbols.push(newSymbol);
|
|
45
|
+
currentContainer = newSymbol;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
else if (n.type === 'struct_specifier') {
|
|
49
|
+
const nameNode = n.childForFieldName('name');
|
|
50
|
+
if (nameNode) {
|
|
51
|
+
const newSymbol = {
|
|
52
|
+
name: nameNode.text,
|
|
53
|
+
kind: 'class',
|
|
54
|
+
startLine: n.startPosition.row + 1,
|
|
55
|
+
endLine: n.endPosition.row + 1,
|
|
56
|
+
signature: `struct ${nameNode.text}`,
|
|
57
|
+
container: container,
|
|
58
|
+
};
|
|
59
|
+
symbols.push(newSymbol);
|
|
60
|
+
currentContainer = newSymbol;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
for (let i = 0; i < n.childCount; i++)
|
|
64
|
+
traverse(n.child(i), currentContainer);
|
|
65
|
+
};
|
|
66
|
+
traverse(node, undefined);
|
|
67
|
+
return { symbols, refs };
|
|
68
|
+
}
|
|
69
|
+
findIdentifier(node) {
|
|
70
|
+
if (!node)
|
|
71
|
+
return null;
|
|
72
|
+
if (node.type === 'identifier')
|
|
73
|
+
return node;
|
|
74
|
+
// recursive search, but limit depth or prioritize 'declarator' fields?
|
|
75
|
+
// In C, function_declarator has 'declarator' field.
|
|
76
|
+
if (node.type === 'function_declarator' || node.type === 'pointer_declarator' || node.type === 'parenthesized_declarator') {
|
|
77
|
+
const decl = node.childForFieldName('declarator');
|
|
78
|
+
if (decl)
|
|
79
|
+
return this.findIdentifier(decl);
|
|
80
|
+
// if no named field, just check children
|
|
81
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
82
|
+
const res = this.findIdentifier(node.child(i));
|
|
83
|
+
if (res)
|
|
84
|
+
return res;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
getSignature(node) {
|
|
90
|
+
return node.text.split('{')[0].trim();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
exports.CAdapter = CAdapter;
|