@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,412 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createContextBudget,
|
|
3
|
+
} from "../retrieval/budget.js";
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
formatRetrievalResults,
|
|
7
|
+
} from "./contextBuilder.js";
|
|
8
|
+
|
|
9
|
+
const DEFAULT_RETRIEVAL_OPTIONS =
|
|
10
|
+
Object.freeze({
|
|
11
|
+
limit: 6,
|
|
12
|
+
maxSourceLength: 2500,
|
|
13
|
+
|
|
14
|
+
// Aggregate estimated token budget for
|
|
15
|
+
// repository evidence sent to the model.
|
|
16
|
+
tokenBudget: 6000,
|
|
17
|
+
});
|
|
18
|
+
function shrinkExcerpt(
|
|
19
|
+
content,
|
|
20
|
+
maxLength
|
|
21
|
+
) {
|
|
22
|
+
if (
|
|
23
|
+
typeof content !== "string" ||
|
|
24
|
+
content.length <= maxLength
|
|
25
|
+
) {
|
|
26
|
+
return content;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (maxLength <= 0) {
|
|
30
|
+
return "";
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/*
|
|
34
|
+
* Preserve evidence from both ends of an
|
|
35
|
+
* already relevance-centered retrieval excerpt.
|
|
36
|
+
*
|
|
37
|
+
* Taking only content.slice(0, maxLength)
|
|
38
|
+
* can discard relevant symbols located later
|
|
39
|
+
* in the retrieved excerpt.
|
|
40
|
+
*/
|
|
41
|
+
const separator = "\n...\n";
|
|
42
|
+
|
|
43
|
+
if (
|
|
44
|
+
maxLength <=
|
|
45
|
+
separator.length + 2
|
|
46
|
+
) {
|
|
47
|
+
return content.slice(
|
|
48
|
+
0,
|
|
49
|
+
maxLength
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const available =
|
|
54
|
+
maxLength -
|
|
55
|
+
separator.length;
|
|
56
|
+
|
|
57
|
+
const headLength =
|
|
58
|
+
Math.ceil(
|
|
59
|
+
available / 2
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
const tailLength =
|
|
63
|
+
Math.floor(
|
|
64
|
+
available / 2
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
content.slice(
|
|
69
|
+
0,
|
|
70
|
+
headLength
|
|
71
|
+
) +
|
|
72
|
+
separator +
|
|
73
|
+
content.slice(
|
|
74
|
+
content.length -
|
|
75
|
+
tailLength
|
|
76
|
+
)
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
function selectResultsWithinBudget(
|
|
80
|
+
results,
|
|
81
|
+
tokenBudget
|
|
82
|
+
) {
|
|
83
|
+
const budget =
|
|
84
|
+
createContextBudget(
|
|
85
|
+
tokenBudget
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
if (
|
|
89
|
+
!Array.isArray(results) ||
|
|
90
|
+
results.length === 0
|
|
91
|
+
) {
|
|
92
|
+
return {
|
|
93
|
+
results: [],
|
|
94
|
+
|
|
95
|
+
stats: {
|
|
96
|
+
selected: 0,
|
|
97
|
+
estimatedTokens: 0,
|
|
98
|
+
tokenBudget,
|
|
99
|
+
|
|
100
|
+
remainingTokens:
|
|
101
|
+
Math.max(
|
|
102
|
+
0,
|
|
103
|
+
tokenBudget
|
|
104
|
+
),
|
|
105
|
+
|
|
106
|
+
utilization: 0,
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/*
|
|
112
|
+
* Breadth-first RAG packing.
|
|
113
|
+
*
|
|
114
|
+
* Start with the smallest useful excerpt
|
|
115
|
+
* from every retrieved result. This gives
|
|
116
|
+
* architectural/cross-file queries the best
|
|
117
|
+
* chance of preserving every relevant file.
|
|
118
|
+
*
|
|
119
|
+
* Once breadth has been established, expand
|
|
120
|
+
* higher-ranked results with the remaining
|
|
121
|
+
* context budget.
|
|
122
|
+
*/
|
|
123
|
+
const MIN_EXCERPT_LENGTH = 300;
|
|
124
|
+
|
|
125
|
+
const selected = [];
|
|
126
|
+
|
|
127
|
+
/*
|
|
128
|
+
* First pass:
|
|
129
|
+
*
|
|
130
|
+
* Establish breadth using a minimal excerpt
|
|
131
|
+
* for every result.
|
|
132
|
+
*
|
|
133
|
+
* Importantly, each candidate is measured
|
|
134
|
+
* using the real formatted representation,
|
|
135
|
+
* so file metadata and formatting overhead
|
|
136
|
+
* are included in the budget calculation.
|
|
137
|
+
*/
|
|
138
|
+
for (const result of results) {
|
|
139
|
+
const candidate = {
|
|
140
|
+
...result,
|
|
141
|
+
|
|
142
|
+
content:
|
|
143
|
+
shrinkExcerpt(
|
|
144
|
+
result?.content,
|
|
145
|
+
MIN_EXCERPT_LENGTH
|
|
146
|
+
),
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const candidateResults = [
|
|
150
|
+
...selected,
|
|
151
|
+
candidate,
|
|
152
|
+
];
|
|
153
|
+
|
|
154
|
+
const candidateText =
|
|
155
|
+
formatRetrievalResults(
|
|
156
|
+
candidateResults
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
const candidateTokens =
|
|
160
|
+
budget.estimate(
|
|
161
|
+
candidateText
|
|
162
|
+
);
|
|
163
|
+
if (
|
|
164
|
+
candidateTokens <=
|
|
165
|
+
tokenBudget
|
|
166
|
+
) {
|
|
167
|
+
selected.push(
|
|
168
|
+
candidate
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/*
|
|
174
|
+
* Second pass:
|
|
175
|
+
*
|
|
176
|
+
* Expand selected results in ranking order.
|
|
177
|
+
*
|
|
178
|
+
* Try progressively larger excerpts instead
|
|
179
|
+
* of jumping directly from 300 characters to
|
|
180
|
+
* the full source. This allows unused context
|
|
181
|
+
* budget to be packed much more efficiently.
|
|
182
|
+
*/
|
|
183
|
+
const expansionSizes = [
|
|
184
|
+
500,
|
|
185
|
+
800,
|
|
186
|
+
1200,
|
|
187
|
+
1600,
|
|
188
|
+
2000,
|
|
189
|
+
2500,
|
|
190
|
+
];
|
|
191
|
+
|
|
192
|
+
for (
|
|
193
|
+
let index = 0;
|
|
194
|
+
index < selected.length;
|
|
195
|
+
index += 1
|
|
196
|
+
) {
|
|
197
|
+
const originalResult =
|
|
198
|
+
results.find(
|
|
199
|
+
(result) =>
|
|
200
|
+
result.path ===
|
|
201
|
+
selected[index].path
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
if (
|
|
205
|
+
!originalResult ||
|
|
206
|
+
typeof originalResult.content !==
|
|
207
|
+
"string"
|
|
208
|
+
) {
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
for (
|
|
213
|
+
const maxLength of
|
|
214
|
+
expansionSizes
|
|
215
|
+
) {
|
|
216
|
+
if (
|
|
217
|
+
maxLength <=
|
|
218
|
+
(
|
|
219
|
+
selected[index].content
|
|
220
|
+
?.length ?? 0
|
|
221
|
+
)
|
|
222
|
+
) {
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const expanded = {
|
|
227
|
+
...originalResult,
|
|
228
|
+
|
|
229
|
+
content:
|
|
230
|
+
shrinkExcerpt(
|
|
231
|
+
originalResult.content,
|
|
232
|
+
maxLength
|
|
233
|
+
),
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
const expandedResults = [
|
|
237
|
+
...selected,
|
|
238
|
+
];
|
|
239
|
+
|
|
240
|
+
expandedResults[index] =
|
|
241
|
+
expanded;
|
|
242
|
+
|
|
243
|
+
const expandedText =
|
|
244
|
+
formatRetrievalResults(
|
|
245
|
+
expandedResults
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
if (
|
|
249
|
+
budget.estimate(
|
|
250
|
+
expandedText
|
|
251
|
+
) <= tokenBudget
|
|
252
|
+
) {
|
|
253
|
+
selected[index] =
|
|
254
|
+
expanded;
|
|
255
|
+
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/*
|
|
260
|
+
* Expansion sizes are ascending.
|
|
261
|
+
* If this size does not fit, larger
|
|
262
|
+
* excerpts will not fit either.
|
|
263
|
+
*/
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/*
|
|
268
|
+
* Finally try the complete retrieved
|
|
269
|
+
* excerpt. This matters when the original
|
|
270
|
+
* source length lies between configured
|
|
271
|
+
* expansion sizes or exceeds 2500 due to
|
|
272
|
+
* excerpt markers.
|
|
273
|
+
*/
|
|
274
|
+
if (
|
|
275
|
+
originalResult.content.length >
|
|
276
|
+
(
|
|
277
|
+
selected[index].content
|
|
278
|
+
?.length ?? 0
|
|
279
|
+
)
|
|
280
|
+
) {
|
|
281
|
+
const fullyExpandedResults = [
|
|
282
|
+
...selected,
|
|
283
|
+
];
|
|
284
|
+
|
|
285
|
+
fullyExpandedResults[index] = {
|
|
286
|
+
...originalResult,
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
const fullyExpandedText =
|
|
290
|
+
formatRetrievalResults(
|
|
291
|
+
fullyExpandedResults
|
|
292
|
+
);
|
|
293
|
+
|
|
294
|
+
if (
|
|
295
|
+
budget.estimate(
|
|
296
|
+
fullyExpandedText
|
|
297
|
+
) <= tokenBudget
|
|
298
|
+
) {
|
|
299
|
+
selected[index] = {
|
|
300
|
+
...originalResult,
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const finalText =
|
|
307
|
+
formatRetrievalResults(
|
|
308
|
+
selected
|
|
309
|
+
);
|
|
310
|
+
|
|
311
|
+
const estimatedTokens =
|
|
312
|
+
budget.estimate(
|
|
313
|
+
finalText
|
|
314
|
+
);
|
|
315
|
+
|
|
316
|
+
return {
|
|
317
|
+
results: selected,
|
|
318
|
+
|
|
319
|
+
stats: {
|
|
320
|
+
selected:
|
|
321
|
+
selected.length,
|
|
322
|
+
|
|
323
|
+
estimatedTokens,
|
|
324
|
+
|
|
325
|
+
tokenBudget,
|
|
326
|
+
|
|
327
|
+
remainingTokens:
|
|
328
|
+
Math.max(
|
|
329
|
+
0,
|
|
330
|
+
tokenBudget -
|
|
331
|
+
estimatedTokens
|
|
332
|
+
),
|
|
333
|
+
|
|
334
|
+
utilization:
|
|
335
|
+
tokenBudget === 0
|
|
336
|
+
? 0
|
|
337
|
+
: estimatedTokens /
|
|
338
|
+
tokenBudget,
|
|
339
|
+
},
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
export async function retrieveContext({
|
|
344
|
+
repository,
|
|
345
|
+
plan,
|
|
346
|
+
query,
|
|
347
|
+
options = {},
|
|
348
|
+
}) {
|
|
349
|
+
if (!plan?.requiresRAG) {
|
|
350
|
+
return {
|
|
351
|
+
enabled: false,
|
|
352
|
+
query,
|
|
353
|
+
results: [],
|
|
354
|
+
stats: {
|
|
355
|
+
retrieved: 0,
|
|
356
|
+
},
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
if (!repository?.retriever) {
|
|
361
|
+
throw new Error(
|
|
362
|
+
"Repository retriever has not been initialized."
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const retrievalOptions = {
|
|
367
|
+
...DEFAULT_RETRIEVAL_OPTIONS,
|
|
368
|
+
...options,
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
const {
|
|
372
|
+
tokenBudget,
|
|
373
|
+
...searchOptions
|
|
374
|
+
} = retrievalOptions;
|
|
375
|
+
|
|
376
|
+
const results =
|
|
377
|
+
(await repository.retriever.search(
|
|
378
|
+
query,
|
|
379
|
+
searchOptions
|
|
380
|
+
)) ?? [];
|
|
381
|
+
|
|
382
|
+
const normalizedResults =
|
|
383
|
+
Array.isArray(results)
|
|
384
|
+
? results
|
|
385
|
+
: [results].filter(Boolean);
|
|
386
|
+
|
|
387
|
+
const selection =
|
|
388
|
+
selectResultsWithinBudget(
|
|
389
|
+
normalizedResults,
|
|
390
|
+
tokenBudget
|
|
391
|
+
);
|
|
392
|
+
|
|
393
|
+
return {
|
|
394
|
+
enabled: true,
|
|
395
|
+
query,
|
|
396
|
+
results:
|
|
397
|
+
selection.results,
|
|
398
|
+
|
|
399
|
+
stats: {
|
|
400
|
+
retrieved:
|
|
401
|
+
normalizedResults.length,
|
|
402
|
+
|
|
403
|
+
...selection.stats,
|
|
404
|
+
|
|
405
|
+
limit:
|
|
406
|
+
retrievalOptions.limit,
|
|
407
|
+
|
|
408
|
+
maxSourceLength:
|
|
409
|
+
retrievalOptions.maxSourceLength,
|
|
410
|
+
},
|
|
411
|
+
};
|
|
412
|
+
}
|