@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,536 @@
|
|
|
1
|
+
import {
|
|
2
|
+
evaluateApprovalPolicy,
|
|
3
|
+
} from "./approvalPolicy.js";
|
|
4
|
+
|
|
5
|
+
const TOOL_SOURCES = new Set([
|
|
6
|
+
"builtin",
|
|
7
|
+
"plugin",
|
|
8
|
+
"mcp",
|
|
9
|
+
]);
|
|
10
|
+
|
|
11
|
+
const SIDE_EFFECTS = new Set([
|
|
12
|
+
"none",
|
|
13
|
+
"write",
|
|
14
|
+
"execute",
|
|
15
|
+
"destructive",
|
|
16
|
+
]);
|
|
17
|
+
|
|
18
|
+
const APPROVAL_MODES = new Set([
|
|
19
|
+
"never",
|
|
20
|
+
"policy",
|
|
21
|
+
"always",
|
|
22
|
+
]);
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
const APPROVAL_DECISIONS = new Set([
|
|
26
|
+
"approved",
|
|
27
|
+
"denied",
|
|
28
|
+
]);
|
|
29
|
+
function assertNonEmptyString(value, name) {
|
|
30
|
+
if (
|
|
31
|
+
typeof value !== "string" ||
|
|
32
|
+
value.trim().length === 0
|
|
33
|
+
) {
|
|
34
|
+
throw new TypeError(
|
|
35
|
+
`${name} must be a non-empty string.`
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function normalizeCapabilities(capabilities) {
|
|
41
|
+
if (capabilities == null) {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (!Array.isArray(capabilities)) {
|
|
46
|
+
throw new TypeError(
|
|
47
|
+
"Tool capabilities must be an array."
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return [
|
|
52
|
+
...new Set(
|
|
53
|
+
capabilities.map((capability) => {
|
|
54
|
+
assertNonEmptyString(
|
|
55
|
+
capability,
|
|
56
|
+
"Tool capability"
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
return capability.trim();
|
|
60
|
+
})
|
|
61
|
+
),
|
|
62
|
+
];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function normalizeInputSchema(schema) {
|
|
66
|
+
if (schema == null) {
|
|
67
|
+
return {
|
|
68
|
+
type: "object",
|
|
69
|
+
properties: {},
|
|
70
|
+
additionalProperties: false,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (
|
|
75
|
+
typeof schema !== "object" ||
|
|
76
|
+
Array.isArray(schema)
|
|
77
|
+
) {
|
|
78
|
+
throw new TypeError(
|
|
79
|
+
"Tool input schema must be an object."
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return schema;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function defineTool({
|
|
87
|
+
name,
|
|
88
|
+
description,
|
|
89
|
+
version = "1.0.0",
|
|
90
|
+
source = "builtin",
|
|
91
|
+
inputSchema,
|
|
92
|
+
capabilities = [],
|
|
93
|
+
sideEffect = "none",
|
|
94
|
+
approval = "policy",
|
|
95
|
+
execute,
|
|
96
|
+
}) {
|
|
97
|
+
assertNonEmptyString(name, "Tool name");
|
|
98
|
+
assertNonEmptyString(
|
|
99
|
+
description,
|
|
100
|
+
"Tool description"
|
|
101
|
+
);
|
|
102
|
+
assertNonEmptyString(
|
|
103
|
+
version,
|
|
104
|
+
"Tool version"
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
if (!TOOL_SOURCES.has(source)) {
|
|
108
|
+
throw new TypeError(
|
|
109
|
+
`Invalid tool source: ${source}`
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (!SIDE_EFFECTS.has(sideEffect)) {
|
|
114
|
+
throw new TypeError(
|
|
115
|
+
`Invalid tool side effect: ${sideEffect}`
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (!APPROVAL_MODES.has(approval)) {
|
|
120
|
+
throw new TypeError(
|
|
121
|
+
`Invalid tool approval mode: ${approval}`
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (typeof execute !== "function") {
|
|
126
|
+
throw new TypeError(
|
|
127
|
+
"Tool execute must be a function."
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return Object.freeze({
|
|
132
|
+
name: name.trim(),
|
|
133
|
+
description: description.trim(),
|
|
134
|
+
version: version.trim(),
|
|
135
|
+
|
|
136
|
+
source,
|
|
137
|
+
|
|
138
|
+
inputSchema:
|
|
139
|
+
normalizeInputSchema(inputSchema),
|
|
140
|
+
|
|
141
|
+
capabilities:
|
|
142
|
+
Object.freeze(
|
|
143
|
+
normalizeCapabilities(capabilities)
|
|
144
|
+
),
|
|
145
|
+
|
|
146
|
+
sideEffect,
|
|
147
|
+
approval,
|
|
148
|
+
|
|
149
|
+
execute,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function createToolResult({
|
|
154
|
+
tool,
|
|
155
|
+
success,
|
|
156
|
+
output = null,
|
|
157
|
+
error = null,
|
|
158
|
+
metadata = {},
|
|
159
|
+
startedAt = null,
|
|
160
|
+
completedAt = null,
|
|
161
|
+
}) {
|
|
162
|
+
assertNonEmptyString(tool, "Tool result tool");
|
|
163
|
+
|
|
164
|
+
if (typeof success !== "boolean") {
|
|
165
|
+
throw new TypeError(
|
|
166
|
+
"Tool result success must be a boolean."
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (
|
|
171
|
+
metadata == null ||
|
|
172
|
+
typeof metadata !== "object" ||
|
|
173
|
+
Array.isArray(metadata)
|
|
174
|
+
) {
|
|
175
|
+
throw new TypeError(
|
|
176
|
+
"Tool result metadata must be an object."
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const durationMs =
|
|
181
|
+
Number.isFinite(startedAt) &&
|
|
182
|
+
Number.isFinite(completedAt)
|
|
183
|
+
? Math.max(
|
|
184
|
+
0,
|
|
185
|
+
completedAt - startedAt
|
|
186
|
+
)
|
|
187
|
+
: null;
|
|
188
|
+
|
|
189
|
+
return {
|
|
190
|
+
success,
|
|
191
|
+
tool: tool.trim(),
|
|
192
|
+
|
|
193
|
+
output:
|
|
194
|
+
success
|
|
195
|
+
? output
|
|
196
|
+
: null,
|
|
197
|
+
|
|
198
|
+
error:
|
|
199
|
+
success
|
|
200
|
+
? null
|
|
201
|
+
: normalizeToolError(error),
|
|
202
|
+
|
|
203
|
+
metadata,
|
|
204
|
+
|
|
205
|
+
timing: {
|
|
206
|
+
startedAt,
|
|
207
|
+
completedAt,
|
|
208
|
+
durationMs,
|
|
209
|
+
},
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
function normalizeAllowedCapabilities(
|
|
213
|
+
capabilities
|
|
214
|
+
) {
|
|
215
|
+
if (capabilities == null) {
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (!Array.isArray(capabilities)) {
|
|
220
|
+
throw new TypeError(
|
|
221
|
+
"Allowed capabilities must be an array."
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return new Set(
|
|
226
|
+
normalizeCapabilities(capabilities)
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function hasRequiredCapabilities(
|
|
231
|
+
tool,
|
|
232
|
+
allowedCapabilities
|
|
233
|
+
) {
|
|
234
|
+
if (allowedCapabilities === null) {
|
|
235
|
+
return true;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return tool.capabilities.every(
|
|
239
|
+
(capability) =>
|
|
240
|
+
allowedCapabilities.has(capability)
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
export function authorizeToolExecution(
|
|
244
|
+
tool,
|
|
245
|
+
{
|
|
246
|
+
allowedCapabilities = null,
|
|
247
|
+
approval = null,
|
|
248
|
+
policy = {},
|
|
249
|
+
} = {}
|
|
250
|
+
) {
|
|
251
|
+
if (!isTool(tool)) {
|
|
252
|
+
throw new TypeError(
|
|
253
|
+
"Invalid tool."
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const capabilities =
|
|
258
|
+
normalizeAllowedCapabilities(
|
|
259
|
+
allowedCapabilities
|
|
260
|
+
);
|
|
261
|
+
|
|
262
|
+
if (
|
|
263
|
+
!hasRequiredCapabilities(
|
|
264
|
+
tool,
|
|
265
|
+
capabilities
|
|
266
|
+
)
|
|
267
|
+
) {
|
|
268
|
+
return {
|
|
269
|
+
allowed: false,
|
|
270
|
+
code: "capability_denied",
|
|
271
|
+
reason:
|
|
272
|
+
"Tool requires capabilities that are not allowed.",
|
|
273
|
+
requiresApproval: false,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (
|
|
278
|
+
approval != null &&
|
|
279
|
+
!APPROVAL_DECISIONS.has(approval)
|
|
280
|
+
) {
|
|
281
|
+
throw new TypeError(
|
|
282
|
+
`Invalid approval decision: ${approval}`
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (tool.approval === "never") {
|
|
287
|
+
return {
|
|
288
|
+
allowed: true,
|
|
289
|
+
code: "allowed",
|
|
290
|
+
reason: null,
|
|
291
|
+
requiresApproval: false,
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (approval === "denied") {
|
|
296
|
+
return {
|
|
297
|
+
allowed: false,
|
|
298
|
+
code: "approval_denied",
|
|
299
|
+
reason:
|
|
300
|
+
"Tool execution was denied.",
|
|
301
|
+
requiresApproval: true,
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if (approval === "approved") {
|
|
306
|
+
return {
|
|
307
|
+
allowed: true,
|
|
308
|
+
code: "allowed",
|
|
309
|
+
reason: null,
|
|
310
|
+
requiresApproval: true,
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (tool.approval === "always") {
|
|
315
|
+
return {
|
|
316
|
+
allowed: false,
|
|
317
|
+
code: "approval_required",
|
|
318
|
+
reason:
|
|
319
|
+
"Tool always requires explicit approval.",
|
|
320
|
+
requiresApproval: true,
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const policyDecision =
|
|
325
|
+
evaluateApprovalPolicy(
|
|
326
|
+
tool,
|
|
327
|
+
policy
|
|
328
|
+
);
|
|
329
|
+
|
|
330
|
+
if (
|
|
331
|
+
policyDecision.decision === "allow"
|
|
332
|
+
) {
|
|
333
|
+
return {
|
|
334
|
+
allowed: true,
|
|
335
|
+
code: "allowed",
|
|
336
|
+
reason: policyDecision.reason,
|
|
337
|
+
requiresApproval: false,
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (
|
|
342
|
+
policyDecision.decision === "deny"
|
|
343
|
+
) {
|
|
344
|
+
return {
|
|
345
|
+
allowed: false,
|
|
346
|
+
code: "policy_denied",
|
|
347
|
+
reason: policyDecision.reason,
|
|
348
|
+
requiresApproval: false,
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
return {
|
|
353
|
+
allowed: false,
|
|
354
|
+
code: "approval_required",
|
|
355
|
+
reason: policyDecision.reason,
|
|
356
|
+
requiresApproval: true,
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
export async function executeTool(
|
|
361
|
+
tool,
|
|
362
|
+
input,
|
|
363
|
+
context = {}
|
|
364
|
+
) {
|
|
365
|
+
if (!isTool(tool)) {
|
|
366
|
+
throw new TypeError(
|
|
367
|
+
"Invalid tool."
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
if (
|
|
372
|
+
context == null ||
|
|
373
|
+
typeof context !== "object" ||
|
|
374
|
+
Array.isArray(context)
|
|
375
|
+
) {
|
|
376
|
+
throw new TypeError(
|
|
377
|
+
"Tool execution context must be an object."
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
const startedAt = Date.now();
|
|
382
|
+
|
|
383
|
+
try {
|
|
384
|
+
const output =
|
|
385
|
+
await tool.execute(
|
|
386
|
+
input,
|
|
387
|
+
context
|
|
388
|
+
);
|
|
389
|
+
|
|
390
|
+
const completedAt = Date.now();
|
|
391
|
+
|
|
392
|
+
return createToolResult({
|
|
393
|
+
tool: tool.name,
|
|
394
|
+
success: true,
|
|
395
|
+
output,
|
|
396
|
+
metadata: {
|
|
397
|
+
source: tool.source,
|
|
398
|
+
sideEffect: tool.sideEffect,
|
|
399
|
+
approval: tool.approval,
|
|
400
|
+
},
|
|
401
|
+
startedAt,
|
|
402
|
+
completedAt,
|
|
403
|
+
});
|
|
404
|
+
} catch (error) {
|
|
405
|
+
const completedAt = Date.now();
|
|
406
|
+
|
|
407
|
+
return createToolResult({
|
|
408
|
+
tool: tool.name,
|
|
409
|
+
success: false,
|
|
410
|
+
error,
|
|
411
|
+
metadata: {
|
|
412
|
+
source: tool.source,
|
|
413
|
+
sideEffect: tool.sideEffect,
|
|
414
|
+
approval: tool.approval,
|
|
415
|
+
},
|
|
416
|
+
startedAt,
|
|
417
|
+
completedAt,
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
export async function executeAuthorizedTool(
|
|
422
|
+
tool,
|
|
423
|
+
input,
|
|
424
|
+
context = {},
|
|
425
|
+
authorization = {}
|
|
426
|
+
) {
|
|
427
|
+
const decision =
|
|
428
|
+
authorizeToolExecution(
|
|
429
|
+
tool,
|
|
430
|
+
authorization
|
|
431
|
+
);
|
|
432
|
+
|
|
433
|
+
if (!decision.allowed) {
|
|
434
|
+
const now = Date.now();
|
|
435
|
+
|
|
436
|
+
return createToolResult({
|
|
437
|
+
tool: tool.name,
|
|
438
|
+
success: false,
|
|
439
|
+
|
|
440
|
+
error: {
|
|
441
|
+
code: decision.code,
|
|
442
|
+
message: decision.reason,
|
|
443
|
+
details: {
|
|
444
|
+
requiresApproval:
|
|
445
|
+
decision.requiresApproval,
|
|
446
|
+
},
|
|
447
|
+
},
|
|
448
|
+
|
|
449
|
+
metadata: {
|
|
450
|
+
source: tool.source,
|
|
451
|
+
sideEffect: tool.sideEffect,
|
|
452
|
+
approval: tool.approval,
|
|
453
|
+
authorization: decision,
|
|
454
|
+
},
|
|
455
|
+
|
|
456
|
+
startedAt: now,
|
|
457
|
+
completedAt: now,
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
const result = await executeTool(
|
|
462
|
+
tool,
|
|
463
|
+
input,
|
|
464
|
+
context
|
|
465
|
+
);
|
|
466
|
+
|
|
467
|
+
return {
|
|
468
|
+
...result,
|
|
469
|
+
|
|
470
|
+
metadata: {
|
|
471
|
+
...result.metadata,
|
|
472
|
+
authorization: decision,
|
|
473
|
+
},
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
export function normalizeToolError(error) {
|
|
477
|
+
if (!error) {
|
|
478
|
+
return {
|
|
479
|
+
code: "tool_error",
|
|
480
|
+
message: "Tool execution failed.",
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
if (typeof error === "string") {
|
|
485
|
+
return {
|
|
486
|
+
code: "tool_error",
|
|
487
|
+
message: error,
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
return {
|
|
492
|
+
code:
|
|
493
|
+
error.code ??
|
|
494
|
+
"tool_error",
|
|
495
|
+
|
|
496
|
+
message:
|
|
497
|
+
error.message ??
|
|
498
|
+
"Tool execution failed.",
|
|
499
|
+
|
|
500
|
+
details:
|
|
501
|
+
error.details ??
|
|
502
|
+
null,
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
export function isTool(value) {
|
|
507
|
+
return Boolean(
|
|
508
|
+
value &&
|
|
509
|
+
typeof value === "object" &&
|
|
510
|
+
typeof value.name === "string" &&
|
|
511
|
+
typeof value.description === "string" &&
|
|
512
|
+
typeof value.execute === "function" &&
|
|
513
|
+
TOOL_SOURCES.has(value.source) &&
|
|
514
|
+
SIDE_EFFECTS.has(value.sideEffect) &&
|
|
515
|
+
APPROVAL_MODES.has(value.approval)
|
|
516
|
+
);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
export const ToolSource = Object.freeze({
|
|
520
|
+
BUILTIN: "builtin",
|
|
521
|
+
PLUGIN: "plugin",
|
|
522
|
+
MCP: "mcp",
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
export const ToolSideEffect = Object.freeze({
|
|
526
|
+
NONE: "none",
|
|
527
|
+
WRITE: "write",
|
|
528
|
+
EXECUTE: "execute",
|
|
529
|
+
DESTRUCTIVE: "destructive",
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
export const ToolApproval = Object.freeze({
|
|
533
|
+
NEVER: "never",
|
|
534
|
+
POLICY: "policy",
|
|
535
|
+
ALWAYS: "always",
|
|
536
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export async function getLastCommit(git) {
|
|
2
|
+
const log = await git.log({ maxCount: 1 });
|
|
3
|
+
|
|
4
|
+
if (log.total === 0) {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const commit = log.latest;
|
|
9
|
+
|
|
10
|
+
return {
|
|
11
|
+
hash: commit.hash,
|
|
12
|
+
author: commit.author_name,
|
|
13
|
+
message: commit.message,
|
|
14
|
+
date: commit.date,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import simpleGit from "simple-git";
|
|
2
|
+
|
|
3
|
+
import { getBranch } from "./branch.js";
|
|
4
|
+
import { getStatus } from "./status.js";
|
|
5
|
+
import { getRemote } from "./remote.js";
|
|
6
|
+
import { getLastCommit } from "./commit.js";
|
|
7
|
+
import { getDiff, getStagedDiff } from "./diff.js";
|
|
8
|
+
|
|
9
|
+
export async function inspectGit(root) {
|
|
10
|
+
const git = simpleGit(root);
|
|
11
|
+
|
|
12
|
+
const isRepository = await git.checkIsRepo();
|
|
13
|
+
|
|
14
|
+
if (!isRepository) {
|
|
15
|
+
return {
|
|
16
|
+
isRepository: false,
|
|
17
|
+
branch: null,
|
|
18
|
+
status: null,
|
|
19
|
+
remote: null,
|
|
20
|
+
lastCommit: null,
|
|
21
|
+
diff: null,
|
|
22
|
+
stagedDiff: null,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
isRepository: true,
|
|
28
|
+
branch: await getBranch(git),
|
|
29
|
+
status: await getStatus(git),
|
|
30
|
+
remote: await getRemote(git),
|
|
31
|
+
lastCommit: await getLastCommit(git),
|
|
32
|
+
diff: await getDiff(git),
|
|
33
|
+
stagedDiff: await getStagedDiff(git),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { createSystemPrompt } from "./system.js";
|
|
2
|
+
import { createPlannerPrompt } from "./planner.js";
|
|
3
|
+
import { createCoderPrompt } from "./coder.js";
|
|
4
|
+
import { createReviewerPrompt } from "./reviewer.js";
|
|
5
|
+
|
|
6
|
+
export function buildPlannerMessages(context) {
|
|
7
|
+
return [
|
|
8
|
+
{
|
|
9
|
+
role: "system",
|
|
10
|
+
content: createSystemPrompt(),
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
role: "user",
|
|
14
|
+
content: createPlannerPrompt(context),
|
|
15
|
+
},
|
|
16
|
+
];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function buildCoderMessages(context) {
|
|
20
|
+
return [
|
|
21
|
+
{
|
|
22
|
+
role: "system",
|
|
23
|
+
content: createSystemPrompt(),
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
role: "user",
|
|
27
|
+
content: createCoderPrompt(context),
|
|
28
|
+
},
|
|
29
|
+
];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function buildReviewerMessages(context) {
|
|
33
|
+
return [
|
|
34
|
+
{
|
|
35
|
+
role: "system",
|
|
36
|
+
content: createSystemPrompt(),
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
role: "user",
|
|
40
|
+
content: createReviewerPrompt(context),
|
|
41
|
+
},
|
|
42
|
+
];
|
|
43
|
+
}
|