@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,127 @@
|
|
|
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.writeAstGraphToCozo = writeAstGraphToCozo;
|
|
7
|
+
exports.removeFileFromAstGraph = removeFileFromAstGraph;
|
|
8
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
9
|
+
const cozo_1 = require("./cozo");
|
|
10
|
+
const crypto_1 = require("./crypto");
|
|
11
|
+
const paths_1 = require("./paths");
|
|
12
|
+
async function writeAstGraphToCozo(repoRoot, data, opts) {
|
|
13
|
+
const db = await (0, cozo_1.openRepoCozoDb)(repoRoot);
|
|
14
|
+
if (!db)
|
|
15
|
+
return { enabled: false, skippedReason: 'Cozo backend not available (see .git-ai/cozo.error.json)' };
|
|
16
|
+
const mode = opts?.mode ?? 'replace';
|
|
17
|
+
const op = mode === 'put' ? ':put' : ':replace';
|
|
18
|
+
const script = `
|
|
19
|
+
{
|
|
20
|
+
?[file_id, file, lang] <- $files
|
|
21
|
+
${op} ast_file { file_id: String => file: String, lang: String }
|
|
22
|
+
}
|
|
23
|
+
{
|
|
24
|
+
?[ref_id, file, lang, name, kind, signature, start_line, end_line] <- $symbols
|
|
25
|
+
${op} ast_symbol { ref_id: String => file: String, lang: String, name: String, kind: String, signature: String, start_line: Int, end_line: Int }
|
|
26
|
+
}
|
|
27
|
+
{
|
|
28
|
+
?[parent_id, child_id] <- $contains
|
|
29
|
+
${op} ast_contains { parent_id: String, child_id: String }
|
|
30
|
+
}
|
|
31
|
+
{
|
|
32
|
+
?[sub_id, super_name] <- $extends_name
|
|
33
|
+
${op} ast_extends_name { sub_id: String, super_name: String }
|
|
34
|
+
}
|
|
35
|
+
{
|
|
36
|
+
?[sub_id, iface_name] <- $implements_name
|
|
37
|
+
${op} ast_implements_name { sub_id: String, iface_name: String }
|
|
38
|
+
}
|
|
39
|
+
{
|
|
40
|
+
?[from_id, from_lang, name, ref_kind, file, line, col] <- $refs_name
|
|
41
|
+
${op} ast_ref_name { from_id: String, from_lang: String, name: String, ref_kind: String, file: String, line: Int, col: Int }
|
|
42
|
+
}
|
|
43
|
+
{
|
|
44
|
+
?[caller_id, caller_lang, callee_name, file, line, col] <- $calls_name
|
|
45
|
+
${op} ast_call_name { caller_id: String, caller_lang: String, callee_name: String, file: String, line: Int, col: Int }
|
|
46
|
+
}
|
|
47
|
+
`;
|
|
48
|
+
await db.run(script, data);
|
|
49
|
+
if (db.engine !== 'sqlite' && db.exportRelations) {
|
|
50
|
+
const exported = await db.exportRelations(['ast_file', 'ast_symbol', 'ast_contains', 'ast_extends_name', 'ast_implements_name', 'ast_ref_name', 'ast_call_name']);
|
|
51
|
+
await fs_extra_1.default.writeJSON((0, cozo_1.repoAstGraphExportPath)(repoRoot), exported, { spaces: 2 });
|
|
52
|
+
}
|
|
53
|
+
if (db.close)
|
|
54
|
+
await db.close();
|
|
55
|
+
return {
|
|
56
|
+
enabled: true,
|
|
57
|
+
engine: db.engine,
|
|
58
|
+
dbPath: db.dbPath,
|
|
59
|
+
counts: {
|
|
60
|
+
files: data.files.length,
|
|
61
|
+
symbols: data.symbols.length,
|
|
62
|
+
contains: data.contains.length,
|
|
63
|
+
extends_name: data.extends_name.length,
|
|
64
|
+
implements_name: data.implements_name.length,
|
|
65
|
+
refs_name: data.refs_name.length,
|
|
66
|
+
calls_name: data.calls_name.length,
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
async function removeFileFromAstGraph(repoRoot, file) {
|
|
71
|
+
const db = await (0, cozo_1.openRepoCozoDb)(repoRoot);
|
|
72
|
+
if (!db)
|
|
73
|
+
return { enabled: false, skippedReason: 'Cozo backend not available (see .git-ai/cozo.error.json)' };
|
|
74
|
+
const filePosix = (0, paths_1.toPosixPath)(file);
|
|
75
|
+
const file_id = (0, crypto_1.sha256Hex)(`file:${filePosix}`);
|
|
76
|
+
const script = `
|
|
77
|
+
syms[ref_id] := *ast_symbol{ref_id, file}, file == $file
|
|
78
|
+
{
|
|
79
|
+
?[ref_id] := syms[ref_id]
|
|
80
|
+
:rm ast_symbol { ref_id }
|
|
81
|
+
}
|
|
82
|
+
{
|
|
83
|
+
?[parent_id, child_id] := *ast_contains{parent_id, child_id}, syms[child_id]
|
|
84
|
+
:rm ast_contains { parent_id, child_id }
|
|
85
|
+
}
|
|
86
|
+
{
|
|
87
|
+
?[parent_id, child_id] := *ast_contains{parent_id, child_id}, syms[parent_id]
|
|
88
|
+
:rm ast_contains { parent_id, child_id }
|
|
89
|
+
}
|
|
90
|
+
{
|
|
91
|
+
?[parent_id, child_id] := *ast_contains{parent_id, child_id}, parent_id == $file_id
|
|
92
|
+
:rm ast_contains { parent_id, child_id }
|
|
93
|
+
}
|
|
94
|
+
{
|
|
95
|
+
?[sub_id, super_name] := *ast_extends_name{sub_id, super_name}, syms[sub_id]
|
|
96
|
+
:rm ast_extends_name { sub_id, super_name }
|
|
97
|
+
}
|
|
98
|
+
{
|
|
99
|
+
?[sub_id, iface_name] := *ast_implements_name{sub_id, iface_name}, syms[sub_id]
|
|
100
|
+
:rm ast_implements_name { sub_id, iface_name }
|
|
101
|
+
}
|
|
102
|
+
{
|
|
103
|
+
?[from_id, from_lang, name, ref_kind, file, line, col] := *ast_ref_name{from_id, from_lang, name, ref_kind, file, line, col}, file == $file
|
|
104
|
+
:rm ast_ref_name { from_id, from_lang, name, ref_kind, file, line, col }
|
|
105
|
+
}
|
|
106
|
+
{
|
|
107
|
+
?[caller_id, caller_lang, callee_name, file, line, col] := *ast_call_name{caller_id, caller_lang, callee_name, file, line, col}, file == $file
|
|
108
|
+
:rm ast_call_name { caller_id, caller_lang, callee_name, file, line, col }
|
|
109
|
+
}
|
|
110
|
+
{
|
|
111
|
+
?[file_id] <- [[$file_id]]
|
|
112
|
+
:rm ast_file { file_id }
|
|
113
|
+
}
|
|
114
|
+
`;
|
|
115
|
+
await db.run(script, { file: filePosix, file_id });
|
|
116
|
+
if (db.engine !== 'sqlite' && db.exportRelations) {
|
|
117
|
+
const exported = await db.exportRelations(['ast_file', 'ast_symbol', 'ast_contains', 'ast_extends_name', 'ast_implements_name', 'ast_ref_name', 'ast_call_name']);
|
|
118
|
+
await fs_extra_1.default.writeJSON((0, cozo_1.repoAstGraphExportPath)(repoRoot), exported, { spaces: 2 });
|
|
119
|
+
}
|
|
120
|
+
if (db.close)
|
|
121
|
+
await db.close();
|
|
122
|
+
return {
|
|
123
|
+
enabled: true,
|
|
124
|
+
engine: db.engine,
|
|
125
|
+
dbPath: db.dbPath,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runAstGraphQuery = runAstGraphQuery;
|
|
4
|
+
exports.buildFindSymbolsQuery = buildFindSymbolsQuery;
|
|
5
|
+
exports.buildChildrenQuery = buildChildrenQuery;
|
|
6
|
+
exports.buildFindReferencesQuery = buildFindReferencesQuery;
|
|
7
|
+
exports.buildCallersByNameQuery = buildCallersByNameQuery;
|
|
8
|
+
exports.buildCalleesByNameQuery = buildCalleesByNameQuery;
|
|
9
|
+
exports.buildCallChainByNameQuery = buildCallChainByNameQuery;
|
|
10
|
+
exports.buildCallChainDownstreamByNameQuery = buildCallChainDownstreamByNameQuery;
|
|
11
|
+
exports.buildCallChainUpstreamByNameQuery = buildCallChainUpstreamByNameQuery;
|
|
12
|
+
const cozo_1 = require("./cozo");
|
|
13
|
+
async function runAstGraphQuery(repoRoot, query, params) {
|
|
14
|
+
const db = await (0, cozo_1.openRepoCozoDb)(repoRoot);
|
|
15
|
+
if (!db) {
|
|
16
|
+
throw new Error('AST graph is not available: Cozo backend not available (see .git-ai/cozo.error.json)');
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
return await db.run(query, params ?? {});
|
|
20
|
+
}
|
|
21
|
+
finally {
|
|
22
|
+
if (db.close)
|
|
23
|
+
await db.close();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function buildFindSymbolsQuery(lang) {
|
|
27
|
+
return `
|
|
28
|
+
?[ref_id, file, lang, name, kind, signature, start_line, end_line] :=
|
|
29
|
+
*ast_symbol{ref_id, file, lang, name, kind, signature, start_line, end_line},
|
|
30
|
+
starts_with(lowercase(name), lowercase($prefix))${lang ? `,
|
|
31
|
+
lowercase(lang) == lowercase($lang)` : ''}
|
|
32
|
+
`;
|
|
33
|
+
}
|
|
34
|
+
function buildChildrenQuery() {
|
|
35
|
+
return `
|
|
36
|
+
?[child_id, file, lang, name, kind, signature, start_line, end_line] :=
|
|
37
|
+
*ast_contains{parent_id: $parent_id, child_id},
|
|
38
|
+
*ast_symbol{ref_id: child_id, file, lang, name, kind, signature, start_line, end_line}
|
|
39
|
+
`;
|
|
40
|
+
}
|
|
41
|
+
function buildFindReferencesQuery(lang) {
|
|
42
|
+
return `
|
|
43
|
+
?[file, line, col, ref_kind, from_id, from_kind, from_name, from_lang] :=
|
|
44
|
+
*ast_ref_name{from_id, from_lang, name, ref_kind, file, line, col},
|
|
45
|
+
lowercase(name) == lowercase($name),
|
|
46
|
+
*ast_symbol{ref_id: from_id, name: from_name, kind: from_kind, lang: from_lang}${lang ? `,
|
|
47
|
+
lowercase(from_lang) == lowercase($lang)` : ''}
|
|
48
|
+
|
|
49
|
+
?[file, line, col, ref_kind, from_id, from_kind, from_name, from_lang] :=
|
|
50
|
+
*ast_ref_name{from_id, from_lang, name, ref_kind, file, line, col},
|
|
51
|
+
lowercase(name) == lowercase($name),
|
|
52
|
+
*ast_file{file_id: from_id, file: from_name, lang: from_lang},
|
|
53
|
+
from_kind = 'file'${lang ? `,
|
|
54
|
+
lowercase(from_lang) == lowercase($lang)` : ''}
|
|
55
|
+
`;
|
|
56
|
+
}
|
|
57
|
+
function buildCallersByNameQuery(lang) {
|
|
58
|
+
return `
|
|
59
|
+
?[caller_id, caller_kind, caller_name, file, line, col, caller_lang] :=
|
|
60
|
+
*ast_call_name{caller_id, caller_lang, callee_name, file, line, col},
|
|
61
|
+
lowercase(callee_name) == lowercase($name),
|
|
62
|
+
*ast_symbol{ref_id: caller_id, name: caller_name, kind: caller_kind, lang: caller_lang}${lang ? `,
|
|
63
|
+
lowercase(caller_lang) == lowercase($lang)` : ''}
|
|
64
|
+
|
|
65
|
+
?[caller_id, caller_kind, caller_name, file, line, col, caller_lang] :=
|
|
66
|
+
*ast_call_name{caller_id, caller_lang, callee_name, file, line, col},
|
|
67
|
+
lowercase(callee_name) == lowercase($name),
|
|
68
|
+
*ast_file{file_id: caller_id, file: caller_name, lang: caller_lang},
|
|
69
|
+
caller_kind = 'file'${lang ? `,
|
|
70
|
+
lowercase(caller_lang) == lowercase($lang)` : ''}
|
|
71
|
+
`;
|
|
72
|
+
}
|
|
73
|
+
function buildCalleesByNameQuery(lang) {
|
|
74
|
+
return `
|
|
75
|
+
?[caller_id, caller_lang, callee_id, callee_file, callee_name, callee_kind, file, line, col] :=
|
|
76
|
+
*ast_symbol{ref_id: caller_id, name: caller_name, lang: caller_lang},
|
|
77
|
+
lowercase(caller_name) == lowercase($name)${lang ? `, lowercase(caller_lang) == lowercase($lang)` : ''},
|
|
78
|
+
*ast_call_name{caller_id, caller_lang, callee_name, file, line, col},
|
|
79
|
+
*ast_symbol{ref_id: callee_id, file: callee_file, name: callee_name, kind: callee_kind, lang: caller_lang}
|
|
80
|
+
`;
|
|
81
|
+
}
|
|
82
|
+
function buildCallChainByNameQuery() {
|
|
83
|
+
throw new Error('Deprecated: use buildCallChainDownstreamByNameQuery or buildCallChainUpstreamByNameQuery');
|
|
84
|
+
}
|
|
85
|
+
function buildCallChainDownstreamByNameQuery() {
|
|
86
|
+
return `
|
|
87
|
+
start_ids[ref_id] :=
|
|
88
|
+
*ast_symbol{ref_id, name, lang},
|
|
89
|
+
lowercase(name) == lowercase($name),
|
|
90
|
+
lowercase(lang) == lowercase($lang)
|
|
91
|
+
|
|
92
|
+
step[caller_id, callee_id, depth, lang] :=
|
|
93
|
+
start_ids[caller_id],
|
|
94
|
+
*ast_call_name{caller_id, caller_lang: lang, callee_name},
|
|
95
|
+
*ast_symbol{ref_id: callee_id, name: callee_name, lang},
|
|
96
|
+
depth = 1,
|
|
97
|
+
lowercase(lang) == lowercase($lang)
|
|
98
|
+
|
|
99
|
+
step[caller_id, callee_id, depth, lang] :=
|
|
100
|
+
step[prev_caller_id, prev_callee_id, d1, lang],
|
|
101
|
+
*ast_call_name{caller_id: prev_callee_id, caller_lang: lang, callee_name},
|
|
102
|
+
*ast_symbol{ref_id: callee_id, name: callee_name, lang},
|
|
103
|
+
caller_id = prev_callee_id,
|
|
104
|
+
depth = d1 + 1,
|
|
105
|
+
depth <= $max_depth,
|
|
106
|
+
lowercase(lang) == lowercase($lang)
|
|
107
|
+
|
|
108
|
+
?[caller_id, callee_id, depth, caller_name, callee_name, lang] :=
|
|
109
|
+
step[caller_id, callee_id, depth, lang],
|
|
110
|
+
*ast_symbol{ref_id: caller_id, name: caller_name, lang},
|
|
111
|
+
*ast_symbol{ref_id: callee_id, name: callee_name, lang}
|
|
112
|
+
`;
|
|
113
|
+
}
|
|
114
|
+
function buildCallChainUpstreamByNameQuery() {
|
|
115
|
+
return `
|
|
116
|
+
start_ids[ref_id] :=
|
|
117
|
+
*ast_symbol{ref_id, name, lang},
|
|
118
|
+
lowercase(name) == lowercase($name),
|
|
119
|
+
lowercase(lang) == lowercase($lang)
|
|
120
|
+
|
|
121
|
+
step[caller_id, callee_id, depth, lang] :=
|
|
122
|
+
start_ids[callee_id],
|
|
123
|
+
*ast_symbol{ref_id: callee_id, name: callee_name, lang},
|
|
124
|
+
*ast_call_name{caller_id, caller_lang: lang, callee_name},
|
|
125
|
+
depth = 1,
|
|
126
|
+
lowercase(lang) == lowercase($lang)
|
|
127
|
+
|
|
128
|
+
step[caller_id, callee_id, depth, lang] :=
|
|
129
|
+
step[prev_caller_id, prev_callee_id, d1, lang],
|
|
130
|
+
*ast_symbol{ref_id: prev_caller_id, name: prev_name, lang},
|
|
131
|
+
*ast_call_name{caller_id, caller_lang: lang, callee_name: prev_name},
|
|
132
|
+
callee_id = prev_caller_id,
|
|
133
|
+
depth = d1 + 1,
|
|
134
|
+
depth <= $max_depth,
|
|
135
|
+
lowercase(lang) == lowercase($lang)
|
|
136
|
+
|
|
137
|
+
?[caller_id, callee_id, depth, caller_name, callee_name, lang] :=
|
|
138
|
+
step[caller_id, callee_id, depth, lang],
|
|
139
|
+
*ast_symbol{ref_id: caller_id, name: caller_name, lang},
|
|
140
|
+
*ast_symbol{ref_id: callee_id, name: callee_name, lang}
|
|
141
|
+
`;
|
|
142
|
+
}
|
|
@@ -0,0 +1,266 @@
|
|
|
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.repoAstGraphDbPath = repoAstGraphDbPath;
|
|
7
|
+
exports.repoAstGraphExportPath = repoAstGraphExportPath;
|
|
8
|
+
exports.openCozoDbAtPath = openCozoDbAtPath;
|
|
9
|
+
exports.openRepoCozoDb = openRepoCozoDb;
|
|
10
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
11
|
+
const path_1 = __importDefault(require("path"));
|
|
12
|
+
function repoAstGraphDbPath(repoRoot) {
|
|
13
|
+
return path_1.default.join(repoRoot, '.git-ai', 'ast-graph.sqlite');
|
|
14
|
+
}
|
|
15
|
+
function repoAstGraphExportPath(repoRoot) {
|
|
16
|
+
return path_1.default.join(repoRoot, '.git-ai', 'ast-graph.export.json');
|
|
17
|
+
}
|
|
18
|
+
let cozoWasmInit = null;
|
|
19
|
+
async function tryImportFromExport(repoRoot, client) {
|
|
20
|
+
if (!client.importRelations)
|
|
21
|
+
return;
|
|
22
|
+
if (client.engine === 'sqlite')
|
|
23
|
+
return;
|
|
24
|
+
const exportPath = repoAstGraphExportPath(repoRoot);
|
|
25
|
+
if (!await fs_extra_1.default.pathExists(exportPath))
|
|
26
|
+
return;
|
|
27
|
+
const data = await fs_extra_1.default.readJSON(exportPath).catch(() => null);
|
|
28
|
+
if (!data)
|
|
29
|
+
return;
|
|
30
|
+
await client.importRelations(data);
|
|
31
|
+
}
|
|
32
|
+
async function tryImportFromExportPath(exportPath, client) {
|
|
33
|
+
if (!exportPath)
|
|
34
|
+
return;
|
|
35
|
+
if (!client.importRelations)
|
|
36
|
+
return;
|
|
37
|
+
if (client.engine === 'sqlite')
|
|
38
|
+
return;
|
|
39
|
+
if (!await fs_extra_1.default.pathExists(exportPath))
|
|
40
|
+
return;
|
|
41
|
+
const data = await fs_extra_1.default.readJSON(exportPath).catch(() => null);
|
|
42
|
+
if (!data)
|
|
43
|
+
return;
|
|
44
|
+
await client.importRelations(data);
|
|
45
|
+
}
|
|
46
|
+
async function openCozoNode(repoRoot) {
|
|
47
|
+
let mod;
|
|
48
|
+
try {
|
|
49
|
+
const moduleName = 'cozo-node';
|
|
50
|
+
mod = await import(moduleName);
|
|
51
|
+
}
|
|
52
|
+
catch (e) {
|
|
53
|
+
throw new Error(`Failed to load cozo-node: ${String(e?.message ?? e)}`);
|
|
54
|
+
}
|
|
55
|
+
const CozoDb = mod?.CozoDb ?? mod?.default?.CozoDb ?? mod?.default ?? mod;
|
|
56
|
+
if (typeof CozoDb !== 'function')
|
|
57
|
+
throw new Error('cozo-node loaded but CozoDb export is missing');
|
|
58
|
+
const dbPath = repoAstGraphDbPath(repoRoot);
|
|
59
|
+
await fs_extra_1.default.ensureDir(path_1.default.dirname(dbPath));
|
|
60
|
+
let db;
|
|
61
|
+
let engine = 'mem';
|
|
62
|
+
try {
|
|
63
|
+
db = new CozoDb('sqlite', dbPath);
|
|
64
|
+
engine = 'sqlite';
|
|
65
|
+
}
|
|
66
|
+
catch (e1) {
|
|
67
|
+
try {
|
|
68
|
+
db = new CozoDb({ engine: 'sqlite', path: dbPath });
|
|
69
|
+
engine = 'sqlite';
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
db = new CozoDb();
|
|
73
|
+
engine = 'mem';
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const client = {
|
|
77
|
+
backend: 'cozo-node',
|
|
78
|
+
engine,
|
|
79
|
+
dbPath: engine === 'sqlite' ? dbPath : undefined,
|
|
80
|
+
run: async (script, params) => db.run(script, params ?? {}),
|
|
81
|
+
exportRelations: typeof db.exportRelations === 'function' ? async (rels) => db.exportRelations(rels) : undefined,
|
|
82
|
+
importRelations: typeof db.importRelations === 'function' ? async (data) => db.importRelations(data) : undefined,
|
|
83
|
+
close: typeof db.close === 'function' ? async () => { await db.close(); } : undefined,
|
|
84
|
+
};
|
|
85
|
+
await tryImportFromExport(repoRoot, client);
|
|
86
|
+
return client;
|
|
87
|
+
}
|
|
88
|
+
async function openCozoWasm(repoRoot) {
|
|
89
|
+
let mod;
|
|
90
|
+
try {
|
|
91
|
+
const moduleName = 'cozo-lib-wasm';
|
|
92
|
+
mod = await import(moduleName);
|
|
93
|
+
}
|
|
94
|
+
catch (e) {
|
|
95
|
+
throw new Error(`Failed to load cozo-lib-wasm: ${String(e?.message ?? e)}`);
|
|
96
|
+
}
|
|
97
|
+
const init = mod?.default;
|
|
98
|
+
const CozoDb = mod?.CozoDb;
|
|
99
|
+
if (typeof init !== 'function' || typeof CozoDb?.new !== 'function') {
|
|
100
|
+
throw new Error('cozo-lib-wasm loaded but exports are not compatible');
|
|
101
|
+
}
|
|
102
|
+
if (!cozoWasmInit)
|
|
103
|
+
cozoWasmInit = Promise.resolve(init()).then(() => { });
|
|
104
|
+
await cozoWasmInit;
|
|
105
|
+
const db = CozoDb.new();
|
|
106
|
+
const run = async (script, params) => {
|
|
107
|
+
const out = db.run(String(script), JSON.stringify(params ?? {}));
|
|
108
|
+
try {
|
|
109
|
+
return JSON.parse(String(out));
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
return out;
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
const exportRelations = async (relations) => {
|
|
116
|
+
if (typeof db.export_relations !== 'function')
|
|
117
|
+
return null;
|
|
118
|
+
const out = db.export_relations(JSON.stringify(relations));
|
|
119
|
+
try {
|
|
120
|
+
return JSON.parse(String(out));
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
return out;
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
const importRelations = async (data) => {
|
|
127
|
+
if (typeof db.import_relations !== 'function')
|
|
128
|
+
return null;
|
|
129
|
+
const out = db.import_relations(JSON.stringify(data));
|
|
130
|
+
try {
|
|
131
|
+
return JSON.parse(String(out));
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
return out;
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
const client = {
|
|
138
|
+
backend: 'cozo-wasm',
|
|
139
|
+
engine: 'mem',
|
|
140
|
+
run,
|
|
141
|
+
exportRelations,
|
|
142
|
+
importRelations,
|
|
143
|
+
close: typeof db.free === 'function' ? async () => { db.free(); } : undefined,
|
|
144
|
+
};
|
|
145
|
+
await tryImportFromExport(repoRoot, client);
|
|
146
|
+
return client;
|
|
147
|
+
}
|
|
148
|
+
async function openCozoDbAtPath(dbPath, exportPath) {
|
|
149
|
+
const errors = [];
|
|
150
|
+
try {
|
|
151
|
+
const moduleName = 'cozo-node';
|
|
152
|
+
const mod = await import(moduleName);
|
|
153
|
+
const CozoDb = mod?.CozoDb ?? mod?.default?.CozoDb ?? mod?.default ?? mod;
|
|
154
|
+
if (typeof CozoDb !== 'function')
|
|
155
|
+
throw new Error('cozo-node loaded but CozoDb export is missing');
|
|
156
|
+
await fs_extra_1.default.ensureDir(path_1.default.dirname(dbPath));
|
|
157
|
+
let db;
|
|
158
|
+
let engine = 'mem';
|
|
159
|
+
try {
|
|
160
|
+
db = new CozoDb('sqlite', dbPath);
|
|
161
|
+
engine = 'sqlite';
|
|
162
|
+
}
|
|
163
|
+
catch (e1) {
|
|
164
|
+
try {
|
|
165
|
+
db = new CozoDb({ engine: 'sqlite', path: dbPath });
|
|
166
|
+
engine = 'sqlite';
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
db = new CozoDb();
|
|
170
|
+
engine = 'mem';
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
const client = {
|
|
174
|
+
backend: 'cozo-node',
|
|
175
|
+
engine,
|
|
176
|
+
dbPath: engine === 'sqlite' ? dbPath : undefined,
|
|
177
|
+
run: async (script, params) => db.run(script, params ?? {}),
|
|
178
|
+
exportRelations: typeof db.exportRelations === 'function' ? async (rels) => db.exportRelations(rels) : undefined,
|
|
179
|
+
importRelations: typeof db.importRelations === 'function' ? async (data) => db.importRelations(data) : undefined,
|
|
180
|
+
close: typeof db.close === 'function' ? async () => { await db.close(); } : undefined,
|
|
181
|
+
};
|
|
182
|
+
await tryImportFromExportPath(exportPath, client);
|
|
183
|
+
return client;
|
|
184
|
+
}
|
|
185
|
+
catch (e) {
|
|
186
|
+
errors.push(String(e?.message ?? e));
|
|
187
|
+
}
|
|
188
|
+
try {
|
|
189
|
+
const moduleName = 'cozo-lib-wasm';
|
|
190
|
+
const mod = await import(moduleName);
|
|
191
|
+
const init = mod?.default;
|
|
192
|
+
const CozoDb = mod?.CozoDb;
|
|
193
|
+
if (typeof init !== 'function' || typeof CozoDb?.new !== 'function') {
|
|
194
|
+
throw new Error('cozo-lib-wasm loaded but exports are not compatible');
|
|
195
|
+
}
|
|
196
|
+
if (!cozoWasmInit)
|
|
197
|
+
cozoWasmInit = Promise.resolve(init()).then(() => { });
|
|
198
|
+
await cozoWasmInit;
|
|
199
|
+
const db = CozoDb.new();
|
|
200
|
+
const run = async (script, params) => {
|
|
201
|
+
const out = db.run(String(script), JSON.stringify(params ?? {}));
|
|
202
|
+
try {
|
|
203
|
+
return JSON.parse(String(out));
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
return out;
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
const exportRelations = async (relations) => {
|
|
210
|
+
if (typeof db.export_relations !== 'function')
|
|
211
|
+
return null;
|
|
212
|
+
const out = db.export_relations(JSON.stringify(relations));
|
|
213
|
+
try {
|
|
214
|
+
return JSON.parse(String(out));
|
|
215
|
+
}
|
|
216
|
+
catch {
|
|
217
|
+
return out;
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
const importRelations = async (data) => {
|
|
221
|
+
if (typeof db.import_relations !== 'function')
|
|
222
|
+
return null;
|
|
223
|
+
const out = db.import_relations(JSON.stringify(data));
|
|
224
|
+
try {
|
|
225
|
+
return JSON.parse(String(out));
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
return out;
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
const client = {
|
|
232
|
+
backend: 'cozo-wasm',
|
|
233
|
+
engine: 'mem',
|
|
234
|
+
run,
|
|
235
|
+
exportRelations,
|
|
236
|
+
importRelations,
|
|
237
|
+
close: typeof db.free === 'function' ? async () => { db.free(); } : undefined,
|
|
238
|
+
};
|
|
239
|
+
await tryImportFromExportPath(exportPath, client);
|
|
240
|
+
return client;
|
|
241
|
+
}
|
|
242
|
+
catch (e) {
|
|
243
|
+
errors.push(String(e?.message ?? e));
|
|
244
|
+
}
|
|
245
|
+
await fs_extra_1.default.ensureDir(path_1.default.dirname(dbPath));
|
|
246
|
+
await fs_extra_1.default.writeJSON(path_1.default.join(path_1.default.dirname(dbPath), 'cozo.error.json'), { errors }, { spaces: 2 }).catch(() => { });
|
|
247
|
+
return null;
|
|
248
|
+
}
|
|
249
|
+
async function openRepoCozoDb(repoRoot) {
|
|
250
|
+
const errors = [];
|
|
251
|
+
try {
|
|
252
|
+
return await openCozoNode(repoRoot);
|
|
253
|
+
}
|
|
254
|
+
catch (e) {
|
|
255
|
+
errors.push(String(e?.message ?? e));
|
|
256
|
+
}
|
|
257
|
+
try {
|
|
258
|
+
return await openCozoWasm(repoRoot);
|
|
259
|
+
}
|
|
260
|
+
catch (e) {
|
|
261
|
+
errors.push(String(e?.message ?? e));
|
|
262
|
+
}
|
|
263
|
+
await fs_extra_1.default.ensureDir(path_1.default.join(repoRoot, '.git-ai'));
|
|
264
|
+
await fs_extra_1.default.writeJSON(path_1.default.join(repoRoot, '.git-ai', 'cozo.error.json'), { errors }, { spaces: 2 }).catch(() => { });
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildAstLayer = buildAstLayer;
|
|
4
|
+
const types_1 = require("./types");
|
|
5
|
+
function buildAstLayer(filePath, lang, root, options) {
|
|
6
|
+
const nodes = [];
|
|
7
|
+
const edges = [];
|
|
8
|
+
const edgeTypes = [types_1.EdgeType.CHILD, types_1.EdgeType.NEXT_TOKEN];
|
|
9
|
+
const includeNextToken = options?.includeNextToken ?? true;
|
|
10
|
+
const visited = new Set();
|
|
11
|
+
const pushNode = (node) => {
|
|
12
|
+
const id = (0, types_1.astNodeId)(filePath, node);
|
|
13
|
+
if (visited.has(id))
|
|
14
|
+
return id;
|
|
15
|
+
visited.add(id);
|
|
16
|
+
nodes.push((0, types_1.createAstNode)(filePath, lang, node));
|
|
17
|
+
return id;
|
|
18
|
+
};
|
|
19
|
+
const traverse = (node) => {
|
|
20
|
+
const parentId = pushNode(node);
|
|
21
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
22
|
+
const child = node.child(i);
|
|
23
|
+
if (!child)
|
|
24
|
+
continue;
|
|
25
|
+
const childId = pushNode(child);
|
|
26
|
+
edges.push({ from: parentId, to: childId, type: types_1.EdgeType.CHILD });
|
|
27
|
+
traverse(child);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
const linkNextTokens = () => {
|
|
31
|
+
const tokens = [];
|
|
32
|
+
const walk = (node) => {
|
|
33
|
+
if (node.childCount === 0) {
|
|
34
|
+
tokens.push(node);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
38
|
+
const child = node.child(i);
|
|
39
|
+
if (child)
|
|
40
|
+
walk(child);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
walk(root);
|
|
44
|
+
for (let i = 0; i < tokens.length - 1; i++) {
|
|
45
|
+
const fromId = (0, types_1.astNodeId)(filePath, tokens[i]);
|
|
46
|
+
const toId = (0, types_1.astNodeId)(filePath, tokens[i + 1]);
|
|
47
|
+
if (fromId === toId)
|
|
48
|
+
continue;
|
|
49
|
+
edges.push({ from: fromId, to: toId, type: types_1.EdgeType.NEXT_TOKEN });
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
traverse(root);
|
|
53
|
+
if (includeNextToken)
|
|
54
|
+
linkNextTokens();
|
|
55
|
+
return { nodes, edges, edgeTypes };
|
|
56
|
+
}
|