@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.
Files changed (141) hide show
  1. package/LICENSE +0 -0
  2. package/README.md +7 -0
  3. package/apps/cli/bin/codeforge.cmd +2 -0
  4. package/apps/cli/src/bootstrap.js +115 -0
  5. package/apps/cli/src/cli.js +189 -0
  6. package/apps/cli/src/dev/git.js +17 -0
  7. package/apps/cli/src/dev/index.js +68 -0
  8. package/apps/cli/src/dev/provider.js +48 -0
  9. package/apps/cli/src/dev/scanner.js +14 -0
  10. package/apps/cli/src/index.js +31 -0
  11. package/bin/codeforge.js +2 -0
  12. package/package.json +63 -0
  13. package/packages/agent/contextBuilder.js +234 -0
  14. package/packages/agent/executor.js +1729 -0
  15. package/packages/agent/fallback.js +129 -0
  16. package/packages/agent/index.js +26 -0
  17. package/packages/agent/intent.js +73 -0
  18. package/packages/agent/modelSelector.js +469 -0
  19. package/packages/agent/planner.js +379 -0
  20. package/packages/agent/rag.js +412 -0
  21. package/packages/agent/ragSelector.js +570 -0
  22. package/packages/agent/router.js +121 -0
  23. package/packages/agent/thinking.js +54 -0
  24. package/packages/agent/toolCalls.js +258 -0
  25. package/packages/config/config.js +391 -0
  26. package/packages/config/defaults.js +72 -0
  27. package/packages/config/index.js +2 -0
  28. package/packages/core/approvalPolicy.js +140 -0
  29. package/packages/core/context.js +0 -0
  30. package/packages/core/message.js +0 -0
  31. package/packages/core/plan.js +0 -0
  32. package/packages/core/reasoning.js +0 -0
  33. package/packages/core/result.js +0 -0
  34. package/packages/core/retrieval.js +0 -0
  35. package/packages/core/tool.js +536 -0
  36. package/packages/git/branch.js +7 -0
  37. package/packages/git/commit.js +16 -0
  38. package/packages/git/diff.js +15 -0
  39. package/packages/git/git.js +35 -0
  40. package/packages/git/index.js +6 -0
  41. package/packages/git/remote.js +9 -0
  42. package/packages/git/status.js +11 -0
  43. package/packages/memory/index.js +0 -0
  44. package/packages/memory/project.js +0 -0
  45. package/packages/memory/session.js +0 -0
  46. package/packages/prompts/builder.js +43 -0
  47. package/packages/prompts/coder.js +38 -0
  48. package/packages/prompts/index.js +5 -0
  49. package/packages/prompts/planner.js +49 -0
  50. package/packages/prompts/reviewer.js +38 -0
  51. package/packages/prompts/system.js +94 -0
  52. package/packages/providers/index.js +31 -0
  53. package/packages/providers/openrouter.js +380 -0
  54. package/packages/reasoning/budget.js +0 -0
  55. package/packages/reasoning/chain.js +0 -0
  56. package/packages/reasoning/coder.js +0 -0
  57. package/packages/reasoning/evaluator.js +0 -0
  58. package/packages/reasoning/index.js +8 -0
  59. package/packages/reasoning/planner.js +0 -0
  60. package/packages/reasoning/reflector.js +0 -0
  61. package/packages/reasoning/reviewer.js +0 -0
  62. package/packages/reasoning/router.js +0 -0
  63. package/packages/retrieval/budget.js +92 -0
  64. package/packages/retrieval/cache.js +84 -0
  65. package/packages/retrieval/embeddings.js +147 -0
  66. package/packages/retrieval/graph.js +151 -0
  67. package/packages/retrieval/imports.js +74 -0
  68. package/packages/retrieval/index.js +9 -0
  69. package/packages/retrieval/parser/extractors/calls.js +43 -0
  70. package/packages/retrieval/parser/extractors/comments.js +49 -0
  71. package/packages/retrieval/parser/extractors/diagnostics.js +21 -0
  72. package/packages/retrieval/parser/extractors/exports.js +71 -0
  73. package/packages/retrieval/parser/extractors/imports.js +40 -0
  74. package/packages/retrieval/parser/extractors/index.js +12 -0
  75. package/packages/retrieval/parser/extractors/metrics.js +78 -0
  76. package/packages/retrieval/parser/extractors/symbols.js +51 -0
  77. package/packages/retrieval/parser/extractors/todos.js +53 -0
  78. package/packages/retrieval/parser/helpers.js +138 -0
  79. package/packages/retrieval/parser/index.js +10 -0
  80. package/packages/retrieval/parser/languages/c.js +14 -0
  81. package/packages/retrieval/parser/languages/cpp.js +21 -0
  82. package/packages/retrieval/parser/languages/csharp.js +14 -0
  83. package/packages/retrieval/parser/languages/go.js +14 -0
  84. package/packages/retrieval/parser/languages/index.js +12 -0
  85. package/packages/retrieval/parser/languages/java.js +14 -0
  86. package/packages/retrieval/parser/languages/javascript.js +14 -0
  87. package/packages/retrieval/parser/languages/php.js +14 -0
  88. package/packages/retrieval/parser/languages/python.js +14 -0
  89. package/packages/retrieval/parser/languages/ruby.js +14 -0
  90. package/packages/retrieval/parser/languages/rust.js +14 -0
  91. package/packages/retrieval/parser/languages/swift.js +14 -0
  92. package/packages/retrieval/parser/languages/typescript.js +14 -0
  93. package/packages/retrieval/parser/languages.js +218 -0
  94. package/packages/retrieval/parser/parseFile.js +79 -0
  95. package/packages/retrieval/parser/parseRepository.js +78 -0
  96. package/packages/retrieval/parser/queries/c.js +148 -0
  97. package/packages/retrieval/parser/queries/cpp.js +198 -0
  98. package/packages/retrieval/parser/queries/csharp.js +151 -0
  99. package/packages/retrieval/parser/queries/go.js +124 -0
  100. package/packages/retrieval/parser/queries/index.js +35 -0
  101. package/packages/retrieval/parser/queries/java.js +128 -0
  102. package/packages/retrieval/parser/queries/javascript.js +181 -0
  103. package/packages/retrieval/parser/queries/php.js +140 -0
  104. package/packages/retrieval/parser/queries/python.js +110 -0
  105. package/packages/retrieval/parser/queries/ruby.js +105 -0
  106. package/packages/retrieval/parser/queries/rust.js +175 -0
  107. package/packages/retrieval/parser/queries/swift.js +134 -0
  108. package/packages/retrieval/parser/queries/typescript.js +202 -0
  109. package/packages/retrieval/parser/registry.js +107 -0
  110. package/packages/retrieval/parser/traverse.js +82 -0
  111. package/packages/retrieval/parser/types.js +239 -0
  112. package/packages/retrieval/parser.js +78 -0
  113. package/packages/retrieval/ranker.js +73 -0
  114. package/packages/retrieval/retriever.js +910 -0
  115. package/packages/retrieval/symbols.js +145 -0
  116. package/packages/scanner/detect.js +69 -0
  117. package/packages/scanner/ignore.js +12 -0
  118. package/packages/scanner/index.js +2 -0
  119. package/packages/scanner/root.js +21 -0
  120. package/packages/scanner/scanner.js +35 -0
  121. package/packages/scanner/tree.js +45 -0
  122. package/packages/terminal/activity.js +514 -0
  123. package/packages/terminal/banner.js +34 -0
  124. package/packages/terminal/colors.js +16 -0
  125. package/packages/terminal/dashboard.js +94 -0
  126. package/packages/terminal/index.js +19 -0
  127. package/packages/terminal/logger.js +43 -0
  128. package/packages/terminal/prompt.js +11 -0
  129. package/packages/terminal/renderer.js +1209 -0
  130. package/packages/terminal/spinner.js +9 -0
  131. package/packages/tools/editFile.js +261 -0
  132. package/packages/tools/filesystem.js +82 -0
  133. package/packages/tools/index.js +24 -0
  134. package/packages/tools/readFile.js +101 -0
  135. package/packages/tools/registry.js +227 -0
  136. package/packages/tools/searchFiles.js +322 -0
  137. package/packages/tools/shell.js +352 -0
  138. package/packages/tools/writeFile.js +212 -0
  139. package/packages/utils/constants.js +0 -0
  140. package/packages/utils/helpers.js +0 -0
  141. 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
+ }