@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.
Files changed (2) hide show
  1. package/dist/main.js +618 -542
  2. 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
- file_path: resolvedPath,
2738
- language,
2739
- total_lines: totalLines,
2740
- items,
2741
- summary: generateSummary(items, totalLines)
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
- file_path: args.file_path || "",
2747
- language: "unknown",
2748
- total_lines: 0,
2749
- items: [],
2750
- summary: "",
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/async_command.ts
2757
- import os2 from "os";
2758
- import { spawn } from "child_process";
2759
- import { v4 as uuidv42 } from "uuid";
2760
- var runningCommands = /* @__PURE__ */ new Map();
2761
- var MAX_OUTPUT_SIZE = 3e4;
2762
- var MAX_STORED_COMMANDS = 50;
2763
- var OUTPUT_TRUNCATION_MSG = "\n[OUTPUT TRUNCATED - 30KB/200 lines max]";
2764
- var DANGEROUS_PATTERNS = [
2765
- // Elevação de privilégios
2766
- /^sudo\s+/i,
2767
- /^doas\s+/i,
2768
- /^su\s+/i,
2769
- /^pkexec\s+/i,
2770
- /\|\s*sudo\s+/i,
2771
- /;\s*sudo\s+/i,
2772
- /&&\s*sudo\s+/i,
2773
- // Comandos destrutivos
2774
- /\brm\s+(-[rf]+\s+)*[\/~]/i,
2775
- /\brm\s+-[rf]*\s+\*/i,
2776
- /\bchmod\s+(777|666)\s+\//i,
2777
- /\bdd\s+.*of=\/dev\/(sd|hd|nvme)/i,
2778
- /\bmkfs\./i,
2779
- // Fork bombs
2780
- /:\(\)\s*\{\s*:\|:&\s*\}\s*;:/,
2781
- // Remote code exec
2782
- /\bcurl\s+.*\|\s*(ba)?sh/i,
2783
- /\bwget\s+.*\|\s*(ba)?sh/i
2784
- ];
2785
- var INTERACTIVE_PATTERNS = [
2786
- /^(vim|vi|nano|emacs|pico)\s*/i,
2787
- /^(less|more|most)\s*/i,
2788
- /^(top|htop|btop|atop|nmon)\s*/i,
2789
- /^(ssh|telnet|ftp|sftp)\s+/i,
2790
- /^(mysql|psql|redis-cli|mongo|mongosh)\s*$/i,
2791
- /^(python|python3|node|ruby|irb|lua)\s*$/i,
2792
- /^(gdb|lldb)\s*/i
2793
- ];
2794
- function cleanupOldCommands() {
2795
- if (runningCommands.size <= MAX_STORED_COMMANDS) return;
2796
- const commands = Array.from(runningCommands.entries()).filter(([_, cmd]) => cmd.status !== "running").sort((a, b) => (a[1].endTime || 0) - (b[1].endTime || 0));
2797
- const toRemove = commands.slice(0, commands.length - MAX_STORED_COMMANDS + 10);
2798
- for (const [id] of toRemove) {
2799
- runningCommands.delete(id);
2800
- }
2801
- }
2802
- function isDangerousCommand(command) {
2803
- const trimmed = command.trim();
2804
- for (const pattern of DANGEROUS_PATTERNS) {
2805
- if (pattern.test(trimmed)) {
2806
- return "Command requires elevated privileges (sudo/doas) which cannot be handled in async mode";
2807
- }
2808
- }
2809
- for (const pattern of INTERACTIVE_PATTERNS) {
2810
- if (pattern.test(trimmed)) {
2811
- return "Interactive commands are not supported in async mode";
2812
- }
2813
- }
2814
- return null;
2815
- }
2816
- async function runCommandAsync(args) {
2817
- try {
2818
- const {
2819
- command,
2820
- cwd = process.cwd(),
2821
- timeout = 0
2822
- } = args;
2823
- if (!command || typeof command !== "string") {
2824
- return {
2825
- success: false,
2826
- error: "command is required and must be a string"
2827
- };
2828
- }
2829
- const dangerReason = isDangerousCommand(command);
2830
- if (dangerReason) {
2831
- return {
2832
- success: false,
2833
- error: dangerReason
2834
- };
2835
- }
2836
- const commandId = uuidv42().substring(0, 8);
2837
- const platform = os2.platform();
2838
- let shellCmd;
2839
- let shellArgs;
2840
- if (platform === "win32") {
2841
- shellCmd = process.env.COMSPEC || "cmd.exe";
2842
- shellArgs = ["/c", command];
2843
- } else {
2844
- shellCmd = process.env.SHELL || "/bin/bash";
2845
- shellArgs = ["-c", command];
2846
- }
2847
- const entry = {
2848
- id: commandId,
2849
- command,
2850
- status: "running",
2851
- stdout: "",
2852
- stderr: "",
2853
- exitCode: null,
2854
- startTime: Date.now(),
2855
- process: null
2856
- };
2857
- const child = spawn(shellCmd, shellArgs, {
2858
- cwd,
2859
- env: process.env,
2860
- windowsHide: true
2861
- });
2862
- entry.process = child;
2863
- let stdoutTruncated = false;
2864
- child.stdout?.on("data", (data) => {
2865
- if (!stdoutTruncated) {
2866
- entry.stdout += data.toString();
2867
- if (entry.stdout.length > MAX_OUTPUT_SIZE) {
2868
- entry.stdout = entry.stdout.substring(0, MAX_OUTPUT_SIZE) + OUTPUT_TRUNCATION_MSG;
2869
- stdoutTruncated = true;
2870
- }
2871
- }
2872
- });
2873
- let stderrTruncated = false;
2874
- child.stderr?.on("data", (data) => {
2875
- if (!stderrTruncated) {
2876
- entry.stderr += data.toString();
2877
- if (entry.stderr.length > MAX_OUTPUT_SIZE) {
2878
- entry.stderr = entry.stderr.substring(0, MAX_OUTPUT_SIZE) + OUTPUT_TRUNCATION_MSG;
2879
- stderrTruncated = true;
2880
- }
2881
- }
2882
- });
2883
- child.on("close", (code) => {
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
- runningCommands.set(commandId, entry);
2912
- cleanupOldCommands();
2913
- return {
2914
- success: true,
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 commandStatus(args) {
2927
- try {
2928
- const {
2929
- command_id,
2930
- wait_seconds = 0,
2931
- output_limit = 1e4
2932
- } = args;
2933
- if (!command_id) {
2934
- return {
2935
- success: false,
2936
- command_id: "",
2937
- status: "error",
2938
- error: "command_id is required"
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
- if (stderr.length > output_limit) {
2972
- stderr = "..." + stderr.substring(stderr.length - output_limit);
2973
- truncated = true;
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
- async function sendCommandInput(args) {
2996
- try {
2997
- const { command_id, input } = args;
2998
- if (!command_id || input === void 0) {
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 killCommand(args) {
3024
+ async function viewFileOutline(args) {
3030
3025
  try {
3031
- const { command_id } = args;
3032
- const entry = runningCommands.get(command_id);
3033
- if (!entry) {
3026
+ const { file_path } = args;
3027
+ if (!file_path || typeof file_path !== "string") {
3034
3028
  return {
3035
3029
  success: false,
3036
- error: `Command with id "${command_id}" not found`
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
- if (entry.status !== "running" || !entry.process) {
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
- error: `Command is not running (status: ${entry.status})`
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
- entry.process.kill("SIGTERM");
3046
- entry.status = "killed";
3047
- entry.endTime = Date.now();
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
- message: `Command ${command_id} killed`
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
- error: `Failed to kill command: ${error.message}`
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) => [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nomad-e/bluma-cli",
3
- "version": "0.0.108",
3
+ "version": "0.0.109",
4
4
  "description": "BluMa independent agent for automation and advanced software engineering.",
5
5
  "author": "Alex Fonseca",
6
6
  "license": "Apache-2.0",