@oisheek_c/codeforge 1.0.1
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 +0 -0
- package/README.md +7 -0
- package/apps/cli/bin/codeforge.cmd +2 -0
- package/apps/cli/src/bootstrap.js +115 -0
- package/apps/cli/src/cli.js +189 -0
- package/apps/cli/src/dev/git.js +17 -0
- package/apps/cli/src/dev/index.js +68 -0
- package/apps/cli/src/dev/provider.js +48 -0
- package/apps/cli/src/dev/scanner.js +14 -0
- package/apps/cli/src/index.js +31 -0
- package/bin/codeforge.js +2 -0
- package/package.json +63 -0
- package/packages/agent/contextBuilder.js +234 -0
- package/packages/agent/executor.js +1729 -0
- package/packages/agent/fallback.js +129 -0
- package/packages/agent/index.js +26 -0
- package/packages/agent/intent.js +73 -0
- package/packages/agent/modelSelector.js +469 -0
- package/packages/agent/planner.js +379 -0
- package/packages/agent/rag.js +412 -0
- package/packages/agent/ragSelector.js +570 -0
- package/packages/agent/router.js +121 -0
- package/packages/agent/thinking.js +54 -0
- package/packages/agent/toolCalls.js +258 -0
- package/packages/config/config.js +391 -0
- package/packages/config/defaults.js +72 -0
- package/packages/config/index.js +2 -0
- package/packages/core/approvalPolicy.js +140 -0
- package/packages/core/context.js +0 -0
- package/packages/core/message.js +0 -0
- package/packages/core/plan.js +0 -0
- package/packages/core/reasoning.js +0 -0
- package/packages/core/result.js +0 -0
- package/packages/core/retrieval.js +0 -0
- package/packages/core/tool.js +536 -0
- package/packages/git/branch.js +7 -0
- package/packages/git/commit.js +16 -0
- package/packages/git/diff.js +15 -0
- package/packages/git/git.js +35 -0
- package/packages/git/index.js +6 -0
- package/packages/git/remote.js +9 -0
- package/packages/git/status.js +11 -0
- package/packages/memory/index.js +0 -0
- package/packages/memory/project.js +0 -0
- package/packages/memory/session.js +0 -0
- package/packages/prompts/builder.js +43 -0
- package/packages/prompts/coder.js +38 -0
- package/packages/prompts/index.js +5 -0
- package/packages/prompts/planner.js +49 -0
- package/packages/prompts/reviewer.js +38 -0
- package/packages/prompts/system.js +94 -0
- package/packages/providers/index.js +31 -0
- package/packages/providers/openrouter.js +380 -0
- package/packages/reasoning/budget.js +0 -0
- package/packages/reasoning/chain.js +0 -0
- package/packages/reasoning/coder.js +0 -0
- package/packages/reasoning/evaluator.js +0 -0
- package/packages/reasoning/index.js +8 -0
- package/packages/reasoning/planner.js +0 -0
- package/packages/reasoning/reflector.js +0 -0
- package/packages/reasoning/reviewer.js +0 -0
- package/packages/reasoning/router.js +0 -0
- package/packages/retrieval/budget.js +92 -0
- package/packages/retrieval/cache.js +84 -0
- package/packages/retrieval/embeddings.js +147 -0
- package/packages/retrieval/graph.js +151 -0
- package/packages/retrieval/imports.js +74 -0
- package/packages/retrieval/index.js +9 -0
- package/packages/retrieval/parser/extractors/calls.js +43 -0
- package/packages/retrieval/parser/extractors/comments.js +49 -0
- package/packages/retrieval/parser/extractors/diagnostics.js +21 -0
- package/packages/retrieval/parser/extractors/exports.js +71 -0
- package/packages/retrieval/parser/extractors/imports.js +40 -0
- package/packages/retrieval/parser/extractors/index.js +12 -0
- package/packages/retrieval/parser/extractors/metrics.js +78 -0
- package/packages/retrieval/parser/extractors/symbols.js +51 -0
- package/packages/retrieval/parser/extractors/todos.js +53 -0
- package/packages/retrieval/parser/helpers.js +138 -0
- package/packages/retrieval/parser/index.js +10 -0
- package/packages/retrieval/parser/languages/c.js +14 -0
- package/packages/retrieval/parser/languages/cpp.js +21 -0
- package/packages/retrieval/parser/languages/csharp.js +14 -0
- package/packages/retrieval/parser/languages/go.js +14 -0
- package/packages/retrieval/parser/languages/index.js +12 -0
- package/packages/retrieval/parser/languages/java.js +14 -0
- package/packages/retrieval/parser/languages/javascript.js +14 -0
- package/packages/retrieval/parser/languages/php.js +14 -0
- package/packages/retrieval/parser/languages/python.js +14 -0
- package/packages/retrieval/parser/languages/ruby.js +14 -0
- package/packages/retrieval/parser/languages/rust.js +14 -0
- package/packages/retrieval/parser/languages/swift.js +14 -0
- package/packages/retrieval/parser/languages/typescript.js +14 -0
- package/packages/retrieval/parser/languages.js +218 -0
- package/packages/retrieval/parser/parseFile.js +79 -0
- package/packages/retrieval/parser/parseRepository.js +78 -0
- package/packages/retrieval/parser/queries/c.js +148 -0
- package/packages/retrieval/parser/queries/cpp.js +198 -0
- package/packages/retrieval/parser/queries/csharp.js +151 -0
- package/packages/retrieval/parser/queries/go.js +124 -0
- package/packages/retrieval/parser/queries/index.js +35 -0
- package/packages/retrieval/parser/queries/java.js +128 -0
- package/packages/retrieval/parser/queries/javascript.js +181 -0
- package/packages/retrieval/parser/queries/php.js +140 -0
- package/packages/retrieval/parser/queries/python.js +110 -0
- package/packages/retrieval/parser/queries/ruby.js +105 -0
- package/packages/retrieval/parser/queries/rust.js +175 -0
- package/packages/retrieval/parser/queries/swift.js +134 -0
- package/packages/retrieval/parser/queries/typescript.js +202 -0
- package/packages/retrieval/parser/registry.js +107 -0
- package/packages/retrieval/parser/traverse.js +82 -0
- package/packages/retrieval/parser/types.js +239 -0
- package/packages/retrieval/parser.js +78 -0
- package/packages/retrieval/ranker.js +73 -0
- package/packages/retrieval/retriever.js +910 -0
- package/packages/retrieval/symbols.js +145 -0
- package/packages/scanner/detect.js +69 -0
- package/packages/scanner/ignore.js +12 -0
- package/packages/scanner/index.js +2 -0
- package/packages/scanner/root.js +21 -0
- package/packages/scanner/scanner.js +35 -0
- package/packages/scanner/tree.js +45 -0
- package/packages/terminal/activity.js +514 -0
- package/packages/terminal/banner.js +34 -0
- package/packages/terminal/colors.js +16 -0
- package/packages/terminal/dashboard.js +94 -0
- package/packages/terminal/index.js +19 -0
- package/packages/terminal/logger.js +43 -0
- package/packages/terminal/prompt.js +11 -0
- package/packages/terminal/renderer.js +1209 -0
- package/packages/terminal/spinner.js +9 -0
- package/packages/tools/editFile.js +261 -0
- package/packages/tools/filesystem.js +82 -0
- package/packages/tools/index.js +24 -0
- package/packages/tools/readFile.js +101 -0
- package/packages/tools/registry.js +227 -0
- package/packages/tools/searchFiles.js +322 -0
- package/packages/tools/shell.js +352 -0
- package/packages/tools/writeFile.js +212 -0
- package/packages/utils/constants.js +0 -0
- package/packages/utils/helpers.js +0 -0
- package/packages/utils/logger.js +0 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* packages/retrieval/budget.js
|
|
3
|
+
*
|
|
4
|
+
* Context budget manager.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export class ContextBudget {
|
|
8
|
+
constructor(limit = 16000) {
|
|
9
|
+
this.limit = limit;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Estimate token count.
|
|
14
|
+
*
|
|
15
|
+
* Default heuristic:
|
|
16
|
+
* 1 token ≈ 4 characters.
|
|
17
|
+
*/
|
|
18
|
+
estimate(text = "") {
|
|
19
|
+
return Math.ceil(text.length / 4);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Select as many items as fit within the budget.
|
|
24
|
+
*/
|
|
25
|
+
select(items) {
|
|
26
|
+
let used = 0;
|
|
27
|
+
|
|
28
|
+
const selected = [];
|
|
29
|
+
|
|
30
|
+
for (const item of items) {
|
|
31
|
+
const text =
|
|
32
|
+
item.text ??
|
|
33
|
+
item.metadata?.text ??
|
|
34
|
+
"";
|
|
35
|
+
|
|
36
|
+
const cost = this.estimate(text);
|
|
37
|
+
|
|
38
|
+
if (used + cost > this.limit) {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
used += cost;
|
|
43
|
+
selected.push(item);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
items: selected,
|
|
48
|
+
used,
|
|
49
|
+
remaining: this.limit - used,
|
|
50
|
+
limit: this.limit,
|
|
51
|
+
utilization:
|
|
52
|
+
this.limit === 0
|
|
53
|
+
? 0
|
|
54
|
+
: used / this.limit,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Check whether a single item fits.
|
|
60
|
+
*/
|
|
61
|
+
fits(item) {
|
|
62
|
+
const text =
|
|
63
|
+
item.text ??
|
|
64
|
+
item.metadata?.text ??
|
|
65
|
+
"";
|
|
66
|
+
|
|
67
|
+
return this.estimate(text) <= this.limit;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Remaining budget after using some tokens.
|
|
72
|
+
*/
|
|
73
|
+
remaining(used) {
|
|
74
|
+
return Math.max(0, this.limit - used);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Budget statistics.
|
|
79
|
+
*/
|
|
80
|
+
stats() {
|
|
81
|
+
return {
|
|
82
|
+
limit: this.limit,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Factory.
|
|
89
|
+
*/
|
|
90
|
+
export function createContextBudget(limit) {
|
|
91
|
+
return new ContextBudget(limit);
|
|
92
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* packages/retrieval/cache.js
|
|
3
|
+
*
|
|
4
|
+
* Simple in-memory cache for retrieval artifacts.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export class RetrievalCache {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.clear();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
clear() {
|
|
13
|
+
this.cache = new Map();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Check if a key exists.
|
|
18
|
+
*/
|
|
19
|
+
has(key) {
|
|
20
|
+
return this.cache.has(key);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Retrieve a cached value.
|
|
25
|
+
*/
|
|
26
|
+
get(key) {
|
|
27
|
+
const entry = this.cache.get(key);
|
|
28
|
+
|
|
29
|
+
if (!entry) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return entry.value;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Store a value.
|
|
38
|
+
*/
|
|
39
|
+
set(key, value) {
|
|
40
|
+
this.cache.set(key, {
|
|
41
|
+
value,
|
|
42
|
+
createdAt: Date.now(),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
return value;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Remove one cache entry.
|
|
50
|
+
*/
|
|
51
|
+
delete(key) {
|
|
52
|
+
return this.cache.delete(key);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Number of cached entries.
|
|
57
|
+
*/
|
|
58
|
+
size() {
|
|
59
|
+
return this.cache.size;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* List all cache keys.
|
|
64
|
+
*/
|
|
65
|
+
keys() {
|
|
66
|
+
return [...this.cache.keys()];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Cache statistics.
|
|
71
|
+
*/
|
|
72
|
+
stats() {
|
|
73
|
+
return {
|
|
74
|
+
entries: this.cache.size,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Factory.
|
|
81
|
+
*/
|
|
82
|
+
export function createRetrievalCache() {
|
|
83
|
+
return new RetrievalCache();
|
|
84
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* packages/retrieval/embeddings.js
|
|
3
|
+
*
|
|
4
|
+
* Embedding provider abstraction and vector store.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Base embedding provider.
|
|
9
|
+
*/
|
|
10
|
+
export class EmbeddingProvider {
|
|
11
|
+
async embed(_text) {
|
|
12
|
+
throw new Error("embed() not implemented");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async embedBatch(texts) {
|
|
16
|
+
return Promise.all(
|
|
17
|
+
texts.map(text => this.embed(text))
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Normalize a vector.
|
|
24
|
+
*/
|
|
25
|
+
export function normalizeVector(vector) {
|
|
26
|
+
const magnitude = Math.sqrt(
|
|
27
|
+
vector.reduce((sum, value) => sum + value * value, 0)
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
if (magnitude === 0) {
|
|
31
|
+
return [...vector];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return vector.map(value => value / magnitude);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* In-memory embedding store.
|
|
39
|
+
*/
|
|
40
|
+
export class EmbeddingStore {
|
|
41
|
+
constructor() {
|
|
42
|
+
this.clear();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
clear() {
|
|
46
|
+
this.vectors = new Map();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
set(key, embedding, metadata = {}) {
|
|
50
|
+
this.vectors.set(key, {
|
|
51
|
+
embedding: normalizeVector(embedding),
|
|
52
|
+
metadata,
|
|
53
|
+
createdAt: Date.now(),
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
setMany(entries) {
|
|
58
|
+
for (const entry of entries) {
|
|
59
|
+
this.set(
|
|
60
|
+
entry.key,
|
|
61
|
+
entry.embedding,
|
|
62
|
+
entry.metadata
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
get(key) {
|
|
68
|
+
return this.vectors.get(key) ?? null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
has(key) {
|
|
72
|
+
return this.vectors.has(key);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
delete(key) {
|
|
76
|
+
return this.vectors.delete(key);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
entries() {
|
|
80
|
+
return [...this.vectors.entries()];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
size() {
|
|
84
|
+
return this.vectors.size;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
stats() {
|
|
88
|
+
return {
|
|
89
|
+
vectors: this.vectors.size,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Cosine similarity.
|
|
96
|
+
*/
|
|
97
|
+
export function cosineSimilarity(a, b) {
|
|
98
|
+
if (
|
|
99
|
+
!Array.isArray(a) ||
|
|
100
|
+
!Array.isArray(b) ||
|
|
101
|
+
a.length !== b.length ||
|
|
102
|
+
a.length === 0
|
|
103
|
+
) {
|
|
104
|
+
return 0;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
let dot = 0;
|
|
108
|
+
|
|
109
|
+
let magA = 0;
|
|
110
|
+
let magB = 0;
|
|
111
|
+
|
|
112
|
+
for (let i = 0; i < a.length; i++) {
|
|
113
|
+
dot += a[i] * b[i];
|
|
114
|
+
magA += a[i] * a[i];
|
|
115
|
+
magB += b[i] * b[i];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (magA === 0 || magB === 0) {
|
|
119
|
+
return 0;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return dot / (Math.sqrt(magA) * Math.sqrt(magB));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Search embeddings.
|
|
127
|
+
*/
|
|
128
|
+
export function searchEmbeddings(queryVector, store) {
|
|
129
|
+
const query = normalizeVector(queryVector);
|
|
130
|
+
|
|
131
|
+
return store
|
|
132
|
+
.entries()
|
|
133
|
+
.map(([key, value]) => ({
|
|
134
|
+
key,
|
|
135
|
+
score: cosineSimilarity(
|
|
136
|
+
query,
|
|
137
|
+
value.embedding
|
|
138
|
+
),
|
|
139
|
+
metadata: value.metadata,
|
|
140
|
+
}))
|
|
141
|
+
.sort((a, b) => b.score - a.score);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Default singleton store.
|
|
146
|
+
*/
|
|
147
|
+
export const embeddingStore = new EmbeddingStore();
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* packages/retrieval/graph.js
|
|
3
|
+
*
|
|
4
|
+
* Repository dependency graph.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export class RepositoryGraph {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.clear();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
clear() {
|
|
13
|
+
this.files = new Map();
|
|
14
|
+
|
|
15
|
+
// Graph edges
|
|
16
|
+
this.dependencies = new Map();
|
|
17
|
+
this.dependents = new Map();
|
|
18
|
+
|
|
19
|
+
// External indexes
|
|
20
|
+
this.symbolIndex = null;
|
|
21
|
+
this.importIndex = null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Build graph from repository indexes.
|
|
26
|
+
*/
|
|
27
|
+
build(repository, symbolIndex, importIndex) {
|
|
28
|
+
this.clear();
|
|
29
|
+
|
|
30
|
+
this.symbolIndex = symbolIndex;
|
|
31
|
+
this.importIndex = importIndex;
|
|
32
|
+
|
|
33
|
+
const files = repository.files ?? repository;
|
|
34
|
+
|
|
35
|
+
for (const file of files) {
|
|
36
|
+
this.addFile(file);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return this;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Add one parsed file.
|
|
44
|
+
*/
|
|
45
|
+
addFile(parsedFile) {
|
|
46
|
+
this.files.set(parsedFile.path, parsedFile);
|
|
47
|
+
|
|
48
|
+
const edges = new Set();
|
|
49
|
+
|
|
50
|
+
const imports = this.importIndex?.file(parsedFile.path) ?? [];
|
|
51
|
+
|
|
52
|
+
for (const imp of imports) {
|
|
53
|
+
edges.add(imp.source);
|
|
54
|
+
|
|
55
|
+
if (!this.dependents.has(imp.source)) {
|
|
56
|
+
this.dependents.set(imp.source, new Set());
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
this.dependents
|
|
60
|
+
.get(imp.source)
|
|
61
|
+
.add(parsedFile.path);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
this.dependencies.set(parsedFile.path, edges);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Lookup a parsed file.
|
|
69
|
+
*/
|
|
70
|
+
getFile(path) {
|
|
71
|
+
return this.files.get(path) ?? null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* All parsed files.
|
|
76
|
+
*/
|
|
77
|
+
getFiles() {
|
|
78
|
+
return [...this.files.values()];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* File dependencies.
|
|
83
|
+
*/
|
|
84
|
+
getDependencies(path) {
|
|
85
|
+
return [...(this.dependencies.get(path) ?? [])];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Reverse dependencies.
|
|
90
|
+
*/
|
|
91
|
+
getDependents(module) {
|
|
92
|
+
return [...(this.dependents.get(module) ?? [])];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Symbol lookup.
|
|
97
|
+
*
|
|
98
|
+
* Delegates to SymbolIndex.
|
|
99
|
+
*/
|
|
100
|
+
findSymbol(name) {
|
|
101
|
+
return this.symbolIndex?.find(name) ?? [];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* File exists.
|
|
106
|
+
*/
|
|
107
|
+
hasFile(path) {
|
|
108
|
+
return this.files.has(path);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Repository statistics.
|
|
113
|
+
*/
|
|
114
|
+
stats() {
|
|
115
|
+
let edgeCount = 0;
|
|
116
|
+
|
|
117
|
+
for (const deps of this.dependencies.values()) {
|
|
118
|
+
edgeCount += deps.size;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
files: this.files.size,
|
|
123
|
+
edges: edgeCount,
|
|
124
|
+
symbols: this.symbolIndex?.stats().total ?? 0,
|
|
125
|
+
modules: this.importIndex?.stats().modules ?? 0,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
fileCount() {
|
|
130
|
+
return this.files.size;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
symbolCount() {
|
|
134
|
+
return this.symbolIndex?.stats().total ?? 0;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Convenience builder.
|
|
140
|
+
*/
|
|
141
|
+
export function buildRepositoryGraph(
|
|
142
|
+
repository,
|
|
143
|
+
symbolIndex,
|
|
144
|
+
importIndex
|
|
145
|
+
) {
|
|
146
|
+
return new RepositoryGraph().build(
|
|
147
|
+
repository,
|
|
148
|
+
symbolIndex,
|
|
149
|
+
importIndex
|
|
150
|
+
);
|
|
151
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* packages/retrieval/imports.js
|
|
3
|
+
*
|
|
4
|
+
* Repository-wide import index.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export class ImportIndex {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.clear();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
clear() {
|
|
13
|
+
this.byFile = new Map();
|
|
14
|
+
this.bySource = new Map();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
add(file, imp) {
|
|
18
|
+
if (!this.byFile.has(file)) {
|
|
19
|
+
this.byFile.set(file, []);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
this.byFile.get(file).push(imp);
|
|
23
|
+
|
|
24
|
+
if (!this.bySource.has(imp.source)) {
|
|
25
|
+
this.bySource.set(imp.source, []);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
this.bySource.get(imp.source).push({
|
|
29
|
+
file,
|
|
30
|
+
import: imp,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
addFile(parsedFile) {
|
|
35
|
+
if (!parsedFile?.imports) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
for (const imp of parsedFile.imports) {
|
|
40
|
+
this.add(parsedFile.path, imp);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
build(repository) {
|
|
45
|
+
this.clear();
|
|
46
|
+
|
|
47
|
+
const files = repository.files ?? repository;
|
|
48
|
+
|
|
49
|
+
for (const file of files) {
|
|
50
|
+
this.addFile(file);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return this;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
file(path) {
|
|
57
|
+
return this.byFile.get(path) ?? [];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
source(module) {
|
|
61
|
+
return this.bySource.get(module) ?? [];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
stats() {
|
|
65
|
+
return {
|
|
66
|
+
files: this.byFile.size,
|
|
67
|
+
modules: this.bySource.size,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function buildImportIndex(repository) {
|
|
73
|
+
return new ImportIndex().build(repository);
|
|
74
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from "./budget.js";
|
|
2
|
+
export * from "./cache.js";
|
|
3
|
+
export * from "./embeddings.js";
|
|
4
|
+
export * from "./graph.js";
|
|
5
|
+
export * from "./imports.js";
|
|
6
|
+
export * from "./parser.js";
|
|
7
|
+
export * from "./ranker.js";
|
|
8
|
+
export * from "./retriever.js";
|
|
9
|
+
export * from "./symbols.js";
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* packages/retrieval/parser/extractors/calls.js
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
iterateCaptures,
|
|
7
|
+
getNodeLocation,
|
|
8
|
+
getNodeText,
|
|
9
|
+
} from "../helpers.js";
|
|
10
|
+
|
|
11
|
+
import { createCall } from "../types.js";
|
|
12
|
+
|
|
13
|
+
export default function extractCalls({
|
|
14
|
+
query,
|
|
15
|
+
tree,
|
|
16
|
+
source,
|
|
17
|
+
}) {
|
|
18
|
+
const calls = [];
|
|
19
|
+
|
|
20
|
+
if (!query) {
|
|
21
|
+
return calls;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
for (const { node, name } of iterateCaptures(query, tree)) {
|
|
25
|
+
calls.push(
|
|
26
|
+
createCall({
|
|
27
|
+
// Query should capture the called identifier/member.
|
|
28
|
+
name: node.text,
|
|
29
|
+
|
|
30
|
+
// e.g. call.function, call.method, call.constructor
|
|
31
|
+
kind: name.replace(/^call\./, ""),
|
|
32
|
+
|
|
33
|
+
location: getNodeLocation(node),
|
|
34
|
+
|
|
35
|
+
metadata: {
|
|
36
|
+
text: getNodeText(node, source),
|
|
37
|
+
},
|
|
38
|
+
})
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return calls;
|
|
43
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* packages/retrieval/parser/extractors/comments.js
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
iterateCaptures,
|
|
7
|
+
getNodeLocation,
|
|
8
|
+
getNodeText,
|
|
9
|
+
} from "../helpers.js";
|
|
10
|
+
|
|
11
|
+
import { createComment } from "../types.js";
|
|
12
|
+
|
|
13
|
+
export default function extractComments({
|
|
14
|
+
query,
|
|
15
|
+
tree,
|
|
16
|
+
source,
|
|
17
|
+
}) {
|
|
18
|
+
const comments = [];
|
|
19
|
+
|
|
20
|
+
if (!query) {
|
|
21
|
+
return comments;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
for (const { node } of iterateCaptures(query, tree)) {
|
|
25
|
+
const text = getNodeText(node, source);
|
|
26
|
+
|
|
27
|
+
comments.push(
|
|
28
|
+
createComment({
|
|
29
|
+
text,
|
|
30
|
+
|
|
31
|
+
block: text.startsWith("/*"),
|
|
32
|
+
|
|
33
|
+
documentation:
|
|
34
|
+
text.startsWith("/**") ||
|
|
35
|
+
text.startsWith("///"),
|
|
36
|
+
|
|
37
|
+
line: node.startPosition.row + 1,
|
|
38
|
+
|
|
39
|
+
metadata: {
|
|
40
|
+
raw: text,
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
location: getNodeLocation(node),
|
|
44
|
+
})
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return comments;
|
|
49
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* packages/retrieval/parser/extractors/diagnostics.js
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { createDiagnostic } from "../types.js";
|
|
6
|
+
|
|
7
|
+
export default function extractDiagnostics({
|
|
8
|
+
tree,
|
|
9
|
+
}) {
|
|
10
|
+
if (!tree.rootNode.hasError) {
|
|
11
|
+
return [];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return [
|
|
15
|
+
createDiagnostic({
|
|
16
|
+
severity: "error",
|
|
17
|
+
type: "syntax",
|
|
18
|
+
message: "Tree-sitter detected syntax errors.",
|
|
19
|
+
}),
|
|
20
|
+
];
|
|
21
|
+
}
|