@nomad-e/bluma-cli 0.0.108 → 0.0.109
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/dist/main.js +618 -542
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -1,8 +1,330 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
2
3
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
4
|
var __esm = (fn, res) => function __init() {
|
|
4
5
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
5
6
|
};
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// src/app/agent/tools/natives/async_command.ts
|
|
13
|
+
var async_command_exports = {};
|
|
14
|
+
__export(async_command_exports, {
|
|
15
|
+
commandStatus: () => commandStatus,
|
|
16
|
+
killCommand: () => killCommand,
|
|
17
|
+
runCommandAsync: () => runCommandAsync,
|
|
18
|
+
sendCommandInput: () => sendCommandInput
|
|
19
|
+
});
|
|
20
|
+
import os2 from "os";
|
|
21
|
+
import { spawn } from "child_process";
|
|
22
|
+
import { v4 as uuidv42 } from "uuid";
|
|
23
|
+
function cleanupOldCommands() {
|
|
24
|
+
if (runningCommands.size <= MAX_STORED_COMMANDS) return;
|
|
25
|
+
const commands = Array.from(runningCommands.entries()).filter(([_, cmd]) => cmd.status !== "running").sort((a, b) => (a[1].endTime || 0) - (b[1].endTime || 0));
|
|
26
|
+
const toRemove = commands.slice(0, commands.length - MAX_STORED_COMMANDS + 10);
|
|
27
|
+
for (const [id] of toRemove) {
|
|
28
|
+
runningCommands.delete(id);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function isDangerousCommand(command) {
|
|
32
|
+
const trimmed = command.trim();
|
|
33
|
+
for (const pattern of DANGEROUS_PATTERNS) {
|
|
34
|
+
if (pattern.test(trimmed)) {
|
|
35
|
+
return "Command requires elevated privileges (sudo/doas) which cannot be handled in async mode";
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
for (const pattern of INTERACTIVE_PATTERNS) {
|
|
39
|
+
if (pattern.test(trimmed)) {
|
|
40
|
+
return "Interactive commands are not supported in async mode";
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
async function runCommandAsync(args) {
|
|
46
|
+
try {
|
|
47
|
+
const {
|
|
48
|
+
command,
|
|
49
|
+
cwd = process.cwd(),
|
|
50
|
+
timeout = 0
|
|
51
|
+
} = args;
|
|
52
|
+
if (!command || typeof command !== "string") {
|
|
53
|
+
return {
|
|
54
|
+
success: false,
|
|
55
|
+
error: "command is required and must be a string"
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const dangerReason = isDangerousCommand(command);
|
|
59
|
+
if (dangerReason) {
|
|
60
|
+
return {
|
|
61
|
+
success: false,
|
|
62
|
+
error: dangerReason
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
const commandId = uuidv42().substring(0, 8);
|
|
66
|
+
const platform = os2.platform();
|
|
67
|
+
let shellCmd;
|
|
68
|
+
let shellArgs;
|
|
69
|
+
if (platform === "win32") {
|
|
70
|
+
shellCmd = process.env.COMSPEC || "cmd.exe";
|
|
71
|
+
shellArgs = ["/c", command];
|
|
72
|
+
} else {
|
|
73
|
+
shellCmd = process.env.SHELL || "/bin/bash";
|
|
74
|
+
shellArgs = ["-c", command];
|
|
75
|
+
}
|
|
76
|
+
const entry = {
|
|
77
|
+
id: commandId,
|
|
78
|
+
command,
|
|
79
|
+
status: "running",
|
|
80
|
+
stdout: "",
|
|
81
|
+
stderr: "",
|
|
82
|
+
exitCode: null,
|
|
83
|
+
startTime: Date.now(),
|
|
84
|
+
process: null
|
|
85
|
+
};
|
|
86
|
+
const child = spawn(shellCmd, shellArgs, {
|
|
87
|
+
cwd,
|
|
88
|
+
env: process.env,
|
|
89
|
+
windowsHide: true
|
|
90
|
+
});
|
|
91
|
+
entry.process = child;
|
|
92
|
+
let stdoutTruncated = false;
|
|
93
|
+
child.stdout?.on("data", (data) => {
|
|
94
|
+
if (!stdoutTruncated) {
|
|
95
|
+
entry.stdout += data.toString();
|
|
96
|
+
if (entry.stdout.length > MAX_OUTPUT_SIZE) {
|
|
97
|
+
entry.stdout = entry.stdout.substring(0, MAX_OUTPUT_SIZE) + OUTPUT_TRUNCATION_MSG;
|
|
98
|
+
stdoutTruncated = true;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
let stderrTruncated = false;
|
|
103
|
+
child.stderr?.on("data", (data) => {
|
|
104
|
+
if (!stderrTruncated) {
|
|
105
|
+
entry.stderr += data.toString();
|
|
106
|
+
if (entry.stderr.length > MAX_OUTPUT_SIZE) {
|
|
107
|
+
entry.stderr = entry.stderr.substring(0, MAX_OUTPUT_SIZE) + OUTPUT_TRUNCATION_MSG;
|
|
108
|
+
stderrTruncated = true;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
child.on("close", (code) => {
|
|
113
|
+
entry.exitCode = code;
|
|
114
|
+
entry.status = code === 0 ? "completed" : "error";
|
|
115
|
+
entry.endTime = Date.now();
|
|
116
|
+
entry.process = null;
|
|
117
|
+
});
|
|
118
|
+
child.on("error", (error) => {
|
|
119
|
+
entry.stderr += `
|
|
120
|
+
Process error: ${error.message}`;
|
|
121
|
+
entry.status = "error";
|
|
122
|
+
entry.endTime = Date.now();
|
|
123
|
+
entry.process = null;
|
|
124
|
+
});
|
|
125
|
+
if (timeout > 0) {
|
|
126
|
+
setTimeout(() => {
|
|
127
|
+
if (entry.status === "running") {
|
|
128
|
+
child.kill("SIGTERM");
|
|
129
|
+
setTimeout(() => {
|
|
130
|
+
if (entry.status === "running") {
|
|
131
|
+
child.kill("SIGKILL");
|
|
132
|
+
}
|
|
133
|
+
}, 2e3);
|
|
134
|
+
entry.status = "timeout";
|
|
135
|
+
entry.stderr += `
|
|
136
|
+
Command timed out after ${timeout} seconds`;
|
|
137
|
+
}
|
|
138
|
+
}, timeout * 1e3);
|
|
139
|
+
}
|
|
140
|
+
runningCommands.set(commandId, entry);
|
|
141
|
+
cleanupOldCommands();
|
|
142
|
+
return {
|
|
143
|
+
success: true,
|
|
144
|
+
command_id: commandId,
|
|
145
|
+
command,
|
|
146
|
+
message: `Command started in background. Use command_status with id "${commandId}" to check progress.`
|
|
147
|
+
};
|
|
148
|
+
} catch (error) {
|
|
149
|
+
return {
|
|
150
|
+
success: false,
|
|
151
|
+
error: `Unexpected error: ${error.message}`
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
async function commandStatus(args) {
|
|
156
|
+
try {
|
|
157
|
+
const {
|
|
158
|
+
command_id,
|
|
159
|
+
wait_seconds = 0,
|
|
160
|
+
output_limit = 1e4
|
|
161
|
+
} = args;
|
|
162
|
+
if (!command_id) {
|
|
163
|
+
return {
|
|
164
|
+
success: false,
|
|
165
|
+
command_id: "",
|
|
166
|
+
status: "error",
|
|
167
|
+
error: "command_id is required"
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
const entry = runningCommands.get(command_id);
|
|
171
|
+
if (!entry) {
|
|
172
|
+
return {
|
|
173
|
+
success: false,
|
|
174
|
+
command_id,
|
|
175
|
+
status: "not_found",
|
|
176
|
+
error: `Command with id "${command_id}" not found. It may have expired or never existed.`
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
if (wait_seconds > 0 && entry.status === "running") {
|
|
180
|
+
await new Promise((resolve) => {
|
|
181
|
+
const checkInterval = setInterval(() => {
|
|
182
|
+
if (entry.status !== "running") {
|
|
183
|
+
clearInterval(checkInterval);
|
|
184
|
+
resolve();
|
|
185
|
+
}
|
|
186
|
+
}, 100);
|
|
187
|
+
setTimeout(() => {
|
|
188
|
+
clearInterval(checkInterval);
|
|
189
|
+
resolve();
|
|
190
|
+
}, wait_seconds * 1e3);
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
let stdout = entry.stdout;
|
|
194
|
+
let stderr = entry.stderr;
|
|
195
|
+
let truncated = false;
|
|
196
|
+
if (stdout.length > output_limit) {
|
|
197
|
+
stdout = "..." + stdout.substring(stdout.length - output_limit);
|
|
198
|
+
truncated = true;
|
|
199
|
+
}
|
|
200
|
+
if (stderr.length > output_limit) {
|
|
201
|
+
stderr = "..." + stderr.substring(stderr.length - output_limit);
|
|
202
|
+
truncated = true;
|
|
203
|
+
}
|
|
204
|
+
const duration = entry.endTime ? (entry.endTime - entry.startTime) / 1e3 : (Date.now() - entry.startTime) / 1e3;
|
|
205
|
+
return {
|
|
206
|
+
success: true,
|
|
207
|
+
command_id,
|
|
208
|
+
status: entry.status,
|
|
209
|
+
stdout: stdout || void 0,
|
|
210
|
+
stderr: stderr || void 0,
|
|
211
|
+
exit_code: entry.exitCode,
|
|
212
|
+
duration_seconds: Math.round(duration * 10) / 10,
|
|
213
|
+
truncated
|
|
214
|
+
};
|
|
215
|
+
} catch (error) {
|
|
216
|
+
return {
|
|
217
|
+
success: false,
|
|
218
|
+
command_id: args.command_id || "",
|
|
219
|
+
status: "error",
|
|
220
|
+
error: `Unexpected error: ${error.message}`
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
async function sendCommandInput(args) {
|
|
225
|
+
try {
|
|
226
|
+
const { command_id, input } = args;
|
|
227
|
+
if (!command_id || input === void 0) {
|
|
228
|
+
return {
|
|
229
|
+
success: false,
|
|
230
|
+
error: "command_id and input are required"
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
const entry = runningCommands.get(command_id);
|
|
234
|
+
if (!entry) {
|
|
235
|
+
return {
|
|
236
|
+
success: false,
|
|
237
|
+
error: `Command with id "${command_id}" not found`
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
if (entry.status !== "running" || !entry.process) {
|
|
241
|
+
return {
|
|
242
|
+
success: false,
|
|
243
|
+
error: `Command is not running (status: ${entry.status})`
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
entry.process.stdin?.write(input);
|
|
247
|
+
return {
|
|
248
|
+
success: true,
|
|
249
|
+
message: `Sent ${input.length} characters to command ${command_id}`
|
|
250
|
+
};
|
|
251
|
+
} catch (error) {
|
|
252
|
+
return {
|
|
253
|
+
success: false,
|
|
254
|
+
error: `Failed to send input: ${error.message}`
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
async function killCommand(args) {
|
|
259
|
+
try {
|
|
260
|
+
const { command_id } = args;
|
|
261
|
+
const entry = runningCommands.get(command_id);
|
|
262
|
+
if (!entry) {
|
|
263
|
+
return {
|
|
264
|
+
success: false,
|
|
265
|
+
error: `Command with id "${command_id}" not found`
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
if (entry.status !== "running" || !entry.process) {
|
|
269
|
+
return {
|
|
270
|
+
success: false,
|
|
271
|
+
error: `Command is not running (status: ${entry.status})`
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
entry.process.kill("SIGTERM");
|
|
275
|
+
entry.status = "killed";
|
|
276
|
+
entry.endTime = Date.now();
|
|
277
|
+
return {
|
|
278
|
+
success: true,
|
|
279
|
+
message: `Command ${command_id} killed`
|
|
280
|
+
};
|
|
281
|
+
} catch (error) {
|
|
282
|
+
return {
|
|
283
|
+
success: false,
|
|
284
|
+
error: `Failed to kill command: ${error.message}`
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
var runningCommands, MAX_OUTPUT_SIZE, MAX_STORED_COMMANDS, OUTPUT_TRUNCATION_MSG, DANGEROUS_PATTERNS, INTERACTIVE_PATTERNS;
|
|
289
|
+
var init_async_command = __esm({
|
|
290
|
+
"src/app/agent/tools/natives/async_command.ts"() {
|
|
291
|
+
"use strict";
|
|
292
|
+
runningCommands = /* @__PURE__ */ new Map();
|
|
293
|
+
MAX_OUTPUT_SIZE = 3e4;
|
|
294
|
+
MAX_STORED_COMMANDS = 50;
|
|
295
|
+
OUTPUT_TRUNCATION_MSG = "\n[OUTPUT TRUNCATED - 30KB/200 lines max]";
|
|
296
|
+
DANGEROUS_PATTERNS = [
|
|
297
|
+
// Elevação de privilégios
|
|
298
|
+
/^sudo\s+/i,
|
|
299
|
+
/^doas\s+/i,
|
|
300
|
+
/^su\s+/i,
|
|
301
|
+
/^pkexec\s+/i,
|
|
302
|
+
/\|\s*sudo\s+/i,
|
|
303
|
+
/;\s*sudo\s+/i,
|
|
304
|
+
/&&\s*sudo\s+/i,
|
|
305
|
+
// Comandos destrutivos
|
|
306
|
+
/\brm\s+(-[rf]+\s+)*[\/~]/i,
|
|
307
|
+
/\brm\s+-[rf]*\s+\*/i,
|
|
308
|
+
/\bchmod\s+(777|666)\s+\//i,
|
|
309
|
+
/\bdd\s+.*of=\/dev\/(sd|hd|nvme)/i,
|
|
310
|
+
/\bmkfs\./i,
|
|
311
|
+
// Fork bombs
|
|
312
|
+
/:\(\)\s*\{\s*:\|:&\s*\}\s*;:/,
|
|
313
|
+
// Remote code exec
|
|
314
|
+
/\bcurl\s+.*\|\s*(ba)?sh/i,
|
|
315
|
+
/\bwget\s+.*\|\s*(ba)?sh/i
|
|
316
|
+
];
|
|
317
|
+
INTERACTIVE_PATTERNS = [
|
|
318
|
+
/^(vim|vi|nano|emacs|pico)\s*/i,
|
|
319
|
+
/^(less|more|most)\s*/i,
|
|
320
|
+
/^(top|htop|btop|atop|nmon)\s*/i,
|
|
321
|
+
/^(ssh|telnet|ftp|sftp)\s+/i,
|
|
322
|
+
/^(mysql|psql|redis-cli|mongo|mongosh)\s*$/i,
|
|
323
|
+
/^(python|python3|node|ruby|irb|lua)\s*$/i,
|
|
324
|
+
/^(gdb|lldb)\s*/i
|
|
325
|
+
];
|
|
326
|
+
}
|
|
327
|
+
});
|
|
6
328
|
|
|
7
329
|
// src/app/agent/core/llm/tool_call_normalizer.ts
|
|
8
330
|
import { randomUUID } from "crypto";
|
|
@@ -2476,587 +2798,286 @@ async function grepSearch(args) {
|
|
|
2476
2798
|
searchStats.filesSearched = 1;
|
|
2477
2799
|
const found = await searchFile(resolvedPath, path7.dirname(resolvedPath), pattern, context_lines, matches, max_results);
|
|
2478
2800
|
if (found > 0) searchStats.filesWithMatches = 1;
|
|
2479
|
-
}
|
|
2480
|
-
return {
|
|
2481
|
-
success: true,
|
|
2482
|
-
query,
|
|
2483
|
-
search_path: resolvedPath,
|
|
2484
|
-
matches,
|
|
2485
|
-
files_searched: searchStats.filesSearched,
|
|
2486
|
-
files_with_matches: searchStats.filesWithMatches,
|
|
2487
|
-
total_matches: matches.length,
|
|
2488
|
-
truncated: matches.length >= max_results
|
|
2489
|
-
};
|
|
2490
|
-
} catch (error) {
|
|
2491
|
-
return {
|
|
2492
|
-
success: false,
|
|
2493
|
-
query: args.query || "",
|
|
2494
|
-
search_path: args.path || "",
|
|
2495
|
-
matches: [],
|
|
2496
|
-
files_searched: 0,
|
|
2497
|
-
files_with_matches: 0,
|
|
2498
|
-
total_matches: 0,
|
|
2499
|
-
truncated: false,
|
|
2500
|
-
error: `Unexpected error: ${error.message}`
|
|
2501
|
-
};
|
|
2502
|
-
}
|
|
2503
|
-
}
|
|
2504
|
-
|
|
2505
|
-
// src/app/agent/tools/natives/view_file_outline.ts
|
|
2506
|
-
import path8 from "path";
|
|
2507
|
-
import { promises as fsPromises3 } from "fs";
|
|
2508
|
-
var LANGUAGE_MAP = {
|
|
2509
|
-
".ts": "typescript",
|
|
2510
|
-
".tsx": "typescript",
|
|
2511
|
-
".js": "javascript",
|
|
2512
|
-
".jsx": "javascript",
|
|
2513
|
-
".mjs": "javascript",
|
|
2514
|
-
".cjs": "javascript",
|
|
2515
|
-
".py": "python",
|
|
2516
|
-
".java": "java",
|
|
2517
|
-
".go": "go",
|
|
2518
|
-
".rs": "rust",
|
|
2519
|
-
".rb": "ruby",
|
|
2520
|
-
".php": "php",
|
|
2521
|
-
".cs": "csharp",
|
|
2522
|
-
".cpp": "cpp",
|
|
2523
|
-
".c": "c",
|
|
2524
|
-
".h": "c",
|
|
2525
|
-
".hpp": "cpp",
|
|
2526
|
-
".swift": "swift",
|
|
2527
|
-
".kt": "kotlin",
|
|
2528
|
-
".scala": "scala"
|
|
2529
|
-
};
|
|
2530
|
-
var PATTERNS = {
|
|
2531
|
-
typescript: [
|
|
2532
|
-
// Classes
|
|
2533
|
-
/^(?:export\s+)?(?:abstract\s+)?class\s+(\w+)(?:\s+extends\s+\w+)?(?:\s+implements\s+[\w,\s]+)?/,
|
|
2534
|
-
// Interfaces
|
|
2535
|
-
/^(?:export\s+)?interface\s+(\w+)/,
|
|
2536
|
-
// Types
|
|
2537
|
-
/^(?:export\s+)?type\s+(\w+)/,
|
|
2538
|
-
// Functions (standalone)
|
|
2539
|
-
/^(?:export\s+)?(?:async\s+)?function\s+(\w+)\s*\(/,
|
|
2540
|
-
// Arrow functions assigned to const/let
|
|
2541
|
-
/^(?:export\s+)?(?:const|let)\s+(\w+)\s*=\s*(?:async\s+)?(?:\([^)]*\)|[^=])\s*=>/,
|
|
2542
|
-
// Methods inside classes (indented)
|
|
2543
|
-
/^\s+(?:public|private|protected|static|async|readonly|\s)*(\w+)\s*\([^)]*\)\s*(?::\s*[\w<>\[\]|&\s]+)?\s*\{/,
|
|
2544
|
-
// Const exports
|
|
2545
|
-
/^(?:export\s+)?const\s+(\w+)\s*[:=]/
|
|
2546
|
-
],
|
|
2547
|
-
javascript: [
|
|
2548
|
-
/^(?:export\s+)?(?:default\s+)?class\s+(\w+)/,
|
|
2549
|
-
/^(?:export\s+)?(?:async\s+)?function\s+(\w+)\s*\(/,
|
|
2550
|
-
/^(?:export\s+)?(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?(?:\([^)]*\)|[^=])\s*=>/,
|
|
2551
|
-
/^\s+(?:async\s+)?(\w+)\s*\([^)]*\)\s*\{/,
|
|
2552
|
-
/^(?:export\s+)?(?:const|let|var)\s+(\w+)\s*=/
|
|
2553
|
-
],
|
|
2554
|
-
python: [
|
|
2555
|
-
/^class\s+(\w+)(?:\([^)]*\))?:/,
|
|
2556
|
-
/^(?:async\s+)?def\s+(\w+)\s*\(/,
|
|
2557
|
-
/^(\w+)\s*=\s*(?:lambda|def)/
|
|
2558
|
-
],
|
|
2559
|
-
java: [
|
|
2560
|
-
/^(?:public|private|protected)?\s*(?:static)?\s*(?:final)?\s*(?:abstract)?\s*class\s+(\w+)/,
|
|
2561
|
-
/^(?:public|private|protected)?\s*(?:static)?\s*(?:final)?\s*interface\s+(\w+)/,
|
|
2562
|
-
/^\s*(?:public|private|protected)?\s*(?:static)?\s*(?:final)?\s*(?:synchronized)?\s*(?:\w+(?:<[^>]+>)?)\s+(\w+)\s*\(/
|
|
2563
|
-
],
|
|
2564
|
-
go: [
|
|
2565
|
-
/^type\s+(\w+)\s+struct\s*\{/,
|
|
2566
|
-
/^type\s+(\w+)\s+interface\s*\{/,
|
|
2567
|
-
/^func\s+(?:\([^)]+\)\s+)?(\w+)\s*\(/
|
|
2568
|
-
],
|
|
2569
|
-
rust: [
|
|
2570
|
-
/^(?:pub\s+)?struct\s+(\w+)/,
|
|
2571
|
-
/^(?:pub\s+)?enum\s+(\w+)/,
|
|
2572
|
-
/^(?:pub\s+)?trait\s+(\w+)/,
|
|
2573
|
-
/^(?:pub\s+)?(?:async\s+)?fn\s+(\w+)/,
|
|
2574
|
-
/^impl(?:<[^>]+>)?\s+(?:(\w+)|for\s+(\w+))/
|
|
2575
|
-
],
|
|
2576
|
-
ruby: [
|
|
2577
|
-
/^class\s+(\w+)/,
|
|
2578
|
-
/^module\s+(\w+)/,
|
|
2579
|
-
/^def\s+(\w+)/
|
|
2580
|
-
],
|
|
2581
|
-
php: [
|
|
2582
|
-
/^(?:abstract\s+)?class\s+(\w+)/,
|
|
2583
|
-
/^interface\s+(\w+)/,
|
|
2584
|
-
/^(?:public|private|protected)?\s*(?:static)?\s*function\s+(\w+)/
|
|
2585
|
-
],
|
|
2586
|
-
csharp: [
|
|
2587
|
-
/^(?:public|private|protected|internal)?\s*(?:static)?\s*(?:partial)?\s*class\s+(\w+)/,
|
|
2588
|
-
/^(?:public|private|protected|internal)?\s*interface\s+(\w+)/,
|
|
2589
|
-
/^\s*(?:public|private|protected|internal)?\s*(?:static)?\s*(?:async)?\s*(?:\w+(?:<[^>]+>)?)\s+(\w+)\s*\(/
|
|
2590
|
-
],
|
|
2591
|
-
swift: [
|
|
2592
|
-
/^(?:public|private|internal|open)?\s*class\s+(\w+)/,
|
|
2593
|
-
/^(?:public|private|internal)?\s*struct\s+(\w+)/,
|
|
2594
|
-
/^(?:public|private|internal)?\s*protocol\s+(\w+)/,
|
|
2595
|
-
/^(?:public|private|internal)?\s*(?:static)?\s*func\s+(\w+)/
|
|
2596
|
-
],
|
|
2597
|
-
kotlin: [
|
|
2598
|
-
/^(?:open|abstract|sealed)?\s*class\s+(\w+)/,
|
|
2599
|
-
/^interface\s+(\w+)/,
|
|
2600
|
-
/^(?:private|public|internal)?\s*fun\s+(\w+)/
|
|
2601
|
-
],
|
|
2602
|
-
scala: [
|
|
2603
|
-
/^(?:sealed\s+)?(?:abstract\s+)?class\s+(\w+)/,
|
|
2604
|
-
/^object\s+(\w+)/,
|
|
2605
|
-
/^trait\s+(\w+)/,
|
|
2606
|
-
/^def\s+(\w+)/
|
|
2607
|
-
],
|
|
2608
|
-
c: [
|
|
2609
|
-
/^(?:static\s+)?(?:inline\s+)?(?:const\s+)?(?:\w+(?:\s*\*)*)\s+(\w+)\s*\([^)]*\)\s*\{/,
|
|
2610
|
-
/^typedef\s+struct\s*\w*\s*\{[^}]*\}\s*(\w+)/,
|
|
2611
|
-
/^struct\s+(\w+)\s*\{/
|
|
2612
|
-
],
|
|
2613
|
-
cpp: [
|
|
2614
|
-
/^class\s+(\w+)/,
|
|
2615
|
-
/^(?:virtual\s+)?(?:\w+(?:\s*[*&])*)\s+(\w+)\s*\([^)]*\)\s*(?:const)?\s*(?:override)?\s*\{/,
|
|
2616
|
-
/^namespace\s+(\w+)\s*\{/
|
|
2617
|
-
]
|
|
2618
|
-
};
|
|
2619
|
-
function detectLanguage(filepath) {
|
|
2620
|
-
const ext = path8.extname(filepath).toLowerCase();
|
|
2621
|
-
return LANGUAGE_MAP[ext] || "unknown";
|
|
2622
|
-
}
|
|
2623
|
-
function determineItemType(line, language) {
|
|
2624
|
-
const normalizedLine = line.trim().toLowerCase();
|
|
2625
|
-
if (normalizedLine.includes("class ")) return "class";
|
|
2626
|
-
if (normalizedLine.includes("interface ")) return "interface";
|
|
2627
|
-
if (normalizedLine.includes("type ")) return "type";
|
|
2628
|
-
if (normalizedLine.startsWith("import ")) return "import";
|
|
2629
|
-
if (normalizedLine.includes("export ") && !normalizedLine.includes("function") && !normalizedLine.includes("class")) return "export";
|
|
2630
|
-
if (line.startsWith(" ") || line.startsWith(" ")) {
|
|
2631
|
-
if (normalizedLine.includes("function") || normalizedLine.includes("def ") || normalizedLine.includes("fn ") || normalizedLine.includes("func ")) {
|
|
2632
|
-
return "method";
|
|
2633
|
-
}
|
|
2634
|
-
if (/^\s+\w+\s*\(/.test(line)) return "method";
|
|
2635
|
-
}
|
|
2636
|
-
if (normalizedLine.includes("function ") || normalizedLine.includes("def ") || normalizedLine.includes("fn ") || normalizedLine.includes("func ")) {
|
|
2637
|
-
return "function";
|
|
2638
|
-
}
|
|
2639
|
-
if (normalizedLine.includes("const ") || normalizedLine.includes("let ") || normalizedLine.includes("var ")) {
|
|
2640
|
-
return normalizedLine.includes("=>") ? "function" : "const";
|
|
2641
|
-
}
|
|
2642
|
-
return "function";
|
|
2643
|
-
}
|
|
2644
|
-
async function extractOutline(filepath, content, language) {
|
|
2645
|
-
const items = [];
|
|
2646
|
-
const lines = content.split("\n");
|
|
2647
|
-
const patterns = PATTERNS[language] || PATTERNS.javascript;
|
|
2648
|
-
let currentClass = null;
|
|
2649
|
-
let braceCount = 0;
|
|
2650
|
-
for (let i = 0; i < lines.length; i++) {
|
|
2651
|
-
const line = lines[i];
|
|
2652
|
-
const lineNumber = i + 1;
|
|
2653
|
-
const openBraces = (line.match(/\{/g) || []).length;
|
|
2654
|
-
const closeBraces = (line.match(/\}/g) || []).length;
|
|
2655
|
-
braceCount += openBraces - closeBraces;
|
|
2656
|
-
if (braceCount <= 0 && currentClass) {
|
|
2657
|
-
currentClass = null;
|
|
2658
|
-
}
|
|
2659
|
-
for (const pattern of patterns) {
|
|
2660
|
-
const match = line.match(pattern);
|
|
2661
|
-
if (match) {
|
|
2662
|
-
const name = match[1] || match[2];
|
|
2663
|
-
if (!name) continue;
|
|
2664
|
-
const itemType = determineItemType(line, language);
|
|
2665
|
-
if (!itemType) continue;
|
|
2666
|
-
const exported = line.includes("export ");
|
|
2667
|
-
const isInsideClass = currentClass && (line.startsWith(" ") || line.startsWith(" "));
|
|
2668
|
-
const item = {
|
|
2669
|
-
type: itemType,
|
|
2670
|
-
name,
|
|
2671
|
-
line_start: lineNumber,
|
|
2672
|
-
signature: line.trim().substring(0, 120),
|
|
2673
|
-
exported
|
|
2674
|
-
};
|
|
2675
|
-
if (isInsideClass && itemType === "method" && currentClass) {
|
|
2676
|
-
item.parent = currentClass;
|
|
2677
|
-
}
|
|
2678
|
-
if (itemType === "class") {
|
|
2679
|
-
currentClass = name;
|
|
2680
|
-
}
|
|
2681
|
-
items.push(item);
|
|
2682
|
-
break;
|
|
2683
|
-
}
|
|
2684
|
-
}
|
|
2685
|
-
}
|
|
2686
|
-
return items;
|
|
2687
|
-
}
|
|
2688
|
-
function generateSummary(items, totalLines) {
|
|
2689
|
-
const counts = {};
|
|
2690
|
-
for (const item of items) {
|
|
2691
|
-
counts[item.type] = (counts[item.type] || 0) + 1;
|
|
2692
|
-
}
|
|
2693
|
-
const parts = [`${totalLines} lines`];
|
|
2694
|
-
if (counts.class) parts.push(`${counts.class} class${counts.class > 1 ? "es" : ""}`);
|
|
2695
|
-
if (counts.interface) parts.push(`${counts.interface} interface${counts.interface > 1 ? "s" : ""}`);
|
|
2696
|
-
if (counts.function) parts.push(`${counts.function} function${counts.function > 1 ? "s" : ""}`);
|
|
2697
|
-
if (counts.method) parts.push(`${counts.method} method${counts.method > 1 ? "s" : ""}`);
|
|
2698
|
-
if (counts.type) parts.push(`${counts.type} type${counts.type > 1 ? "s" : ""}`);
|
|
2699
|
-
if (counts.const) parts.push(`${counts.const} const${counts.const > 1 ? "s" : ""}`);
|
|
2700
|
-
return parts.join(", ");
|
|
2701
|
-
}
|
|
2702
|
-
async function viewFileOutline(args) {
|
|
2703
|
-
try {
|
|
2704
|
-
const { file_path } = args;
|
|
2705
|
-
if (!file_path || typeof file_path !== "string") {
|
|
2706
|
-
return {
|
|
2707
|
-
success: false,
|
|
2708
|
-
file_path: file_path || "",
|
|
2709
|
-
language: "unknown",
|
|
2710
|
-
total_lines: 0,
|
|
2711
|
-
items: [],
|
|
2712
|
-
summary: "",
|
|
2713
|
-
error: "file_path is required and must be a string"
|
|
2714
|
-
};
|
|
2715
|
-
}
|
|
2716
|
-
const resolvedPath = path8.resolve(file_path);
|
|
2717
|
-
let content;
|
|
2718
|
-
try {
|
|
2719
|
-
content = await fsPromises3.readFile(resolvedPath, "utf-8");
|
|
2720
|
-
} catch (error) {
|
|
2721
|
-
return {
|
|
2722
|
-
success: false,
|
|
2723
|
-
file_path: resolvedPath,
|
|
2724
|
-
language: "unknown",
|
|
2725
|
-
total_lines: 0,
|
|
2726
|
-
items: [],
|
|
2727
|
-
summary: "",
|
|
2728
|
-
error: error.code === "ENOENT" ? `File not found: ${resolvedPath}` : `Error reading file: ${error.message}`
|
|
2729
|
-
};
|
|
2730
|
-
}
|
|
2731
|
-
const language = detectLanguage(resolvedPath);
|
|
2732
|
-
const lines = content.split("\n");
|
|
2733
|
-
const totalLines = lines.length;
|
|
2734
|
-
const items = await extractOutline(resolvedPath, content, language);
|
|
2801
|
+
}
|
|
2735
2802
|
return {
|
|
2736
2803
|
success: true,
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2804
|
+
query,
|
|
2805
|
+
search_path: resolvedPath,
|
|
2806
|
+
matches,
|
|
2807
|
+
files_searched: searchStats.filesSearched,
|
|
2808
|
+
files_with_matches: searchStats.filesWithMatches,
|
|
2809
|
+
total_matches: matches.length,
|
|
2810
|
+
truncated: matches.length >= max_results
|
|
2742
2811
|
};
|
|
2743
2812
|
} catch (error) {
|
|
2744
2813
|
return {
|
|
2745
2814
|
success: false,
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2815
|
+
query: args.query || "",
|
|
2816
|
+
search_path: args.path || "",
|
|
2817
|
+
matches: [],
|
|
2818
|
+
files_searched: 0,
|
|
2819
|
+
files_with_matches: 0,
|
|
2820
|
+
total_matches: 0,
|
|
2821
|
+
truncated: false,
|
|
2751
2822
|
error: `Unexpected error: ${error.message}`
|
|
2752
2823
|
};
|
|
2753
2824
|
}
|
|
2754
2825
|
}
|
|
2755
2826
|
|
|
2756
|
-
// src/app/agent/tools/natives/
|
|
2757
|
-
import
|
|
2758
|
-
import {
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
]
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
})
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
entry.exitCode = code;
|
|
2885
|
-
entry.status = code === 0 ? "completed" : "error";
|
|
2886
|
-
entry.endTime = Date.now();
|
|
2887
|
-
entry.process = null;
|
|
2888
|
-
});
|
|
2889
|
-
child.on("error", (error) => {
|
|
2890
|
-
entry.stderr += `
|
|
2891
|
-
Process error: ${error.message}`;
|
|
2892
|
-
entry.status = "error";
|
|
2893
|
-
entry.endTime = Date.now();
|
|
2894
|
-
entry.process = null;
|
|
2895
|
-
});
|
|
2896
|
-
if (timeout > 0) {
|
|
2897
|
-
setTimeout(() => {
|
|
2898
|
-
if (entry.status === "running") {
|
|
2899
|
-
child.kill("SIGTERM");
|
|
2900
|
-
setTimeout(() => {
|
|
2901
|
-
if (entry.status === "running") {
|
|
2902
|
-
child.kill("SIGKILL");
|
|
2903
|
-
}
|
|
2904
|
-
}, 2e3);
|
|
2905
|
-
entry.status = "timeout";
|
|
2906
|
-
entry.stderr += `
|
|
2907
|
-
Command timed out after ${timeout} seconds`;
|
|
2908
|
-
}
|
|
2909
|
-
}, timeout * 1e3);
|
|
2827
|
+
// src/app/agent/tools/natives/view_file_outline.ts
|
|
2828
|
+
import path8 from "path";
|
|
2829
|
+
import { promises as fsPromises3 } from "fs";
|
|
2830
|
+
var LANGUAGE_MAP = {
|
|
2831
|
+
".ts": "typescript",
|
|
2832
|
+
".tsx": "typescript",
|
|
2833
|
+
".js": "javascript",
|
|
2834
|
+
".jsx": "javascript",
|
|
2835
|
+
".mjs": "javascript",
|
|
2836
|
+
".cjs": "javascript",
|
|
2837
|
+
".py": "python",
|
|
2838
|
+
".java": "java",
|
|
2839
|
+
".go": "go",
|
|
2840
|
+
".rs": "rust",
|
|
2841
|
+
".rb": "ruby",
|
|
2842
|
+
".php": "php",
|
|
2843
|
+
".cs": "csharp",
|
|
2844
|
+
".cpp": "cpp",
|
|
2845
|
+
".c": "c",
|
|
2846
|
+
".h": "c",
|
|
2847
|
+
".hpp": "cpp",
|
|
2848
|
+
".swift": "swift",
|
|
2849
|
+
".kt": "kotlin",
|
|
2850
|
+
".scala": "scala"
|
|
2851
|
+
};
|
|
2852
|
+
var PATTERNS = {
|
|
2853
|
+
typescript: [
|
|
2854
|
+
// Classes
|
|
2855
|
+
/^(?:export\s+)?(?:abstract\s+)?class\s+(\w+)(?:\s+extends\s+\w+)?(?:\s+implements\s+[\w,\s]+)?/,
|
|
2856
|
+
// Interfaces
|
|
2857
|
+
/^(?:export\s+)?interface\s+(\w+)/,
|
|
2858
|
+
// Types
|
|
2859
|
+
/^(?:export\s+)?type\s+(\w+)/,
|
|
2860
|
+
// Functions (standalone)
|
|
2861
|
+
/^(?:export\s+)?(?:async\s+)?function\s+(\w+)\s*\(/,
|
|
2862
|
+
// Arrow functions assigned to const/let
|
|
2863
|
+
/^(?:export\s+)?(?:const|let)\s+(\w+)\s*=\s*(?:async\s+)?(?:\([^)]*\)|[^=])\s*=>/,
|
|
2864
|
+
// Methods inside classes (indented)
|
|
2865
|
+
/^\s+(?:public|private|protected|static|async|readonly|\s)*(\w+)\s*\([^)]*\)\s*(?::\s*[\w<>\[\]|&\s]+)?\s*\{/,
|
|
2866
|
+
// Const exports
|
|
2867
|
+
/^(?:export\s+)?const\s+(\w+)\s*[:=]/
|
|
2868
|
+
],
|
|
2869
|
+
javascript: [
|
|
2870
|
+
/^(?:export\s+)?(?:default\s+)?class\s+(\w+)/,
|
|
2871
|
+
/^(?:export\s+)?(?:async\s+)?function\s+(\w+)\s*\(/,
|
|
2872
|
+
/^(?:export\s+)?(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?(?:\([^)]*\)|[^=])\s*=>/,
|
|
2873
|
+
/^\s+(?:async\s+)?(\w+)\s*\([^)]*\)\s*\{/,
|
|
2874
|
+
/^(?:export\s+)?(?:const|let|var)\s+(\w+)\s*=/
|
|
2875
|
+
],
|
|
2876
|
+
python: [
|
|
2877
|
+
/^class\s+(\w+)(?:\([^)]*\))?:/,
|
|
2878
|
+
/^(?:async\s+)?def\s+(\w+)\s*\(/,
|
|
2879
|
+
/^(\w+)\s*=\s*(?:lambda|def)/
|
|
2880
|
+
],
|
|
2881
|
+
java: [
|
|
2882
|
+
/^(?:public|private|protected)?\s*(?:static)?\s*(?:final)?\s*(?:abstract)?\s*class\s+(\w+)/,
|
|
2883
|
+
/^(?:public|private|protected)?\s*(?:static)?\s*(?:final)?\s*interface\s+(\w+)/,
|
|
2884
|
+
/^\s*(?:public|private|protected)?\s*(?:static)?\s*(?:final)?\s*(?:synchronized)?\s*(?:\w+(?:<[^>]+>)?)\s+(\w+)\s*\(/
|
|
2885
|
+
],
|
|
2886
|
+
go: [
|
|
2887
|
+
/^type\s+(\w+)\s+struct\s*\{/,
|
|
2888
|
+
/^type\s+(\w+)\s+interface\s*\{/,
|
|
2889
|
+
/^func\s+(?:\([^)]+\)\s+)?(\w+)\s*\(/
|
|
2890
|
+
],
|
|
2891
|
+
rust: [
|
|
2892
|
+
/^(?:pub\s+)?struct\s+(\w+)/,
|
|
2893
|
+
/^(?:pub\s+)?enum\s+(\w+)/,
|
|
2894
|
+
/^(?:pub\s+)?trait\s+(\w+)/,
|
|
2895
|
+
/^(?:pub\s+)?(?:async\s+)?fn\s+(\w+)/,
|
|
2896
|
+
/^impl(?:<[^>]+>)?\s+(?:(\w+)|for\s+(\w+))/
|
|
2897
|
+
],
|
|
2898
|
+
ruby: [
|
|
2899
|
+
/^class\s+(\w+)/,
|
|
2900
|
+
/^module\s+(\w+)/,
|
|
2901
|
+
/^def\s+(\w+)/
|
|
2902
|
+
],
|
|
2903
|
+
php: [
|
|
2904
|
+
/^(?:abstract\s+)?class\s+(\w+)/,
|
|
2905
|
+
/^interface\s+(\w+)/,
|
|
2906
|
+
/^(?:public|private|protected)?\s*(?:static)?\s*function\s+(\w+)/
|
|
2907
|
+
],
|
|
2908
|
+
csharp: [
|
|
2909
|
+
/^(?:public|private|protected|internal)?\s*(?:static)?\s*(?:partial)?\s*class\s+(\w+)/,
|
|
2910
|
+
/^(?:public|private|protected|internal)?\s*interface\s+(\w+)/,
|
|
2911
|
+
/^\s*(?:public|private|protected|internal)?\s*(?:static)?\s*(?:async)?\s*(?:\w+(?:<[^>]+>)?)\s+(\w+)\s*\(/
|
|
2912
|
+
],
|
|
2913
|
+
swift: [
|
|
2914
|
+
/^(?:public|private|internal|open)?\s*class\s+(\w+)/,
|
|
2915
|
+
/^(?:public|private|internal)?\s*struct\s+(\w+)/,
|
|
2916
|
+
/^(?:public|private|internal)?\s*protocol\s+(\w+)/,
|
|
2917
|
+
/^(?:public|private|internal)?\s*(?:static)?\s*func\s+(\w+)/
|
|
2918
|
+
],
|
|
2919
|
+
kotlin: [
|
|
2920
|
+
/^(?:open|abstract|sealed)?\s*class\s+(\w+)/,
|
|
2921
|
+
/^interface\s+(\w+)/,
|
|
2922
|
+
/^(?:private|public|internal)?\s*fun\s+(\w+)/
|
|
2923
|
+
],
|
|
2924
|
+
scala: [
|
|
2925
|
+
/^(?:sealed\s+)?(?:abstract\s+)?class\s+(\w+)/,
|
|
2926
|
+
/^object\s+(\w+)/,
|
|
2927
|
+
/^trait\s+(\w+)/,
|
|
2928
|
+
/^def\s+(\w+)/
|
|
2929
|
+
],
|
|
2930
|
+
c: [
|
|
2931
|
+
/^(?:static\s+)?(?:inline\s+)?(?:const\s+)?(?:\w+(?:\s*\*)*)\s+(\w+)\s*\([^)]*\)\s*\{/,
|
|
2932
|
+
/^typedef\s+struct\s*\w*\s*\{[^}]*\}\s*(\w+)/,
|
|
2933
|
+
/^struct\s+(\w+)\s*\{/
|
|
2934
|
+
],
|
|
2935
|
+
cpp: [
|
|
2936
|
+
/^class\s+(\w+)/,
|
|
2937
|
+
/^(?:virtual\s+)?(?:\w+(?:\s*[*&])*)\s+(\w+)\s*\([^)]*\)\s*(?:const)?\s*(?:override)?\s*\{/,
|
|
2938
|
+
/^namespace\s+(\w+)\s*\{/
|
|
2939
|
+
]
|
|
2940
|
+
};
|
|
2941
|
+
function detectLanguage(filepath) {
|
|
2942
|
+
const ext = path8.extname(filepath).toLowerCase();
|
|
2943
|
+
return LANGUAGE_MAP[ext] || "unknown";
|
|
2944
|
+
}
|
|
2945
|
+
function determineItemType(line, language) {
|
|
2946
|
+
const normalizedLine = line.trim().toLowerCase();
|
|
2947
|
+
if (normalizedLine.includes("class ")) return "class";
|
|
2948
|
+
if (normalizedLine.includes("interface ")) return "interface";
|
|
2949
|
+
if (normalizedLine.includes("type ")) return "type";
|
|
2950
|
+
if (normalizedLine.startsWith("import ")) return "import";
|
|
2951
|
+
if (normalizedLine.includes("export ") && !normalizedLine.includes("function") && !normalizedLine.includes("class")) return "export";
|
|
2952
|
+
if (line.startsWith(" ") || line.startsWith(" ")) {
|
|
2953
|
+
if (normalizedLine.includes("function") || normalizedLine.includes("def ") || normalizedLine.includes("fn ") || normalizedLine.includes("func ")) {
|
|
2954
|
+
return "method";
|
|
2910
2955
|
}
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
command_id: commandId,
|
|
2916
|
-
command,
|
|
2917
|
-
message: `Command started in background. Use command_status with id "${commandId}" to check progress.`
|
|
2918
|
-
};
|
|
2919
|
-
} catch (error) {
|
|
2920
|
-
return {
|
|
2921
|
-
success: false,
|
|
2922
|
-
error: `Unexpected error: ${error.message}`
|
|
2923
|
-
};
|
|
2956
|
+
if (/^\s+\w+\s*\(/.test(line)) return "method";
|
|
2957
|
+
}
|
|
2958
|
+
if (normalizedLine.includes("function ") || normalizedLine.includes("def ") || normalizedLine.includes("fn ") || normalizedLine.includes("func ")) {
|
|
2959
|
+
return "function";
|
|
2924
2960
|
}
|
|
2961
|
+
if (normalizedLine.includes("const ") || normalizedLine.includes("let ") || normalizedLine.includes("var ")) {
|
|
2962
|
+
return normalizedLine.includes("=>") ? "function" : "const";
|
|
2963
|
+
}
|
|
2964
|
+
return "function";
|
|
2925
2965
|
}
|
|
2926
|
-
async function
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
}
|
|
2941
|
-
const entry = runningCommands.get(command_id);
|
|
2942
|
-
if (!entry) {
|
|
2943
|
-
return {
|
|
2944
|
-
success: false,
|
|
2945
|
-
command_id,
|
|
2946
|
-
status: "not_found",
|
|
2947
|
-
error: `Command with id "${command_id}" not found. It may have expired or never existed.`
|
|
2948
|
-
};
|
|
2949
|
-
}
|
|
2950
|
-
if (wait_seconds > 0 && entry.status === "running") {
|
|
2951
|
-
await new Promise((resolve) => {
|
|
2952
|
-
const checkInterval = setInterval(() => {
|
|
2953
|
-
if (entry.status !== "running") {
|
|
2954
|
-
clearInterval(checkInterval);
|
|
2955
|
-
resolve();
|
|
2956
|
-
}
|
|
2957
|
-
}, 100);
|
|
2958
|
-
setTimeout(() => {
|
|
2959
|
-
clearInterval(checkInterval);
|
|
2960
|
-
resolve();
|
|
2961
|
-
}, wait_seconds * 1e3);
|
|
2962
|
-
});
|
|
2963
|
-
}
|
|
2964
|
-
let stdout = entry.stdout;
|
|
2965
|
-
let stderr = entry.stderr;
|
|
2966
|
-
let truncated = false;
|
|
2967
|
-
if (stdout.length > output_limit) {
|
|
2968
|
-
stdout = "..." + stdout.substring(stdout.length - output_limit);
|
|
2969
|
-
truncated = true;
|
|
2966
|
+
async function extractOutline(filepath, content, language) {
|
|
2967
|
+
const items = [];
|
|
2968
|
+
const lines = content.split("\n");
|
|
2969
|
+
const patterns = PATTERNS[language] || PATTERNS.javascript;
|
|
2970
|
+
let currentClass = null;
|
|
2971
|
+
let braceCount = 0;
|
|
2972
|
+
for (let i = 0; i < lines.length; i++) {
|
|
2973
|
+
const line = lines[i];
|
|
2974
|
+
const lineNumber = i + 1;
|
|
2975
|
+
const openBraces = (line.match(/\{/g) || []).length;
|
|
2976
|
+
const closeBraces = (line.match(/\}/g) || []).length;
|
|
2977
|
+
braceCount += openBraces - closeBraces;
|
|
2978
|
+
if (braceCount <= 0 && currentClass) {
|
|
2979
|
+
currentClass = null;
|
|
2970
2980
|
}
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2981
|
+
for (const pattern of patterns) {
|
|
2982
|
+
const match = line.match(pattern);
|
|
2983
|
+
if (match) {
|
|
2984
|
+
const name = match[1] || match[2];
|
|
2985
|
+
if (!name) continue;
|
|
2986
|
+
const itemType = determineItemType(line, language);
|
|
2987
|
+
if (!itemType) continue;
|
|
2988
|
+
const exported = line.includes("export ");
|
|
2989
|
+
const isInsideClass = currentClass && (line.startsWith(" ") || line.startsWith(" "));
|
|
2990
|
+
const item = {
|
|
2991
|
+
type: itemType,
|
|
2992
|
+
name,
|
|
2993
|
+
line_start: lineNumber,
|
|
2994
|
+
signature: line.trim().substring(0, 120),
|
|
2995
|
+
exported
|
|
2996
|
+
};
|
|
2997
|
+
if (isInsideClass && itemType === "method" && currentClass) {
|
|
2998
|
+
item.parent = currentClass;
|
|
2999
|
+
}
|
|
3000
|
+
if (itemType === "class") {
|
|
3001
|
+
currentClass = name;
|
|
3002
|
+
}
|
|
3003
|
+
items.push(item);
|
|
3004
|
+
break;
|
|
3005
|
+
}
|
|
2974
3006
|
}
|
|
2975
|
-
const duration = entry.endTime ? (entry.endTime - entry.startTime) / 1e3 : (Date.now() - entry.startTime) / 1e3;
|
|
2976
|
-
return {
|
|
2977
|
-
success: true,
|
|
2978
|
-
command_id,
|
|
2979
|
-
status: entry.status,
|
|
2980
|
-
stdout: stdout || void 0,
|
|
2981
|
-
stderr: stderr || void 0,
|
|
2982
|
-
exit_code: entry.exitCode,
|
|
2983
|
-
duration_seconds: Math.round(duration * 10) / 10,
|
|
2984
|
-
truncated
|
|
2985
|
-
};
|
|
2986
|
-
} catch (error) {
|
|
2987
|
-
return {
|
|
2988
|
-
success: false,
|
|
2989
|
-
command_id: args.command_id || "",
|
|
2990
|
-
status: "error",
|
|
2991
|
-
error: `Unexpected error: ${error.message}`
|
|
2992
|
-
};
|
|
2993
3007
|
}
|
|
3008
|
+
return items;
|
|
2994
3009
|
}
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
return {
|
|
3000
|
-
success: false,
|
|
3001
|
-
error: "command_id and input are required"
|
|
3002
|
-
};
|
|
3003
|
-
}
|
|
3004
|
-
const entry = runningCommands.get(command_id);
|
|
3005
|
-
if (!entry) {
|
|
3006
|
-
return {
|
|
3007
|
-
success: false,
|
|
3008
|
-
error: `Command with id "${command_id}" not found`
|
|
3009
|
-
};
|
|
3010
|
-
}
|
|
3011
|
-
if (entry.status !== "running" || !entry.process) {
|
|
3012
|
-
return {
|
|
3013
|
-
success: false,
|
|
3014
|
-
error: `Command is not running (status: ${entry.status})`
|
|
3015
|
-
};
|
|
3016
|
-
}
|
|
3017
|
-
entry.process.stdin?.write(input);
|
|
3018
|
-
return {
|
|
3019
|
-
success: true,
|
|
3020
|
-
message: `Sent ${input.length} characters to command ${command_id}`
|
|
3021
|
-
};
|
|
3022
|
-
} catch (error) {
|
|
3023
|
-
return {
|
|
3024
|
-
success: false,
|
|
3025
|
-
error: `Failed to send input: ${error.message}`
|
|
3026
|
-
};
|
|
3010
|
+
function generateSummary(items, totalLines) {
|
|
3011
|
+
const counts = {};
|
|
3012
|
+
for (const item of items) {
|
|
3013
|
+
counts[item.type] = (counts[item.type] || 0) + 1;
|
|
3027
3014
|
}
|
|
3015
|
+
const parts = [`${totalLines} lines`];
|
|
3016
|
+
if (counts.class) parts.push(`${counts.class} class${counts.class > 1 ? "es" : ""}`);
|
|
3017
|
+
if (counts.interface) parts.push(`${counts.interface} interface${counts.interface > 1 ? "s" : ""}`);
|
|
3018
|
+
if (counts.function) parts.push(`${counts.function} function${counts.function > 1 ? "s" : ""}`);
|
|
3019
|
+
if (counts.method) parts.push(`${counts.method} method${counts.method > 1 ? "s" : ""}`);
|
|
3020
|
+
if (counts.type) parts.push(`${counts.type} type${counts.type > 1 ? "s" : ""}`);
|
|
3021
|
+
if (counts.const) parts.push(`${counts.const} const${counts.const > 1 ? "s" : ""}`);
|
|
3022
|
+
return parts.join(", ");
|
|
3028
3023
|
}
|
|
3029
|
-
async function
|
|
3024
|
+
async function viewFileOutline(args) {
|
|
3030
3025
|
try {
|
|
3031
|
-
const {
|
|
3032
|
-
|
|
3033
|
-
if (!entry) {
|
|
3026
|
+
const { file_path } = args;
|
|
3027
|
+
if (!file_path || typeof file_path !== "string") {
|
|
3034
3028
|
return {
|
|
3035
3029
|
success: false,
|
|
3036
|
-
|
|
3030
|
+
file_path: file_path || "",
|
|
3031
|
+
language: "unknown",
|
|
3032
|
+
total_lines: 0,
|
|
3033
|
+
items: [],
|
|
3034
|
+
summary: "",
|
|
3035
|
+
error: "file_path is required and must be a string"
|
|
3037
3036
|
};
|
|
3038
3037
|
}
|
|
3039
|
-
|
|
3038
|
+
const resolvedPath = path8.resolve(file_path);
|
|
3039
|
+
let content;
|
|
3040
|
+
try {
|
|
3041
|
+
content = await fsPromises3.readFile(resolvedPath, "utf-8");
|
|
3042
|
+
} catch (error) {
|
|
3040
3043
|
return {
|
|
3041
3044
|
success: false,
|
|
3042
|
-
|
|
3045
|
+
file_path: resolvedPath,
|
|
3046
|
+
language: "unknown",
|
|
3047
|
+
total_lines: 0,
|
|
3048
|
+
items: [],
|
|
3049
|
+
summary: "",
|
|
3050
|
+
error: error.code === "ENOENT" ? `File not found: ${resolvedPath}` : `Error reading file: ${error.message}`
|
|
3043
3051
|
};
|
|
3044
3052
|
}
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3053
|
+
const language = detectLanguage(resolvedPath);
|
|
3054
|
+
const lines = content.split("\n");
|
|
3055
|
+
const totalLines = lines.length;
|
|
3056
|
+
const items = await extractOutline(resolvedPath, content, language);
|
|
3048
3057
|
return {
|
|
3049
3058
|
success: true,
|
|
3050
|
-
|
|
3059
|
+
file_path: resolvedPath,
|
|
3060
|
+
language,
|
|
3061
|
+
total_lines: totalLines,
|
|
3062
|
+
items,
|
|
3063
|
+
summary: generateSummary(items, totalLines)
|
|
3051
3064
|
};
|
|
3052
3065
|
} catch (error) {
|
|
3053
3066
|
return {
|
|
3054
3067
|
success: false,
|
|
3055
|
-
|
|
3068
|
+
file_path: args.file_path || "",
|
|
3069
|
+
language: "unknown",
|
|
3070
|
+
total_lines: 0,
|
|
3071
|
+
items: [],
|
|
3072
|
+
summary: "",
|
|
3073
|
+
error: `Unexpected error: ${error.message}`
|
|
3056
3074
|
};
|
|
3057
3075
|
}
|
|
3058
3076
|
}
|
|
3059
3077
|
|
|
3078
|
+
// src/app/agent/tool_invoker.ts
|
|
3079
|
+
init_async_command();
|
|
3080
|
+
|
|
3060
3081
|
// src/app/agent/tools/natives/task_boundary.ts
|
|
3061
3082
|
import path9 from "path";
|
|
3062
3083
|
import { promises as fs7 } from "fs";
|
|
@@ -6219,6 +6240,61 @@ var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
|
|
|
6219
6240
|
]);
|
|
6220
6241
|
return;
|
|
6221
6242
|
}
|
|
6243
|
+
if (text.startsWith("!")) {
|
|
6244
|
+
const command = text.slice(1).trim();
|
|
6245
|
+
if (!command) {
|
|
6246
|
+
setIsProcessing(false);
|
|
6247
|
+
return;
|
|
6248
|
+
}
|
|
6249
|
+
setHistory((prev) => [
|
|
6250
|
+
...prev,
|
|
6251
|
+
{
|
|
6252
|
+
id: prev.length,
|
|
6253
|
+
component: /* @__PURE__ */ jsxs15(Box16, { marginBottom: 1, children: [
|
|
6254
|
+
/* @__PURE__ */ jsx16(Text15, { color: "white", bold: true, children: "$ " }),
|
|
6255
|
+
/* @__PURE__ */ jsx16(Text15, { color: "white", children: command })
|
|
6256
|
+
] })
|
|
6257
|
+
}
|
|
6258
|
+
]);
|
|
6259
|
+
Promise.resolve().then(() => (init_async_command(), async_command_exports)).then(async ({ runCommandAsync: runCommandAsync2 }) => {
|
|
6260
|
+
try {
|
|
6261
|
+
const result = await runCommandAsync2({ command, cwd: workdir });
|
|
6262
|
+
if (result.success && result.command_id) {
|
|
6263
|
+
const contextMessage = `[User executed shell command directly]
|
|
6264
|
+
Command: ${command}
|
|
6265
|
+
Command ID: ${result.command_id}
|
|
6266
|
+
|
|
6267
|
+
Please use command_status to check the result and report back to the user.`;
|
|
6268
|
+
agentInstance.current?.processTurn({ content: contextMessage });
|
|
6269
|
+
} else {
|
|
6270
|
+
setHistory((prev) => [
|
|
6271
|
+
...prev,
|
|
6272
|
+
{
|
|
6273
|
+
id: prev.length,
|
|
6274
|
+
component: /* @__PURE__ */ jsxs15(Text15, { color: "red", children: [
|
|
6275
|
+
"Failed to execute: ",
|
|
6276
|
+
result.error || result.message
|
|
6277
|
+
] })
|
|
6278
|
+
}
|
|
6279
|
+
]);
|
|
6280
|
+
setIsProcessing(false);
|
|
6281
|
+
}
|
|
6282
|
+
} catch (err) {
|
|
6283
|
+
setHistory((prev) => [
|
|
6284
|
+
...prev,
|
|
6285
|
+
{
|
|
6286
|
+
id: prev.length,
|
|
6287
|
+
component: /* @__PURE__ */ jsxs15(Text15, { color: "red", children: [
|
|
6288
|
+
"Error: ",
|
|
6289
|
+
err.message
|
|
6290
|
+
] })
|
|
6291
|
+
}
|
|
6292
|
+
]);
|
|
6293
|
+
setIsProcessing(false);
|
|
6294
|
+
}
|
|
6295
|
+
});
|
|
6296
|
+
return;
|
|
6297
|
+
}
|
|
6222
6298
|
setIsProcessing(true);
|
|
6223
6299
|
const displayText = text.length > 1e4 ? text.substring(0, 1e4) + "..." : text;
|
|
6224
6300
|
setHistory((prev) => [
|