wave-agent-sdk 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 +32 -0
- package/dist/agent.d.ts +96 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +286 -0
- package/dist/hooks/executor.d.ts +56 -0
- package/dist/hooks/executor.d.ts.map +1 -0
- package/dist/hooks/executor.js +312 -0
- package/dist/hooks/index.d.ts +17 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +14 -0
- package/dist/hooks/manager.d.ts +90 -0
- package/dist/hooks/manager.d.ts.map +1 -0
- package/dist/hooks/manager.js +395 -0
- package/dist/hooks/matcher.d.ts +49 -0
- package/dist/hooks/matcher.d.ts.map +1 -0
- package/dist/hooks/matcher.js +147 -0
- package/dist/hooks/settings.d.ts +46 -0
- package/dist/hooks/settings.d.ts.map +1 -0
- package/dist/hooks/settings.js +100 -0
- package/dist/hooks/types.d.ts +80 -0
- package/dist/hooks/types.d.ts.map +1 -0
- package/dist/hooks/types.js +59 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/managers/aiManager.d.ts +61 -0
- package/dist/managers/aiManager.d.ts.map +1 -0
- package/dist/managers/aiManager.js +415 -0
- package/dist/managers/backgroundBashManager.d.ts +27 -0
- package/dist/managers/backgroundBashManager.d.ts.map +1 -0
- package/dist/managers/backgroundBashManager.js +166 -0
- package/dist/managers/bashManager.d.ts +20 -0
- package/dist/managers/bashManager.d.ts.map +1 -0
- package/dist/managers/bashManager.js +66 -0
- package/dist/managers/mcpManager.d.ts +63 -0
- package/dist/managers/mcpManager.d.ts.map +1 -0
- package/dist/managers/mcpManager.js +378 -0
- package/dist/managers/messageManager.d.ts +85 -0
- package/dist/managers/messageManager.d.ts.map +1 -0
- package/dist/managers/messageManager.js +265 -0
- package/dist/managers/skillManager.d.ts +59 -0
- package/dist/managers/skillManager.d.ts.map +1 -0
- package/dist/managers/skillManager.js +317 -0
- package/dist/managers/slashCommandManager.d.ts +77 -0
- package/dist/managers/slashCommandManager.d.ts.map +1 -0
- package/dist/managers/slashCommandManager.js +208 -0
- package/dist/managers/toolManager.d.ts +23 -0
- package/dist/managers/toolManager.d.ts.map +1 -0
- package/dist/managers/toolManager.js +79 -0
- package/dist/services/aiService.d.ts +28 -0
- package/dist/services/aiService.d.ts.map +1 -0
- package/dist/services/aiService.js +180 -0
- package/dist/services/memory.d.ts +8 -0
- package/dist/services/memory.d.ts.map +1 -0
- package/dist/services/memory.js +128 -0
- package/dist/services/session.d.ts +54 -0
- package/dist/services/session.d.ts.map +1 -0
- package/dist/services/session.js +196 -0
- package/dist/tools/bashTool.d.ts +14 -0
- package/dist/tools/bashTool.d.ts.map +1 -0
- package/dist/tools/bashTool.js +351 -0
- package/dist/tools/deleteFileTool.d.ts +6 -0
- package/dist/tools/deleteFileTool.d.ts.map +1 -0
- package/dist/tools/deleteFileTool.js +67 -0
- package/dist/tools/editTool.d.ts +6 -0
- package/dist/tools/editTool.d.ts.map +1 -0
- package/dist/tools/editTool.js +168 -0
- package/dist/tools/globTool.d.ts +6 -0
- package/dist/tools/globTool.d.ts.map +1 -0
- package/dist/tools/globTool.js +113 -0
- package/dist/tools/grepTool.d.ts +6 -0
- package/dist/tools/grepTool.d.ts.map +1 -0
- package/dist/tools/grepTool.js +268 -0
- package/dist/tools/lsTool.d.ts +6 -0
- package/dist/tools/lsTool.d.ts.map +1 -0
- package/dist/tools/lsTool.js +160 -0
- package/dist/tools/multiEditTool.d.ts +6 -0
- package/dist/tools/multiEditTool.d.ts.map +1 -0
- package/dist/tools/multiEditTool.js +222 -0
- package/dist/tools/readTool.d.ts +6 -0
- package/dist/tools/readTool.d.ts.map +1 -0
- package/dist/tools/readTool.js +136 -0
- package/dist/tools/types.d.ts +35 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +4 -0
- package/dist/tools/writeTool.d.ts +6 -0
- package/dist/tools/writeTool.d.ts.map +1 -0
- package/dist/tools/writeTool.js +138 -0
- package/dist/types.d.ts +212 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +13 -0
- package/dist/utils/bashHistory.d.ts +46 -0
- package/dist/utils/bashHistory.d.ts.map +1 -0
- package/dist/utils/bashHistory.js +236 -0
- package/dist/utils/commandArgumentParser.d.ts +34 -0
- package/dist/utils/commandArgumentParser.d.ts.map +1 -0
- package/dist/utils/commandArgumentParser.js +123 -0
- package/dist/utils/constants.d.ts +27 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/constants.js +28 -0
- package/dist/utils/convertMessagesForAPI.d.ts +9 -0
- package/dist/utils/convertMessagesForAPI.d.ts.map +1 -0
- package/dist/utils/convertMessagesForAPI.js +189 -0
- package/dist/utils/customCommands.d.ts +14 -0
- package/dist/utils/customCommands.d.ts.map +1 -0
- package/dist/utils/customCommands.js +71 -0
- package/dist/utils/fileFilter.d.ts +26 -0
- package/dist/utils/fileFilter.d.ts.map +1 -0
- package/dist/utils/fileFilter.js +177 -0
- package/dist/utils/markdownParser.d.ts +27 -0
- package/dist/utils/markdownParser.d.ts.map +1 -0
- package/dist/utils/markdownParser.js +109 -0
- package/dist/utils/mcpUtils.d.ts +24 -0
- package/dist/utils/mcpUtils.d.ts.map +1 -0
- package/dist/utils/mcpUtils.js +51 -0
- package/dist/utils/messageOperations.d.ts +118 -0
- package/dist/utils/messageOperations.d.ts.map +1 -0
- package/dist/utils/messageOperations.js +334 -0
- package/dist/utils/path.d.ts +25 -0
- package/dist/utils/path.d.ts.map +1 -0
- package/dist/utils/path.js +109 -0
- package/dist/utils/skillParser.d.ts +18 -0
- package/dist/utils/skillParser.d.ts.map +1 -0
- package/dist/utils/skillParser.js +147 -0
- package/dist/utils/stringUtils.d.ts +13 -0
- package/dist/utils/stringUtils.d.ts.map +1 -0
- package/dist/utils/stringUtils.js +44 -0
- package/package.json +51 -0
- package/src/agent.ts +405 -0
- package/src/hooks/executor.ts +440 -0
- package/src/hooks/index.ts +52 -0
- package/src/hooks/manager.ts +618 -0
- package/src/hooks/matcher.ts +187 -0
- package/src/hooks/settings.ts +129 -0
- package/src/hooks/types.ts +169 -0
- package/src/index.ts +24 -0
- package/src/managers/aiManager.ts +573 -0
- package/src/managers/backgroundBashManager.ts +203 -0
- package/src/managers/bashManager.ts +97 -0
- package/src/managers/mcpManager.ts +493 -0
- package/src/managers/messageManager.ts +415 -0
- package/src/managers/skillManager.ts +404 -0
- package/src/managers/slashCommandManager.ts +293 -0
- package/src/managers/toolManager.ts +106 -0
- package/src/services/aiService.ts +252 -0
- package/src/services/memory.ts +149 -0
- package/src/services/session.ts +265 -0
- package/src/tools/bashTool.ts +402 -0
- package/src/tools/deleteFileTool.ts +81 -0
- package/src/tools/editTool.ts +192 -0
- package/src/tools/globTool.ts +135 -0
- package/src/tools/grepTool.ts +326 -0
- package/src/tools/lsTool.ts +187 -0
- package/src/tools/multiEditTool.ts +268 -0
- package/src/tools/readTool.ts +165 -0
- package/src/tools/types.ts +47 -0
- package/src/tools/writeTool.ts +163 -0
- package/src/types.ts +260 -0
- package/src/utils/bashHistory.ts +303 -0
- package/src/utils/commandArgumentParser.ts +153 -0
- package/src/utils/constants.ts +37 -0
- package/src/utils/convertMessagesForAPI.ts +236 -0
- package/src/utils/customCommands.ts +85 -0
- package/src/utils/fileFilter.ts +202 -0
- package/src/utils/markdownParser.ts +156 -0
- package/src/utils/mcpUtils.ts +81 -0
- package/src/utils/messageOperations.ts +506 -0
- package/src/utils/path.ts +118 -0
- package/src/utils/skillParser.ts +188 -0
- package/src/utils/stringUtils.ts +50 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import { spawn } from "child_process";
|
|
2
|
+
/**
|
|
3
|
+
* Bash command execution tool - supports both foreground and background execution
|
|
4
|
+
*/
|
|
5
|
+
export const bashTool = {
|
|
6
|
+
name: "Bash",
|
|
7
|
+
config: {
|
|
8
|
+
type: "function",
|
|
9
|
+
function: {
|
|
10
|
+
name: "Bash",
|
|
11
|
+
description: "Executes a given bash command in a persistent shell session with optional timeout, ensuring proper handling and security measures.",
|
|
12
|
+
parameters: {
|
|
13
|
+
type: "object",
|
|
14
|
+
properties: {
|
|
15
|
+
command: {
|
|
16
|
+
type: "string",
|
|
17
|
+
description: "The command to execute",
|
|
18
|
+
},
|
|
19
|
+
timeout: {
|
|
20
|
+
type: "number",
|
|
21
|
+
description: "Optional timeout in milliseconds (max 600000)",
|
|
22
|
+
},
|
|
23
|
+
description: {
|
|
24
|
+
type: "string",
|
|
25
|
+
description: "Clear, concise description of what this command does in 5-10 words.",
|
|
26
|
+
},
|
|
27
|
+
run_in_background: {
|
|
28
|
+
type: "boolean",
|
|
29
|
+
description: "Set to true to run this command in the background. Use BashOutput to read the output later.",
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
required: ["command"],
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
execute: async (args, context) => {
|
|
37
|
+
const command = args.command;
|
|
38
|
+
const runInBackground = args.run_in_background;
|
|
39
|
+
// Set default timeout: 30s for foreground, no timeout for background
|
|
40
|
+
const timeout = args.timeout ??
|
|
41
|
+
(runInBackground ? undefined : 30000);
|
|
42
|
+
if (!command || typeof command !== "string") {
|
|
43
|
+
return {
|
|
44
|
+
success: false,
|
|
45
|
+
content: "",
|
|
46
|
+
error: "Command parameter is required and must be a string",
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
// Validate timeout
|
|
50
|
+
if (timeout !== undefined &&
|
|
51
|
+
(typeof timeout !== "number" || timeout < 0 || timeout > 600000)) {
|
|
52
|
+
return {
|
|
53
|
+
success: false,
|
|
54
|
+
content: "",
|
|
55
|
+
error: "Timeout must be a number between 0 and 600000 milliseconds",
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
if (runInBackground) {
|
|
59
|
+
// Background execution
|
|
60
|
+
const backgroundBashManager = context?.backgroundBashManager;
|
|
61
|
+
if (!backgroundBashManager) {
|
|
62
|
+
return {
|
|
63
|
+
success: false,
|
|
64
|
+
content: "",
|
|
65
|
+
error: "Background bash manager not available",
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
const shellId = backgroundBashManager.startShell(command, timeout);
|
|
69
|
+
return {
|
|
70
|
+
success: true,
|
|
71
|
+
content: `Command started in background with ID: ${shellId}. Use BashOutput tool with bash_id="${shellId}" to monitor output.`,
|
|
72
|
+
shortResult: `Background process ${shellId} started`,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
// Foreground execution (original behavior)
|
|
76
|
+
return new Promise((resolve) => {
|
|
77
|
+
const child = spawn(command, {
|
|
78
|
+
shell: true,
|
|
79
|
+
stdio: "pipe",
|
|
80
|
+
cwd: context.workdir,
|
|
81
|
+
env: {
|
|
82
|
+
...process.env,
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
let outputBuffer = "";
|
|
86
|
+
let errorBuffer = "";
|
|
87
|
+
let isAborted = false;
|
|
88
|
+
// Set up timeout
|
|
89
|
+
let timeoutHandle;
|
|
90
|
+
if (timeout && timeout > 0) {
|
|
91
|
+
timeoutHandle = setTimeout(() => {
|
|
92
|
+
if (!isAborted) {
|
|
93
|
+
handleAbort("Command timed out");
|
|
94
|
+
}
|
|
95
|
+
}, timeout);
|
|
96
|
+
}
|
|
97
|
+
// Handle abort signal
|
|
98
|
+
const handleAbort = (reason = "Command execution was aborted") => {
|
|
99
|
+
if (!isAborted) {
|
|
100
|
+
isAborted = true;
|
|
101
|
+
if (timeoutHandle) {
|
|
102
|
+
clearTimeout(timeoutHandle);
|
|
103
|
+
}
|
|
104
|
+
// Force terminate child process and its children
|
|
105
|
+
if (child.pid) {
|
|
106
|
+
try {
|
|
107
|
+
// Try graceful termination of process group
|
|
108
|
+
process.kill(-child.pid, "SIGTERM");
|
|
109
|
+
// Set timeout for force kill
|
|
110
|
+
setTimeout(() => {
|
|
111
|
+
if (child.pid && !child.killed) {
|
|
112
|
+
try {
|
|
113
|
+
process.kill(-child.pid, "SIGKILL");
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
// logger.error("Failed to force kill process:", killError);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}, 1000);
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
// If process group termination fails, try direct child process termination
|
|
123
|
+
try {
|
|
124
|
+
child.kill("SIGTERM");
|
|
125
|
+
setTimeout(() => {
|
|
126
|
+
if (!child.killed) {
|
|
127
|
+
child.kill("SIGKILL");
|
|
128
|
+
}
|
|
129
|
+
}, 1000);
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
// logger.error("Failed to kill child process:", directKillError);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
resolve({
|
|
137
|
+
success: false,
|
|
138
|
+
content: outputBuffer + (errorBuffer ? "\n" + errorBuffer : ""),
|
|
139
|
+
error: reason,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
// Handle abort signal from context
|
|
144
|
+
if (context?.abortSignal) {
|
|
145
|
+
if (context.abortSignal.aborted) {
|
|
146
|
+
handleAbort();
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
context.abortSignal.addEventListener("abort", () => handleAbort());
|
|
150
|
+
}
|
|
151
|
+
child.stdout?.on("data", (data) => {
|
|
152
|
+
if (!isAborted) {
|
|
153
|
+
outputBuffer += data.toString();
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
child.stderr?.on("data", (data) => {
|
|
157
|
+
if (!isAborted) {
|
|
158
|
+
errorBuffer += data.toString();
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
child.on("exit", (code) => {
|
|
162
|
+
if (!isAborted) {
|
|
163
|
+
if (timeoutHandle) {
|
|
164
|
+
clearTimeout(timeoutHandle);
|
|
165
|
+
}
|
|
166
|
+
const exitCode = code ?? 0;
|
|
167
|
+
const combinedOutput = outputBuffer + (errorBuffer ? "\n" + errorBuffer : "");
|
|
168
|
+
resolve({
|
|
169
|
+
success: exitCode === 0,
|
|
170
|
+
content: combinedOutput || `Command executed with exit code: ${exitCode}`,
|
|
171
|
+
error: exitCode !== 0
|
|
172
|
+
? `Command failed with exit code: ${exitCode}`
|
|
173
|
+
: undefined,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
child.on("error", (error) => {
|
|
178
|
+
if (!isAborted) {
|
|
179
|
+
if (timeoutHandle) {
|
|
180
|
+
clearTimeout(timeoutHandle);
|
|
181
|
+
}
|
|
182
|
+
resolve({
|
|
183
|
+
success: false,
|
|
184
|
+
content: "",
|
|
185
|
+
error: `Failed to execute command: ${error.message}`,
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
},
|
|
191
|
+
formatCompactParams: (params) => {
|
|
192
|
+
const command = params.command;
|
|
193
|
+
const runInBackground = params.run_in_background;
|
|
194
|
+
return `${command}${runInBackground ? " background" : ""}`;
|
|
195
|
+
},
|
|
196
|
+
};
|
|
197
|
+
/**
|
|
198
|
+
* BashOutput tool - retrieves output from background bash shells
|
|
199
|
+
*/
|
|
200
|
+
export const bashOutputTool = {
|
|
201
|
+
name: "BashOutput",
|
|
202
|
+
config: {
|
|
203
|
+
type: "function",
|
|
204
|
+
function: {
|
|
205
|
+
name: "BashOutput",
|
|
206
|
+
description: "Retrieves output from a running or completed background bash shell",
|
|
207
|
+
parameters: {
|
|
208
|
+
type: "object",
|
|
209
|
+
properties: {
|
|
210
|
+
bash_id: {
|
|
211
|
+
type: "string",
|
|
212
|
+
description: "The ID of the background shell to retrieve output from",
|
|
213
|
+
},
|
|
214
|
+
filter: {
|
|
215
|
+
type: "string",
|
|
216
|
+
description: "Optional regular expression to filter the output lines. Only lines matching this regex will be included in the result. Any lines that do not match will no longer be available to read.",
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
required: ["bash_id"],
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
execute: async (args, context) => {
|
|
224
|
+
const bashId = args.bash_id;
|
|
225
|
+
const filter = args.filter;
|
|
226
|
+
if (!bashId || typeof bashId !== "string") {
|
|
227
|
+
return {
|
|
228
|
+
success: false,
|
|
229
|
+
content: "",
|
|
230
|
+
error: "bash_id parameter is required and must be a string",
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
const backgroundBashManager = context?.backgroundBashManager;
|
|
234
|
+
if (!backgroundBashManager) {
|
|
235
|
+
return {
|
|
236
|
+
success: false,
|
|
237
|
+
content: "",
|
|
238
|
+
error: "Background bash manager not available",
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
const output = backgroundBashManager.getOutput(bashId, filter);
|
|
242
|
+
if (!output) {
|
|
243
|
+
return {
|
|
244
|
+
success: false,
|
|
245
|
+
content: "",
|
|
246
|
+
error: `Background shell with ID ${bashId} not found`,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
const shell = backgroundBashManager.getShell(bashId);
|
|
250
|
+
if (!shell) {
|
|
251
|
+
return {
|
|
252
|
+
success: false,
|
|
253
|
+
content: "",
|
|
254
|
+
error: `Background shell with ID ${bashId} not found`,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
let content = "";
|
|
258
|
+
if (output.stdout) {
|
|
259
|
+
content += output.stdout;
|
|
260
|
+
}
|
|
261
|
+
if (output.stderr) {
|
|
262
|
+
content += (content ? "\n" : "") + output.stderr;
|
|
263
|
+
}
|
|
264
|
+
return {
|
|
265
|
+
success: true,
|
|
266
|
+
content: content || "No output available",
|
|
267
|
+
shortResult: `${bashId}: ${output.status}${shell.exitCode !== undefined ? ` (${shell.exitCode})` : ""}`,
|
|
268
|
+
error: undefined,
|
|
269
|
+
};
|
|
270
|
+
},
|
|
271
|
+
formatCompactParams: (params) => {
|
|
272
|
+
const bashId = params.bash_id;
|
|
273
|
+
const filter = params.filter;
|
|
274
|
+
return filter ? `${bashId} filtered: ${filter}` : bashId;
|
|
275
|
+
},
|
|
276
|
+
};
|
|
277
|
+
/**
|
|
278
|
+
* KillBash tool - kills a running background bash shell
|
|
279
|
+
*/
|
|
280
|
+
export const killBashTool = {
|
|
281
|
+
name: "KillBash",
|
|
282
|
+
config: {
|
|
283
|
+
type: "function",
|
|
284
|
+
function: {
|
|
285
|
+
name: "KillBash",
|
|
286
|
+
description: "Kills a running background bash shell by its ID",
|
|
287
|
+
parameters: {
|
|
288
|
+
type: "object",
|
|
289
|
+
properties: {
|
|
290
|
+
shell_id: {
|
|
291
|
+
type: "string",
|
|
292
|
+
description: "The ID of the background shell to kill",
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
required: ["shell_id"],
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
},
|
|
299
|
+
execute: async (args, context) => {
|
|
300
|
+
const shellId = args.shell_id;
|
|
301
|
+
if (!shellId || typeof shellId !== "string") {
|
|
302
|
+
return {
|
|
303
|
+
success: false,
|
|
304
|
+
content: "",
|
|
305
|
+
error: "shell_id parameter is required and must be a string",
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
const backgroundBashManager = context?.backgroundBashManager;
|
|
309
|
+
if (!backgroundBashManager) {
|
|
310
|
+
return {
|
|
311
|
+
success: false,
|
|
312
|
+
content: "",
|
|
313
|
+
error: "Background bash manager not available",
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
const shell = backgroundBashManager.getShell(shellId);
|
|
317
|
+
if (!shell) {
|
|
318
|
+
return {
|
|
319
|
+
success: false,
|
|
320
|
+
content: "",
|
|
321
|
+
error: `Background shell with ID ${shellId} not found`,
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
if (shell.status !== "running") {
|
|
325
|
+
return {
|
|
326
|
+
success: false,
|
|
327
|
+
content: "",
|
|
328
|
+
error: `Background shell ${shellId} is not running (status: ${shell.status})`,
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
const killed = backgroundBashManager.killShell(shellId);
|
|
332
|
+
if (killed) {
|
|
333
|
+
return {
|
|
334
|
+
success: true,
|
|
335
|
+
content: `Background shell ${shellId} has been killed`,
|
|
336
|
+
shortResult: `Killed ${shellId}`,
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
else {
|
|
340
|
+
return {
|
|
341
|
+
success: false,
|
|
342
|
+
content: "",
|
|
343
|
+
error: `Failed to kill background shell ${shellId}`,
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
},
|
|
347
|
+
formatCompactParams: (params) => {
|
|
348
|
+
const shellId = params.shell_id;
|
|
349
|
+
return shellId;
|
|
350
|
+
},
|
|
351
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deleteFileTool.d.ts","sourceRoot":"","sources":["../../src/tools/deleteFileTool.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAA2B,MAAM,YAAY,CAAC;AAGtE;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,UAyE5B,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { unlink } from "fs/promises";
|
|
2
|
+
import { resolvePath, getDisplayPath } from "../utils/path.js";
|
|
3
|
+
/**
|
|
4
|
+
* Delete file tool plugin
|
|
5
|
+
*/
|
|
6
|
+
export const deleteFileTool = {
|
|
7
|
+
name: "Delete",
|
|
8
|
+
config: {
|
|
9
|
+
type: "function",
|
|
10
|
+
function: {
|
|
11
|
+
name: "Delete",
|
|
12
|
+
description: `Deletes a file at the specified path. The operation will fail gracefully if:
|
|
13
|
+
- The file doesn't exist
|
|
14
|
+
- The operation is rejected for security reasons
|
|
15
|
+
- The file cannot be deleted`,
|
|
16
|
+
parameters: {
|
|
17
|
+
type: "object",
|
|
18
|
+
properties: {
|
|
19
|
+
target_file: {
|
|
20
|
+
type: "string",
|
|
21
|
+
description: "The path of the file to delete, relative to the workspace root.",
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
required: ["target_file"],
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
execute: async (args, context) => {
|
|
29
|
+
const targetFile = args.target_file;
|
|
30
|
+
if (!targetFile || typeof targetFile !== "string") {
|
|
31
|
+
return {
|
|
32
|
+
success: false,
|
|
33
|
+
content: "",
|
|
34
|
+
error: "target_file parameter is required and must be a string",
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
const filePath = resolvePath(targetFile, context.workdir);
|
|
39
|
+
// Delete file
|
|
40
|
+
await unlink(filePath);
|
|
41
|
+
// logger.info(`Successfully deleted file: ${filePath}`);
|
|
42
|
+
return {
|
|
43
|
+
success: true,
|
|
44
|
+
content: `Successfully deleted file: ${targetFile}`,
|
|
45
|
+
shortResult: "File deleted",
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
if (error.code === "ENOENT") {
|
|
50
|
+
return {
|
|
51
|
+
success: false,
|
|
52
|
+
content: "",
|
|
53
|
+
error: `File does not exist: ${targetFile}`,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
success: false,
|
|
58
|
+
content: "",
|
|
59
|
+
error: error instanceof Error ? error.message : String(error),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
formatCompactParams: (params, context) => {
|
|
64
|
+
const targetFile = params.target_file;
|
|
65
|
+
return getDisplayPath(targetFile || "", context.workdir);
|
|
66
|
+
},
|
|
67
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editTool.d.ts","sourceRoot":"","sources":["../../src/tools/editTool.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAA2B,MAAM,YAAY,CAAC;AAetE;;GAEG;AACH,eAAO,MAAM,QAAQ,EAAE,UAqKtB,CAAC"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { readFile, writeFile } from "fs/promises";
|
|
2
|
+
import { resolvePath, getDisplayPath } from "../utils/path.js";
|
|
3
|
+
import { diffLines } from "diff";
|
|
4
|
+
/**
|
|
5
|
+
* Format compact parameter display
|
|
6
|
+
*/
|
|
7
|
+
function formatCompactParams(args, context) {
|
|
8
|
+
const filePath = args.file_path;
|
|
9
|
+
return getDisplayPath(filePath || "", context.workdir);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Single file edit tool plugin
|
|
13
|
+
*/
|
|
14
|
+
export const editTool = {
|
|
15
|
+
name: "Edit",
|
|
16
|
+
formatCompactParams,
|
|
17
|
+
config: {
|
|
18
|
+
type: "function",
|
|
19
|
+
function: {
|
|
20
|
+
name: "Edit",
|
|
21
|
+
description: "Performs exact string replacements in files. \n\nUsage:\n- You must use your `Read` tool at least once in the conversation before editing. This tool will error if you attempt an edit without reading the file. \n- When editing text from read_file tool output, ensure you preserve the exact indentation (tabs/spaces) as it appears AFTER the line number prefix. The line number prefix format is: spaces + line number + tab. Everything after that tab is the actual file content to match. Never include any part of the line number prefix in the old_string or new_string.\n- ALWAYS prefer editing existing files in the codebase. NEVER write new files unless explicitly required.\n- Only use emojis if the user explicitly requests it. Avoid adding emojis to files unless asked.\n- The edit will FAIL if `old_string` is not unique in the file. Either provide a larger string with more surrounding context to make it unique or use `replace_all` to change every instance of `old_string`. \n- Use `replace_all` for replacing and renaming strings across the file. This parameter is useful if you want to rename a variable for instance.",
|
|
22
|
+
parameters: {
|
|
23
|
+
type: "object",
|
|
24
|
+
properties: {
|
|
25
|
+
file_path: {
|
|
26
|
+
type: "string",
|
|
27
|
+
description: "The absolute path to the file to modify",
|
|
28
|
+
},
|
|
29
|
+
old_string: {
|
|
30
|
+
type: "string",
|
|
31
|
+
description: "The text to replace",
|
|
32
|
+
},
|
|
33
|
+
new_string: {
|
|
34
|
+
type: "string",
|
|
35
|
+
description: "The text to replace it with (must be different from old_string)",
|
|
36
|
+
},
|
|
37
|
+
replace_all: {
|
|
38
|
+
type: "boolean",
|
|
39
|
+
default: false,
|
|
40
|
+
description: "Replace all occurences of old_string (default false)",
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
required: ["file_path", "old_string", "new_string"],
|
|
44
|
+
additionalProperties: false,
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
execute: async (args, context) => {
|
|
49
|
+
const filePath = args.file_path;
|
|
50
|
+
const oldString = args.old_string;
|
|
51
|
+
const newString = args.new_string;
|
|
52
|
+
const replaceAll = args.replace_all || false;
|
|
53
|
+
// Validate required parameters
|
|
54
|
+
if (!filePath || typeof filePath !== "string") {
|
|
55
|
+
return {
|
|
56
|
+
success: false,
|
|
57
|
+
content: "",
|
|
58
|
+
error: "file_path parameter is required and must be a string",
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
if (typeof oldString !== "string") {
|
|
62
|
+
return {
|
|
63
|
+
success: false,
|
|
64
|
+
content: "",
|
|
65
|
+
error: "old_string parameter is required and must be a string",
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
if (typeof newString !== "string") {
|
|
69
|
+
return {
|
|
70
|
+
success: false,
|
|
71
|
+
content: "",
|
|
72
|
+
error: "new_string parameter is required and must be a string",
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
if (oldString === newString) {
|
|
76
|
+
return {
|
|
77
|
+
success: false,
|
|
78
|
+
content: "",
|
|
79
|
+
error: "old_string and new_string must be different",
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
const resolvedPath = resolvePath(filePath, context.workdir);
|
|
84
|
+
// Read file content
|
|
85
|
+
let originalContent;
|
|
86
|
+
try {
|
|
87
|
+
originalContent = await readFile(resolvedPath, "utf-8");
|
|
88
|
+
}
|
|
89
|
+
catch (readError) {
|
|
90
|
+
return {
|
|
91
|
+
success: false,
|
|
92
|
+
content: "",
|
|
93
|
+
error: `Failed to read file: ${readError instanceof Error ? readError.message : String(readError)}`,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
// Check if old_string exists
|
|
97
|
+
if (!originalContent.includes(oldString)) {
|
|
98
|
+
return {
|
|
99
|
+
success: false,
|
|
100
|
+
content: "",
|
|
101
|
+
error: `old_string not found in file`,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
let newContent;
|
|
105
|
+
let replacementCount;
|
|
106
|
+
if (replaceAll) {
|
|
107
|
+
// Replace all matches
|
|
108
|
+
const regex = new RegExp(escapeRegExp(oldString), "g");
|
|
109
|
+
newContent = originalContent.replace(regex, newString);
|
|
110
|
+
replacementCount = (originalContent.match(regex) || []).length;
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
// Replace only the first match, but first check if it's unique
|
|
114
|
+
const matches = originalContent.split(oldString).length - 1;
|
|
115
|
+
if (matches > 1) {
|
|
116
|
+
return {
|
|
117
|
+
success: false,
|
|
118
|
+
content: "",
|
|
119
|
+
error: `old_string appears ${matches} times in the file. Either provide a larger string with more surrounding context to make it unique or use replace_all=true to change every instance.`,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
newContent = originalContent.replace(oldString, newString);
|
|
123
|
+
replacementCount = 1;
|
|
124
|
+
}
|
|
125
|
+
// Write file
|
|
126
|
+
try {
|
|
127
|
+
await writeFile(resolvedPath, newContent, "utf-8");
|
|
128
|
+
}
|
|
129
|
+
catch (writeError) {
|
|
130
|
+
return {
|
|
131
|
+
success: false,
|
|
132
|
+
content: "",
|
|
133
|
+
error: `Failed to write file: ${writeError instanceof Error ? writeError.message : String(writeError)}`,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
// Generate diff information
|
|
137
|
+
const diffResult = diffLines(originalContent, newContent);
|
|
138
|
+
const shortResult = replaceAll
|
|
139
|
+
? `Replaced ${replacementCount} instances`
|
|
140
|
+
: "Text replaced successfully";
|
|
141
|
+
// logger.info(`Edit tool: ${shortResult}`);
|
|
142
|
+
return {
|
|
143
|
+
success: true,
|
|
144
|
+
content: shortResult,
|
|
145
|
+
shortResult,
|
|
146
|
+
filePath: resolvedPath,
|
|
147
|
+
originalContent,
|
|
148
|
+
newContent,
|
|
149
|
+
diffResult,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
154
|
+
// logger.error(`Edit tool error: ${errorMessage}`);
|
|
155
|
+
return {
|
|
156
|
+
success: false,
|
|
157
|
+
content: "",
|
|
158
|
+
error: errorMessage,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
/**
|
|
164
|
+
* Escape regular expression special characters
|
|
165
|
+
*/
|
|
166
|
+
function escapeRegExp(string) {
|
|
167
|
+
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
168
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"globTool.d.ts","sourceRoot":"","sources":["../../src/tools/globTool.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAA2B,MAAM,YAAY,CAAC;AAItE;;GAEG;AACH,eAAO,MAAM,QAAQ,EAAE,UA6HtB,CAAC"}
|