@gaunt-sloth/tools 0.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/README.md +25 -0
- package/dist/builtInToolsConfig.d.ts +22 -0
- package/dist/builtInToolsConfig.js +134 -0
- package/dist/builtInToolsConfig.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/binaryContentInjectionMiddleware.d.ts +22 -0
- package/dist/middleware/binaryContentInjectionMiddleware.js +125 -0
- package/dist/middleware/binaryContentInjectionMiddleware.js.map +1 -0
- package/dist/middleware/registry.d.ts +34 -0
- package/dist/middleware/registry.js +124 -0
- package/dist/middleware/registry.js.map +1 -0
- package/dist/middleware/types.d.ts +89 -0
- package/dist/middleware/types.js +9 -0
- package/dist/middleware/types.js.map +1 -0
- package/dist/tools/GthCustomToolkit.d.ts +41 -0
- package/dist/tools/GthCustomToolkit.js +280 -0
- package/dist/tools/GthCustomToolkit.js.map +1 -0
- package/dist/tools/GthDevToolkit.d.ts +24 -0
- package/dist/tools/GthDevToolkit.js +189 -0
- package/dist/tools/GthDevToolkit.js.map +1 -0
- package/dist/tools/GthFileSystemToolkit.d.ts +36 -0
- package/dist/tools/GthFileSystemToolkit.js +775 -0
- package/dist/tools/GthFileSystemToolkit.js.map +1 -0
- package/dist/tools/binaryUtils.d.ts +13 -0
- package/dist/tools/binaryUtils.js +55 -0
- package/dist/tools/binaryUtils.js.map +1 -0
- package/dist/tools/gthStatusUpdateTool.d.ts +2 -0
- package/dist/tools/gthStatusUpdateTool.js +15 -0
- package/dist/tools/gthStatusUpdateTool.js.map +1 -0
- package/dist/tools/gthWebFetchTool.d.ts +2 -0
- package/dist/tools/gthWebFetchTool.js +47 -0
- package/dist/tools/gthWebFetchTool.js.map +1 -0
- package/dist/utils/aiignoreUtils.d.ts +29 -0
- package/dist/utils/aiignoreUtils.js +82 -0
- package/dist/utils/aiignoreUtils.js.map +1 -0
- package/package.json +28 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module GthCustomToolkit
|
|
3
|
+
* Toolkit for user-defined custom shell commands.
|
|
4
|
+
* Provides secure execution of shell commands with parameter validation.
|
|
5
|
+
*/
|
|
6
|
+
import { BaseToolkit, StructuredToolInterface } from '@langchain/core/tools';
|
|
7
|
+
import { CustomToolsConfig, CustomCommandParameter, ValidationCheck } from '@gaunt-sloth/core/config.js';
|
|
8
|
+
export default class GthCustomToolkit extends BaseToolkit {
|
|
9
|
+
tools: StructuredToolInterface[];
|
|
10
|
+
private customTools;
|
|
11
|
+
constructor(customTools?: CustomToolsConfig);
|
|
12
|
+
/**
|
|
13
|
+
* Validate parameter value to prevent security issues.
|
|
14
|
+
* Checks can be selectively skipped via the `allow` list.
|
|
15
|
+
*/
|
|
16
|
+
validateParameterValue(paramValue: string, paramName: string, allow?: ValidationCheck[]): string;
|
|
17
|
+
/**
|
|
18
|
+
* Build a custom command with parameter interpolation
|
|
19
|
+
*/
|
|
20
|
+
buildCustomCommand(commandTemplate: string, parameters: Record<string, string>, parameterConfig?: Record<string, CustomCommandParameter>): string;
|
|
21
|
+
/**
|
|
22
|
+
* Prompt the user to confirm execution of a command that failed validation.
|
|
23
|
+
* Returns true if the user confirms, false otherwise.
|
|
24
|
+
*/
|
|
25
|
+
promptUserForValidationOverride(command: string, toolName: string, validationError: string): Promise<boolean>;
|
|
26
|
+
private executeCommand;
|
|
27
|
+
/**
|
|
28
|
+
* Create a Zod schema for a custom command's parameters
|
|
29
|
+
*/
|
|
30
|
+
private createCustomCommandSchema;
|
|
31
|
+
/**
|
|
32
|
+
* Build command without validation (for display in the user prompt).
|
|
33
|
+
* Simply interpolates parameters into the template without security checks.
|
|
34
|
+
*/
|
|
35
|
+
private buildCommandForDisplay;
|
|
36
|
+
/**
|
|
37
|
+
* Create a tool for a custom command
|
|
38
|
+
*/
|
|
39
|
+
private createCustomCommandTool;
|
|
40
|
+
private createTools;
|
|
41
|
+
}
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module GthCustomToolkit
|
|
3
|
+
* Toolkit for user-defined custom shell commands.
|
|
4
|
+
* Provides secure execution of shell commands with parameter validation.
|
|
5
|
+
*/
|
|
6
|
+
import { BaseToolkit, tool } from '@langchain/core/tools';
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import { spawn } from 'child_process';
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
import { displayInfo, displayError, displayWarning } from '@gaunt-sloth/core/utils/consoleUtils.js';
|
|
11
|
+
import { createInterface, stdin, stdout } from '@gaunt-sloth/core/utils/systemUtils.js';
|
|
12
|
+
// Helper function to create a tool with execute type
|
|
13
|
+
function createCustomTool(fn, config) {
|
|
14
|
+
const toolInstance = tool(fn, config);
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
16
|
+
toolInstance.gthCustomType = 'execute';
|
|
17
|
+
return toolInstance;
|
|
18
|
+
}
|
|
19
|
+
export default class GthCustomToolkit extends BaseToolkit {
|
|
20
|
+
tools;
|
|
21
|
+
customTools;
|
|
22
|
+
constructor(customTools = {}) {
|
|
23
|
+
super();
|
|
24
|
+
this.customTools = customTools;
|
|
25
|
+
this.tools = this.createTools();
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Validate parameter value to prevent security issues.
|
|
29
|
+
* Checks can be selectively skipped via the `allow` list.
|
|
30
|
+
*/
|
|
31
|
+
validateParameterValue(paramValue, paramName, allow = []) {
|
|
32
|
+
const allowSet = new Set(allow);
|
|
33
|
+
// Check for absolute paths
|
|
34
|
+
if (!allowSet.has('absolute-paths') && path.isAbsolute(paramValue)) {
|
|
35
|
+
throw new Error(`Absolute paths are not allowed for parameter '${paramName}'`);
|
|
36
|
+
}
|
|
37
|
+
// Check for directory traversal attempts
|
|
38
|
+
if (!allowSet.has('directory-traversal') &&
|
|
39
|
+
(paramValue.includes('..') || paramValue.includes('\\..\\') || paramValue.includes('/../'))) {
|
|
40
|
+
throw new Error(`Directory traversal attempts are not allowed in parameter '${paramName}'`);
|
|
41
|
+
}
|
|
42
|
+
// Check for pipe attempts and other shell injection
|
|
43
|
+
if (!allowSet.has('shell-injection') &&
|
|
44
|
+
(paramValue.includes('|') ||
|
|
45
|
+
paramValue.includes('&') ||
|
|
46
|
+
paramValue.includes(';') ||
|
|
47
|
+
paramValue.includes('`') ||
|
|
48
|
+
paramValue.includes("'") ||
|
|
49
|
+
paramValue.includes('$') ||
|
|
50
|
+
paramValue.includes('$(') ||
|
|
51
|
+
paramValue.includes('\n') ||
|
|
52
|
+
paramValue.includes('\r'))) {
|
|
53
|
+
throw new Error(`Shell injection attempts are not allowed in parameter '${paramName}'.` +
|
|
54
|
+
'Disallowed symbols pipe, ampersand, semicolon, backtick, single quote, dollar sign, command substitution, newline, carriage return');
|
|
55
|
+
}
|
|
56
|
+
// Check for null bytes
|
|
57
|
+
if (!allowSet.has('null-bytes') && paramValue.includes('\0')) {
|
|
58
|
+
throw new Error(`Null bytes are not allowed in parameter '${paramName}'`);
|
|
59
|
+
}
|
|
60
|
+
// Normalize the path to remove any redundant separators
|
|
61
|
+
// Skip normalization when absolute paths are allowed, since normalize
|
|
62
|
+
// would strip the leading separator context on some values
|
|
63
|
+
if (allowSet.has('absolute-paths')) {
|
|
64
|
+
// Still do the post-normalization traversal check when traversal is not allowed
|
|
65
|
+
if (!allowSet.has('directory-traversal')) {
|
|
66
|
+
const normalizedValue = path.normalize(paramValue);
|
|
67
|
+
if (normalizedValue.includes('..')) {
|
|
68
|
+
throw new Error(`Directory traversal attempts are not allowed in parameter '${paramName}'`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return paramValue;
|
|
72
|
+
}
|
|
73
|
+
const normalizedValue = path.normalize(paramValue);
|
|
74
|
+
// Double-check after normalization
|
|
75
|
+
if (!allowSet.has('directory-traversal') && normalizedValue.includes('..')) {
|
|
76
|
+
throw new Error(`Directory traversal attempts are not allowed in parameter '${paramName}'`);
|
|
77
|
+
}
|
|
78
|
+
return normalizedValue;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Build a custom command with parameter interpolation
|
|
82
|
+
*/
|
|
83
|
+
buildCustomCommand(commandTemplate, parameters, parameterConfig) {
|
|
84
|
+
let command = commandTemplate;
|
|
85
|
+
const paramNames = Object.keys(parameters);
|
|
86
|
+
// Check if all provided parameters have placeholders or should be appended
|
|
87
|
+
const hasPlaceholders = paramNames.some((name) => command.includes(`\${${name}}`));
|
|
88
|
+
if (hasPlaceholders) {
|
|
89
|
+
// Replace all placeholders with validated parameter values
|
|
90
|
+
for (const [name, value] of Object.entries(parameters)) {
|
|
91
|
+
const allow = parameterConfig?.[name]?.allow || [];
|
|
92
|
+
const validatedValue = this.validateParameterValue(value, name, allow);
|
|
93
|
+
const placeholder = '${' + name + '}';
|
|
94
|
+
command = command.replace(new RegExp(placeholder.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'), validatedValue);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
else if (paramNames.length > 0 && parameterConfig) {
|
|
98
|
+
// Append parameters in the order defined in the config
|
|
99
|
+
const orderedParams = Object.keys(parameterConfig);
|
|
100
|
+
const appendValues = [];
|
|
101
|
+
for (const name of orderedParams) {
|
|
102
|
+
if (parameters[name] !== undefined) {
|
|
103
|
+
const allow = parameterConfig[name]?.allow || [];
|
|
104
|
+
const validatedValue = this.validateParameterValue(parameters[name], name, allow);
|
|
105
|
+
appendValues.push(validatedValue);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (appendValues.length > 0) {
|
|
109
|
+
command = `${command} ${appendValues.join(' ')}`;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return command;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Prompt the user to confirm execution of a command that failed validation.
|
|
116
|
+
* Returns true if the user confirms, false otherwise.
|
|
117
|
+
*/
|
|
118
|
+
async promptUserForValidationOverride(command, toolName, validationError) {
|
|
119
|
+
displayWarning(`\n⚠️ Validation failed for tool '${toolName}': ${validationError}`);
|
|
120
|
+
displayWarning(`The agent is trying to execute: ${command}`);
|
|
121
|
+
displayWarning('You can add "allow" to this tool\'s configuration in .gsloth.config.json to skip this check (permanent). ' +
|
|
122
|
+
'Available values: "absolute-paths", "directory-traversal", "shell-injection", "null-bytes"');
|
|
123
|
+
// Write prompt manually to avoid double-echo when readline echoes input
|
|
124
|
+
stdout.write('Do you want to allow this execution (one-time)? (y/N): ');
|
|
125
|
+
const rl = createInterface({ input: stdin });
|
|
126
|
+
try {
|
|
127
|
+
const answer = await rl.question('');
|
|
128
|
+
return answer.trim().toLowerCase() === 'y' || answer.trim().toLowerCase() === 'yes';
|
|
129
|
+
}
|
|
130
|
+
finally {
|
|
131
|
+
rl.close();
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
async executeCommand(command, toolName, timeoutSeconds) {
|
|
135
|
+
displayInfo(`\n🔧 Executing ${toolName}: ${command}`);
|
|
136
|
+
return new Promise((resolve, reject) => {
|
|
137
|
+
const child = spawn(command, {
|
|
138
|
+
shell: true,
|
|
139
|
+
});
|
|
140
|
+
let output = '';
|
|
141
|
+
let timedOut = false;
|
|
142
|
+
let timer;
|
|
143
|
+
if (timeoutSeconds !== undefined && timeoutSeconds > 0) {
|
|
144
|
+
timer = setTimeout(() => {
|
|
145
|
+
timedOut = true;
|
|
146
|
+
child.kill();
|
|
147
|
+
}, timeoutSeconds * 1000);
|
|
148
|
+
}
|
|
149
|
+
// Capture output if available (when stdio is not 'inherit')
|
|
150
|
+
if (child.stdout) {
|
|
151
|
+
child.stdout.on('data', (data) => {
|
|
152
|
+
const chunk = data.toString();
|
|
153
|
+
stdout.write(chunk);
|
|
154
|
+
output += chunk;
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
if (child.stderr) {
|
|
158
|
+
child.stderr.on('data', (data) => {
|
|
159
|
+
const chunk = data.toString();
|
|
160
|
+
stdout.write(chunk);
|
|
161
|
+
output += chunk;
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
child.on('close', (code) => {
|
|
165
|
+
if (timer)
|
|
166
|
+
clearTimeout(timer);
|
|
167
|
+
if (timedOut) {
|
|
168
|
+
resolve(`Executing '${command}'...\n\n` +
|
|
169
|
+
`<COMMAND_OUTPUT>\n` +
|
|
170
|
+
output +
|
|
171
|
+
`</COMMAND_OUTPUT>\n` +
|
|
172
|
+
`\n\nCommand '${command}' timed out after ${timeoutSeconds} seconds`);
|
|
173
|
+
}
|
|
174
|
+
else if (code === 0) {
|
|
175
|
+
resolve(`Executing '${command}'...\n\n` +
|
|
176
|
+
`<COMMAND_OUTPUT>\n` +
|
|
177
|
+
output +
|
|
178
|
+
`</COMMAND_OUTPUT>\n` +
|
|
179
|
+
`\n\nCommand '${command}' completed successfully`);
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
resolve(`Executing '${command}'...\n\n` +
|
|
183
|
+
`<COMMAND_OUTPUT>\n` +
|
|
184
|
+
output +
|
|
185
|
+
`</COMMAND_OUTPUT>\n` +
|
|
186
|
+
`\n\nCommand '${command}' exited with code ${code}`);
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
child.on('error', (error) => {
|
|
190
|
+
if (timer)
|
|
191
|
+
clearTimeout(timer);
|
|
192
|
+
const errorMsg = `Failed to execute command '${command}': ${error.message}`;
|
|
193
|
+
displayError(errorMsg);
|
|
194
|
+
reject(new Error(errorMsg));
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Create a Zod schema for a custom command's parameters
|
|
200
|
+
*/
|
|
201
|
+
createCustomCommandSchema(config
|
|
202
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
203
|
+
) {
|
|
204
|
+
if (!config.parameters || Object.keys(config.parameters).length === 0) {
|
|
205
|
+
return z.object({});
|
|
206
|
+
}
|
|
207
|
+
const shape = {};
|
|
208
|
+
for (const [paramName, paramConfig] of Object.entries(config.parameters)) {
|
|
209
|
+
shape[paramName] = z.string().describe(paramConfig.description);
|
|
210
|
+
}
|
|
211
|
+
return z.object(shape);
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Build command without validation (for display in the user prompt).
|
|
215
|
+
* Simply interpolates parameters into the template without security checks.
|
|
216
|
+
*/
|
|
217
|
+
buildCommandForDisplay(commandTemplate, parameters, parameterConfig) {
|
|
218
|
+
let command = commandTemplate;
|
|
219
|
+
const paramNames = Object.keys(parameters);
|
|
220
|
+
const hasPlaceholders = paramNames.some((name) => command.includes(`\${${name}}`));
|
|
221
|
+
if (hasPlaceholders) {
|
|
222
|
+
for (const [name, value] of Object.entries(parameters)) {
|
|
223
|
+
const placeholder = '${' + name + '}';
|
|
224
|
+
command = command.replace(new RegExp(placeholder.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'), value);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
else if (paramNames.length > 0 && parameterConfig) {
|
|
228
|
+
const orderedParams = Object.keys(parameterConfig);
|
|
229
|
+
const appendValues = [];
|
|
230
|
+
for (const name of orderedParams) {
|
|
231
|
+
if (parameters[name] !== undefined) {
|
|
232
|
+
appendValues.push(parameters[name]);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
if (appendValues.length > 0) {
|
|
236
|
+
command = `${command} ${appendValues.join(' ')}`;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return command;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Create a tool for a custom command
|
|
243
|
+
*/
|
|
244
|
+
createCustomCommandTool(name, config) {
|
|
245
|
+
const schema = this.createCustomCommandSchema(config);
|
|
246
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
247
|
+
const toolFn = async (args) => {
|
|
248
|
+
// All parameters are strings, safe to cast
|
|
249
|
+
const stringArgs = args;
|
|
250
|
+
try {
|
|
251
|
+
const command = this.buildCustomCommand(config.command, stringArgs, config.parameters);
|
|
252
|
+
return await this.executeCommand(command, name, config.timeout);
|
|
253
|
+
}
|
|
254
|
+
catch (validationError) {
|
|
255
|
+
// If validation fails, prompt the user for confirmation
|
|
256
|
+
const errorMessage = validationError instanceof Error ? validationError.message : String(validationError);
|
|
257
|
+
const displayCommand = this.buildCommandForDisplay(config.command, stringArgs, config.parameters);
|
|
258
|
+
const userConfirmed = await this.promptUserForValidationOverride(displayCommand, name, errorMessage);
|
|
259
|
+
if (userConfirmed) {
|
|
260
|
+
return await this.executeCommand(displayCommand, name);
|
|
261
|
+
}
|
|
262
|
+
throw new Error(`Execution of '${name}' was rejected by user. Validation error: ${errorMessage}`);
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
return createCustomTool(toolFn, {
|
|
266
|
+
name,
|
|
267
|
+
description: config.description + `\nThe configured command is [${config.command}].`,
|
|
268
|
+
schema,
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
createTools() {
|
|
272
|
+
const tools = [];
|
|
273
|
+
// Create tools for custom commands
|
|
274
|
+
for (const [name, config] of Object.entries(this.customTools)) {
|
|
275
|
+
tools.push(this.createCustomCommandTool(name, config));
|
|
276
|
+
}
|
|
277
|
+
return tools;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
//# sourceMappingURL=GthCustomToolkit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GthCustomToolkit.js","sourceRoot":"","sources":["../../src/tools/GthCustomToolkit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module GthDevToolkit
|
|
3
|
+
*/
|
|
4
|
+
import { BaseToolkit, StructuredToolInterface } from '@langchain/core/tools';
|
|
5
|
+
import { GthDevToolsConfig } from '@gaunt-sloth/core/config.js';
|
|
6
|
+
export default class GthDevToolkit extends BaseToolkit {
|
|
7
|
+
tools: StructuredToolInterface[];
|
|
8
|
+
private commands;
|
|
9
|
+
constructor(commands?: GthDevToolsConfig);
|
|
10
|
+
/**
|
|
11
|
+
* Get tools filtered by operation type
|
|
12
|
+
*/
|
|
13
|
+
getFilteredTools(allowedOperations: 'execute'[]): StructuredToolInterface[];
|
|
14
|
+
/**
|
|
15
|
+
* Validate parameter value to prevent security issues
|
|
16
|
+
*/
|
|
17
|
+
validateParameterValue(paramValue: string, paramName: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* Build the command for running a single test file
|
|
20
|
+
*/
|
|
21
|
+
private buildSingleTestCommand;
|
|
22
|
+
private executeCommand;
|
|
23
|
+
private createTools;
|
|
24
|
+
}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module GthDevToolkit
|
|
3
|
+
*/
|
|
4
|
+
import { BaseToolkit, tool } from '@langchain/core/tools';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { spawn } from 'child_process';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import { displayInfo, displayError } from '@gaunt-sloth/core/utils/consoleUtils.js';
|
|
9
|
+
import { stdout } from '@gaunt-sloth/core/utils/systemUtils.js';
|
|
10
|
+
// Helper function to create a tool with dev type
|
|
11
|
+
function createGthTool(fn, config, gthDevType) {
|
|
12
|
+
const toolInstance = tool(fn, config);
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
14
|
+
toolInstance.gthDevType = gthDevType;
|
|
15
|
+
return toolInstance;
|
|
16
|
+
}
|
|
17
|
+
// Schema definitions for built-in tools
|
|
18
|
+
const RunTestsArgsSchema = z.object({});
|
|
19
|
+
const RunLintArgsSchema = z.object({});
|
|
20
|
+
const RunBuildArgsSchema = z.object({});
|
|
21
|
+
const RunSingleTestArgsSchema = z.object({
|
|
22
|
+
testPath: z.string().describe('Relative path to the test file to run'),
|
|
23
|
+
});
|
|
24
|
+
const TEST_PATH_PLACEHOLDER = '${testPath}';
|
|
25
|
+
export default class GthDevToolkit extends BaseToolkit {
|
|
26
|
+
tools;
|
|
27
|
+
commands;
|
|
28
|
+
constructor(commands = {}) {
|
|
29
|
+
super();
|
|
30
|
+
this.commands = commands;
|
|
31
|
+
this.tools = this.createTools();
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Get tools filtered by operation type
|
|
35
|
+
*/
|
|
36
|
+
getFilteredTools(allowedOperations) {
|
|
37
|
+
return this.tools.filter((tool) => {
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
39
|
+
const toolType = tool.gthDevType;
|
|
40
|
+
return allowedOperations.includes(toolType);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Validate parameter value to prevent security issues
|
|
45
|
+
*/
|
|
46
|
+
validateParameterValue(paramValue, paramName) {
|
|
47
|
+
// Check for absolute paths
|
|
48
|
+
if (path.isAbsolute(paramValue)) {
|
|
49
|
+
throw new Error(`Absolute paths are not allowed for parameter '${paramName}'`);
|
|
50
|
+
}
|
|
51
|
+
// Check for directory traversal attempts
|
|
52
|
+
if (paramValue.includes('..') || paramValue.includes('\\..\\') || paramValue.includes('/../')) {
|
|
53
|
+
throw new Error(`Directory traversal attempts are not allowed in parameter '${paramName}'`);
|
|
54
|
+
}
|
|
55
|
+
// Check for pipe attempts and other shell injection
|
|
56
|
+
if (paramValue.includes('|') ||
|
|
57
|
+
paramValue.includes('&') ||
|
|
58
|
+
paramValue.includes(';') ||
|
|
59
|
+
paramValue.includes('`') ||
|
|
60
|
+
paramValue.includes('$') ||
|
|
61
|
+
paramValue.includes('$(') ||
|
|
62
|
+
paramValue.includes('\n') ||
|
|
63
|
+
paramValue.includes('\r')) {
|
|
64
|
+
throw new Error(`Shell injection attempts are not allowed in parameter '${paramName}'`);
|
|
65
|
+
}
|
|
66
|
+
// Check for null bytes
|
|
67
|
+
if (paramValue.includes('\0')) {
|
|
68
|
+
throw new Error(`Null bytes are not allowed in parameter '${paramName}'`);
|
|
69
|
+
}
|
|
70
|
+
// Normalize the path to remove any redundant separators
|
|
71
|
+
const normalizedValue = path.normalize(paramValue);
|
|
72
|
+
// Double-check after normalization
|
|
73
|
+
if (normalizedValue.includes('..')) {
|
|
74
|
+
throw new Error(`Directory traversal attempts are not allowed in parameter '${paramName}'`);
|
|
75
|
+
}
|
|
76
|
+
return normalizedValue;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Build the command for running a single test file
|
|
80
|
+
*/
|
|
81
|
+
buildSingleTestCommand(testPath) {
|
|
82
|
+
if (this.commands.run_single_test) {
|
|
83
|
+
if (this.commands.run_single_test.includes(TEST_PATH_PLACEHOLDER)) {
|
|
84
|
+
// Interpolate if placeholder is available
|
|
85
|
+
return this.commands.run_single_test.replace(TEST_PATH_PLACEHOLDER, testPath);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
// Concatenate if no placeholder
|
|
89
|
+
return `${this.commands.run_single_test} ${testPath}`;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
throw new Error('No test command configured');
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
async executeCommand(command, toolName) {
|
|
97
|
+
displayInfo(`\n🔧 Executing ${toolName}: ${command}`);
|
|
98
|
+
return new Promise((resolve, reject) => {
|
|
99
|
+
const child = spawn(command, {
|
|
100
|
+
shell: true,
|
|
101
|
+
});
|
|
102
|
+
let output = '';
|
|
103
|
+
// Capture output if available (when stdio is not 'inherit')
|
|
104
|
+
if (child.stdout) {
|
|
105
|
+
child.stdout.on('data', (data) => {
|
|
106
|
+
const chunk = data.toString();
|
|
107
|
+
stdout.write(chunk);
|
|
108
|
+
output += chunk;
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
if (child.stderr) {
|
|
112
|
+
child.stderr.on('data', (data) => {
|
|
113
|
+
const chunk = data.toString();
|
|
114
|
+
stdout.write(chunk);
|
|
115
|
+
output += chunk;
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
child.on('close', (code) => {
|
|
119
|
+
if (code === 0) {
|
|
120
|
+
resolve(`Executing '${command}'...\n\n` +
|
|
121
|
+
`<COMMAND_OUTPUT>\n` +
|
|
122
|
+
output +
|
|
123
|
+
`</COMMAND_OUTPUT>\n` +
|
|
124
|
+
`\n\nCommand '${command}' completed successfully`);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
resolve(`Executing '${command}'...\n\n` +
|
|
128
|
+
`<COMMAND_OUTPUT>\n` +
|
|
129
|
+
output +
|
|
130
|
+
`</COMMAND_OUTPUT>\n` +
|
|
131
|
+
`\n\nCommand '${command}' exited with code ${code}`);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
child.on('error', (error) => {
|
|
135
|
+
const errorMsg = `Failed to execute command '${command}': ${error.message}`;
|
|
136
|
+
displayError(errorMsg);
|
|
137
|
+
reject(new Error(errorMsg));
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
createTools() {
|
|
142
|
+
const tools = [];
|
|
143
|
+
if (this.commands.run_tests) {
|
|
144
|
+
tools.push(createGthTool(async (_args) => {
|
|
145
|
+
return await this.executeCommand(this.commands.run_tests, 'run_tests');
|
|
146
|
+
}, {
|
|
147
|
+
name: 'run_tests',
|
|
148
|
+
description: 'Execute the test suite for this project. Runs the configured test command and returns the output.' +
|
|
149
|
+
`\nThe configured command is [${this.commands.run_tests}].`,
|
|
150
|
+
schema: RunTestsArgsSchema,
|
|
151
|
+
}, 'execute'));
|
|
152
|
+
}
|
|
153
|
+
if (this.commands.run_single_test) {
|
|
154
|
+
tools.push(createGthTool(async (args) => {
|
|
155
|
+
const validatedPath = this.validateParameterValue(args.testPath, 'testPath');
|
|
156
|
+
const command = this.buildSingleTestCommand(validatedPath);
|
|
157
|
+
return await this.executeCommand(command, 'run_single_test');
|
|
158
|
+
}, {
|
|
159
|
+
name: 'run_single_test',
|
|
160
|
+
description: 'Execute a single test file. Runs the configured test command with the specified test file path. ' +
|
|
161
|
+
'The test path must be relative and cannot contain directory traversal attempts or shell injection. ' +
|
|
162
|
+
`\nThe base command is [${this.commands.run_single_test}].`,
|
|
163
|
+
schema: RunSingleTestArgsSchema,
|
|
164
|
+
}, 'execute'));
|
|
165
|
+
}
|
|
166
|
+
if (this.commands.run_lint) {
|
|
167
|
+
tools.push(createGthTool(async (_args) => {
|
|
168
|
+
return await this.executeCommand(this.commands.run_lint, 'run_lint');
|
|
169
|
+
}, {
|
|
170
|
+
name: 'run_lint',
|
|
171
|
+
description: 'Run the linter on the project code. Executes the configured lint command and returns any linting errors or warnings.' +
|
|
172
|
+
`\nThe configured command is [${this.commands.run_lint}].`,
|
|
173
|
+
schema: RunLintArgsSchema,
|
|
174
|
+
}, 'execute'));
|
|
175
|
+
}
|
|
176
|
+
if (this.commands.run_build) {
|
|
177
|
+
tools.push(createGthTool(async (_args) => {
|
|
178
|
+
return await this.executeCommand(this.commands.run_build, 'run_build');
|
|
179
|
+
}, {
|
|
180
|
+
name: 'run_build',
|
|
181
|
+
description: 'Build the project. Executes the configured build command and returns the build output.' +
|
|
182
|
+
`\nThe configured command is [${this.commands.run_build}].`,
|
|
183
|
+
schema: RunBuildArgsSchema,
|
|
184
|
+
}, 'execute'));
|
|
185
|
+
}
|
|
186
|
+
return tools;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=GthDevToolkit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GthDevToolkit.js","sourceRoot":"","sources":["../../src/tools/GthDevToolkit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { BaseToolkit, StructuredToolInterface } from '@langchain/core/tools';
|
|
2
|
+
import type { BinaryFormatConfig } from '@gaunt-sloth/core/config.js';
|
|
3
|
+
export interface GthFileSystemToolkitOptions {
|
|
4
|
+
allowedDirectories?: string[];
|
|
5
|
+
aiignoreConfig?: {
|
|
6
|
+
enabled?: boolean;
|
|
7
|
+
patterns?: string[];
|
|
8
|
+
};
|
|
9
|
+
binaryFormats?: false | BinaryFormatConfig[];
|
|
10
|
+
}
|
|
11
|
+
export default class GthFileSystemToolkit extends BaseToolkit {
|
|
12
|
+
tools: StructuredToolInterface[];
|
|
13
|
+
private allowedDirectories;
|
|
14
|
+
private aiignoreConfig?;
|
|
15
|
+
private binaryFormats?;
|
|
16
|
+
constructor(options?: GthFileSystemToolkitOptions);
|
|
17
|
+
/**
|
|
18
|
+
* Get tools filtered by operation type
|
|
19
|
+
*/
|
|
20
|
+
getFilteredTools(allowedOperations: ('read' | 'write')[]): StructuredToolInterface[];
|
|
21
|
+
private normalizePath;
|
|
22
|
+
private isProtectedDirectory;
|
|
23
|
+
private expandHome;
|
|
24
|
+
private sanitizeRequestedPath;
|
|
25
|
+
private validatePath;
|
|
26
|
+
private getFileStats;
|
|
27
|
+
private searchFiles;
|
|
28
|
+
private normalizeLineEndings;
|
|
29
|
+
private createUnifiedDiff;
|
|
30
|
+
private applyFileEdits;
|
|
31
|
+
private formatSize;
|
|
32
|
+
private tailFile;
|
|
33
|
+
private headFile;
|
|
34
|
+
private createReadBinaryTool;
|
|
35
|
+
private createTools;
|
|
36
|
+
}
|