@nomad-e/bluma-cli 0.1.40 → 0.1.41
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/config/native_tools.json +140 -1
- package/dist/main.js +2002 -738
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -9,6 +9,106 @@ var __export = (target, all) => {
|
|
|
9
9
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
+
// src/app/agent/runtime/sandbox_policy.ts
|
|
13
|
+
import path5 from "path";
|
|
14
|
+
function getSandboxPolicy() {
|
|
15
|
+
const isSandbox = process.env.BLUMA_SANDBOX === "true";
|
|
16
|
+
const workspaceRoot = path5.resolve(
|
|
17
|
+
process.env.BLUMA_SANDBOX_WORKSPACE || process.cwd()
|
|
18
|
+
);
|
|
19
|
+
return {
|
|
20
|
+
mode: isSandbox ? "workspace" : "local",
|
|
21
|
+
isSandbox,
|
|
22
|
+
workspaceRoot
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function isPathInsideWorkspace(targetPath, policy = getSandboxPolicy()) {
|
|
26
|
+
const resolved = path5.resolve(targetPath);
|
|
27
|
+
const relative = path5.relative(policy.workspaceRoot, resolved);
|
|
28
|
+
return relative === "" || !relative.startsWith("..") && !path5.isAbsolute(relative);
|
|
29
|
+
}
|
|
30
|
+
function resolveWorkspacePath(inputPath, policy = getSandboxPolicy()) {
|
|
31
|
+
const candidate = path5.isAbsolute(inputPath) ? path5.resolve(inputPath) : path5.resolve(policy.workspaceRoot, inputPath);
|
|
32
|
+
if (policy.isSandbox && !isPathInsideWorkspace(candidate, policy)) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
`Path "${inputPath}" escapes the sandbox workspace root ${policy.workspaceRoot}`
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
return candidate;
|
|
38
|
+
}
|
|
39
|
+
function resolveCommandCwd(cwd, policy = getSandboxPolicy()) {
|
|
40
|
+
const base = cwd ? path5.resolve(cwd) : policy.workspaceRoot;
|
|
41
|
+
if (policy.isSandbox && !isPathInsideWorkspace(base, policy)) {
|
|
42
|
+
throw new Error(
|
|
43
|
+
`Command cwd "${base}" escapes the sandbox workspace root ${policy.workspaceRoot}`
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
return base;
|
|
47
|
+
}
|
|
48
|
+
function assessCommandSafety(command, policy = getSandboxPolicy()) {
|
|
49
|
+
const trimmed = String(command || "").trim();
|
|
50
|
+
if (!trimmed) {
|
|
51
|
+
return { allowed: false, risk: "blocked", reason: "Command is required." };
|
|
52
|
+
}
|
|
53
|
+
for (const entry of BLOCKED_COMMAND_PATTERNS) {
|
|
54
|
+
if (entry.pattern.test(trimmed)) {
|
|
55
|
+
return { allowed: false, risk: "blocked", reason: entry.reason };
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (HIGH_RISK_COMMAND_PATTERNS.some((pattern) => pattern.test(trimmed))) {
|
|
59
|
+
return {
|
|
60
|
+
allowed: true,
|
|
61
|
+
risk: policy.isSandbox ? "high" : "high",
|
|
62
|
+
reason: policy.isSandbox ? "High-risk command allowed inside the workspace sandbox." : "High-risk command requires explicit approval outside sandbox mode."
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
if (MODERATE_RISK_COMMAND_PATTERNS.some((pattern) => pattern.test(trimmed))) {
|
|
66
|
+
return {
|
|
67
|
+
allowed: true,
|
|
68
|
+
risk: "moderate",
|
|
69
|
+
reason: policy.isSandbox ? "Workspace mutation command allowed inside the sandbox." : "Workspace mutation command requires confirmation outside sandbox mode."
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
return { allowed: true, risk: "safe" };
|
|
73
|
+
}
|
|
74
|
+
var BLOCKED_COMMAND_PATTERNS, HIGH_RISK_COMMAND_PATTERNS, MODERATE_RISK_COMMAND_PATTERNS;
|
|
75
|
+
var init_sandbox_policy = __esm({
|
|
76
|
+
"src/app/agent/runtime/sandbox_policy.ts"() {
|
|
77
|
+
"use strict";
|
|
78
|
+
BLOCKED_COMMAND_PATTERNS = [
|
|
79
|
+
{ pattern: /^sudo\s+/i, reason: "Privilege escalation is not allowed." },
|
|
80
|
+
{ pattern: /^doas\s+/i, reason: "Privilege escalation is not allowed." },
|
|
81
|
+
{ pattern: /^su\s+/i, reason: "Privilege escalation is not allowed." },
|
|
82
|
+
{ pattern: /^pkexec\s+/i, reason: "Privilege escalation is not allowed." },
|
|
83
|
+
{ pattern: /\bmkfs\./i, reason: "Disk formatting commands are blocked." },
|
|
84
|
+
{ pattern: /\bdd\s+.*of=\/dev\/(sd|hd|nvme)/i, reason: "Raw disk writes are blocked." },
|
|
85
|
+
{ pattern: /\brm\s+(-[rf]+\s+)*\/($|\s)/i, reason: "Deleting filesystem roots is blocked." },
|
|
86
|
+
{ pattern: /\brm\s+-[rf]*\s+~($|\s)/i, reason: "Deleting home roots is blocked." },
|
|
87
|
+
{ pattern: /\bcurl\s+.*\|\s*(ba)?sh/i, reason: "Pipe-to-shell remote execution is blocked." },
|
|
88
|
+
{ pattern: /\bwget\s+.*\|\s*(ba)?sh/i, reason: "Pipe-to-shell remote execution is blocked." }
|
|
89
|
+
];
|
|
90
|
+
HIGH_RISK_COMMAND_PATTERNS = [
|
|
91
|
+
/\brm\s+-[rf]/i,
|
|
92
|
+
/\bmv\s+.+\s+\/(?!tmp\b)/i,
|
|
93
|
+
/\bchmod\b/i,
|
|
94
|
+
/\bchown\b/i,
|
|
95
|
+
/\bssh\b/i,
|
|
96
|
+
/\bscp\b/i,
|
|
97
|
+
/\brsync\b/i,
|
|
98
|
+
/\bdocker\b/i,
|
|
99
|
+
/\bkubectl\b/i
|
|
100
|
+
];
|
|
101
|
+
MODERATE_RISK_COMMAND_PATTERNS = [
|
|
102
|
+
/\bnpm\s+(install|update|uninstall)\b/i,
|
|
103
|
+
/\bpnpm\s+(add|install|update|remove)\b/i,
|
|
104
|
+
/\byarn\s+(add|install|remove)\b/i,
|
|
105
|
+
/\buv\s+(add|remove|sync)\b/i,
|
|
106
|
+
/\bpip\s+install\b/i,
|
|
107
|
+
/\bgit\s+(commit|push|rebase|reset|clean)\b/i
|
|
108
|
+
];
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
12
112
|
// src/app/agent/tools/natives/async_command.ts
|
|
13
113
|
var async_command_exports = {};
|
|
14
114
|
__export(async_command_exports, {
|
|
@@ -30,10 +130,10 @@ function cleanupOldCommands() {
|
|
|
30
130
|
}
|
|
31
131
|
function isDangerousCommand(command) {
|
|
32
132
|
const trimmed = command.trim();
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
133
|
+
const policy = getSandboxPolicy();
|
|
134
|
+
const assessment = assessCommandSafety(trimmed, policy);
|
|
135
|
+
if (!assessment.allowed) {
|
|
136
|
+
return assessment.reason || "Command blocked by sandbox policy";
|
|
37
137
|
}
|
|
38
138
|
for (const pattern of INTERACTIVE_PATTERNS) {
|
|
39
139
|
if (pattern.test(trimmed)) {
|
|
@@ -46,7 +146,7 @@ async function runCommandAsync(args) {
|
|
|
46
146
|
try {
|
|
47
147
|
const {
|
|
48
148
|
command,
|
|
49
|
-
cwd
|
|
149
|
+
cwd,
|
|
50
150
|
timeout = 0
|
|
51
151
|
} = args;
|
|
52
152
|
if (!command || typeof command !== "string") {
|
|
@@ -62,6 +162,8 @@ async function runCommandAsync(args) {
|
|
|
62
162
|
error: dangerReason
|
|
63
163
|
};
|
|
64
164
|
}
|
|
165
|
+
const policy = getSandboxPolicy();
|
|
166
|
+
const resolvedCwd = resolveCommandCwd(cwd, policy);
|
|
65
167
|
const commandId = uuidv42().substring(0, 8);
|
|
66
168
|
const platform = os5.platform();
|
|
67
169
|
let shellCmd;
|
|
@@ -84,7 +186,7 @@ async function runCommandAsync(args) {
|
|
|
84
186
|
process: null
|
|
85
187
|
};
|
|
86
188
|
const child = spawn2(shellCmd, shellArgs, {
|
|
87
|
-
cwd,
|
|
189
|
+
cwd: resolvedCwd,
|
|
88
190
|
env: process.env,
|
|
89
191
|
windowsHide: true
|
|
90
192
|
});
|
|
@@ -286,35 +388,15 @@ async function killCommand(args) {
|
|
|
286
388
|
};
|
|
287
389
|
}
|
|
288
390
|
}
|
|
289
|
-
var runningCommands, MAX_OUTPUT_SIZE, MAX_STORED_COMMANDS, OUTPUT_TRUNCATION_MSG,
|
|
391
|
+
var runningCommands, MAX_OUTPUT_SIZE, MAX_STORED_COMMANDS, OUTPUT_TRUNCATION_MSG, INTERACTIVE_PATTERNS;
|
|
290
392
|
var init_async_command = __esm({
|
|
291
393
|
"src/app/agent/tools/natives/async_command.ts"() {
|
|
292
394
|
"use strict";
|
|
395
|
+
init_sandbox_policy();
|
|
293
396
|
runningCommands = /* @__PURE__ */ new Map();
|
|
294
397
|
MAX_OUTPUT_SIZE = 3e4;
|
|
295
398
|
MAX_STORED_COMMANDS = 50;
|
|
296
399
|
OUTPUT_TRUNCATION_MSG = "\n[OUTPUT TRUNCATED - 30KB/200 lines max]";
|
|
297
|
-
DANGEROUS_PATTERNS = [
|
|
298
|
-
// Elevação de privilégios
|
|
299
|
-
/^sudo\s+/i,
|
|
300
|
-
/^doas\s+/i,
|
|
301
|
-
/^su\s+/i,
|
|
302
|
-
/^pkexec\s+/i,
|
|
303
|
-
/\|\s*sudo\s+/i,
|
|
304
|
-
/;\s*sudo\s+/i,
|
|
305
|
-
/&&\s*sudo\s+/i,
|
|
306
|
-
// Comandos destrutivos
|
|
307
|
-
/\brm\s+(-[rf]+\s+)*[\/~]/i,
|
|
308
|
-
/\brm\s+-[rf]*\s+\*/i,
|
|
309
|
-
/\bchmod\s+(777|666)\s+\//i,
|
|
310
|
-
/\bdd\s+.*of=\/dev\/(sd|hd|nvme)/i,
|
|
311
|
-
/\bmkfs\./i,
|
|
312
|
-
// Fork bombs
|
|
313
|
-
/:\(\)\s*\{\s*:\|:&\s*\}\s*;:/,
|
|
314
|
-
// Remote code exec
|
|
315
|
-
/\bcurl\s+.*\|\s*(ba)?sh/i,
|
|
316
|
-
/\bwget\s+.*\|\s*(ba)?sh/i
|
|
317
|
-
];
|
|
318
400
|
INTERACTIVE_PATTERNS = [
|
|
319
401
|
/^(vim|vi|nano|emacs|pico)\s*/i,
|
|
320
402
|
/^(less|more|most)\s*/i,
|
|
@@ -331,14 +413,15 @@ var init_async_command = __esm({
|
|
|
331
413
|
import React12 from "react";
|
|
332
414
|
import { render } from "ink";
|
|
333
415
|
import { EventEmitter as EventEmitter3 } from "events";
|
|
334
|
-
import
|
|
335
|
-
import
|
|
416
|
+
import fs21 from "fs";
|
|
417
|
+
import path26 from "path";
|
|
336
418
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
337
|
-
import {
|
|
419
|
+
import { spawn as spawn4 } from "child_process";
|
|
420
|
+
import { v4 as uuidv47 } from "uuid";
|
|
338
421
|
|
|
339
422
|
// src/app/ui/App.tsx
|
|
340
423
|
import { useState as useState6, useEffect as useEffect7, useRef as useRef5, useCallback as useCallback3, memo as memo12 } from "react";
|
|
341
|
-
import { Box as Box20, Text as
|
|
424
|
+
import { Box as Box20, Text as Text20, Static } from "ink";
|
|
342
425
|
|
|
343
426
|
// src/app/ui/layout.tsx
|
|
344
427
|
import { Box, Text, useStdout } from "ink";
|
|
@@ -391,7 +474,9 @@ var HeaderComponent = ({
|
|
|
391
474
|
sessionId,
|
|
392
475
|
workdir,
|
|
393
476
|
cliVersion = "?",
|
|
394
|
-
recentActivitySummary
|
|
477
|
+
recentActivitySummary,
|
|
478
|
+
activeTaskSummary,
|
|
479
|
+
taskProgressSummary
|
|
395
480
|
}) => {
|
|
396
481
|
const { stdout } = useStdout();
|
|
397
482
|
const cols = Math.max(52, stdout?.columns ?? 80);
|
|
@@ -466,6 +551,10 @@ var HeaderComponent = ({
|
|
|
466
551
|
"as needed."
|
|
467
552
|
] }),
|
|
468
553
|
/* @__PURE__ */ jsx(Box, { marginY: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500".repeat(ruleW) }) }),
|
|
554
|
+
/* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { bold: true, color: M, children: "Work in progress" }) }),
|
|
555
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, wrap: "wrap", children: activeTaskSummary?.trim() ? activeTaskSummary.trim() : "No active task." }),
|
|
556
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, wrap: "wrap", children: taskProgressSummary?.trim() ? taskProgressSummary.trim() : "No tracked todo items." }),
|
|
557
|
+
/* @__PURE__ */ jsx(Box, { marginY: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500".repeat(ruleW) }) }),
|
|
469
558
|
/* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { bold: true, color: M, children: "Recent activity" }) }),
|
|
470
559
|
/* @__PURE__ */ jsx(Text, { dimColor: true, wrap: "wrap", children: recentActivitySummary?.trim() ? recentActivitySummary.trim() : "No recent activity." })
|
|
471
560
|
] }),
|
|
@@ -1973,10 +2062,28 @@ import { Box as Box4, Text as Text4 } from "ink";
|
|
|
1973
2062
|
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1974
2063
|
var SimpleDiff = ({ text, maxHeight }) => {
|
|
1975
2064
|
const allLines = (text || "").split("\n").filter((line) => line !== "");
|
|
2065
|
+
const additions = allLines.filter((line) => line.startsWith("+") && !line.startsWith("+++")).length;
|
|
2066
|
+
const removals = allLines.filter((line) => line.startsWith("-") && !line.startsWith("---")).length;
|
|
2067
|
+
const hunks = allLines.filter((line) => line.startsWith("@@")).length;
|
|
1976
2068
|
const isTruncated = maxHeight > 0 && allLines.length > maxHeight;
|
|
1977
2069
|
const linesToRender = isTruncated ? allLines.slice(-maxHeight) : allLines;
|
|
1978
2070
|
const hiddenCount = allLines.length - linesToRender.length;
|
|
1979
2071
|
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", paddingX: 2, children: [
|
|
2072
|
+
/* @__PURE__ */ jsxs4(Box4, { marginBottom: 1, children: [
|
|
2073
|
+
/* @__PURE__ */ jsx4(Text4, { color: BLUMA_TERMINAL.brandMagenta, children: "diff" }),
|
|
2074
|
+
/* @__PURE__ */ jsxs4(Text4, { dimColor: true, children: [
|
|
2075
|
+
" \xB7 +",
|
|
2076
|
+
additions,
|
|
2077
|
+
" -",
|
|
2078
|
+
removals
|
|
2079
|
+
] }),
|
|
2080
|
+
hunks > 0 ? /* @__PURE__ */ jsxs4(Text4, { dimColor: true, children: [
|
|
2081
|
+
" \xB7 ",
|
|
2082
|
+
hunks,
|
|
2083
|
+
" hunk",
|
|
2084
|
+
hunks > 1 ? "s" : ""
|
|
2085
|
+
] }) : null
|
|
2086
|
+
] }),
|
|
1980
2087
|
isTruncated && /* @__PURE__ */ jsx4(Box4, { marginBottom: 0, children: /* @__PURE__ */ jsxs4(Text4, { dimColor: true, children: [
|
|
1981
2088
|
"\u22EF ",
|
|
1982
2089
|
hiddenCount,
|
|
@@ -1984,26 +2091,26 @@ var SimpleDiff = ({ text, maxHeight }) => {
|
|
|
1984
2091
|
] }) }),
|
|
1985
2092
|
linesToRender.map((line, index) => {
|
|
1986
2093
|
if (line.startsWith("---") || line.startsWith("+++")) {
|
|
1987
|
-
return
|
|
2094
|
+
return /* @__PURE__ */ jsx4(Box4, { children: /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: line }) }, index);
|
|
1988
2095
|
}
|
|
1989
2096
|
let color = "white";
|
|
1990
2097
|
let prefix = "";
|
|
1991
2098
|
if (line.startsWith("+")) {
|
|
1992
|
-
color =
|
|
2099
|
+
color = BLUMA_TERMINAL.success;
|
|
1993
2100
|
prefix = "+ ";
|
|
1994
2101
|
} else if (line.startsWith("-")) {
|
|
1995
|
-
color =
|
|
2102
|
+
color = BLUMA_TERMINAL.err;
|
|
1996
2103
|
prefix = "- ";
|
|
1997
2104
|
} else if (line.startsWith("@@")) {
|
|
1998
|
-
color =
|
|
1999
|
-
prefix = "";
|
|
2105
|
+
color = BLUMA_TERMINAL.brandBlue;
|
|
2106
|
+
prefix = "@ ";
|
|
2000
2107
|
} else {
|
|
2001
|
-
color =
|
|
2108
|
+
color = BLUMA_TERMINAL.muted;
|
|
2002
2109
|
prefix = " ";
|
|
2003
2110
|
}
|
|
2004
2111
|
return /* @__PURE__ */ jsx4(Box4, { children: /* @__PURE__ */ jsxs4(Text4, { color, children: [
|
|
2005
2112
|
prefix,
|
|
2006
|
-
line.replace(/^[
|
|
2113
|
+
line.replace(/^[@+\-]\s?/, "")
|
|
2007
2114
|
] }) }, index);
|
|
2008
2115
|
})
|
|
2009
2116
|
] });
|
|
@@ -2317,16 +2424,17 @@ var ConfirmationPrompt = memo4(ConfirmationPromptComponent);
|
|
|
2317
2424
|
|
|
2318
2425
|
// src/app/agent/agent.ts
|
|
2319
2426
|
import * as dotenv from "dotenv";
|
|
2320
|
-
import
|
|
2321
|
-
import
|
|
2427
|
+
import path24 from "path";
|
|
2428
|
+
import os16 from "os";
|
|
2322
2429
|
|
|
2323
2430
|
// src/app/agent/tool_invoker.ts
|
|
2324
|
-
import { promises as
|
|
2325
|
-
import
|
|
2431
|
+
import { promises as fs14 } from "fs";
|
|
2432
|
+
import path17 from "path";
|
|
2326
2433
|
import { fileURLToPath } from "url";
|
|
2327
2434
|
|
|
2328
2435
|
// src/app/agent/tools/natives/edit.ts
|
|
2329
|
-
|
|
2436
|
+
init_sandbox_policy();
|
|
2437
|
+
import path6 from "path";
|
|
2330
2438
|
import os4 from "os";
|
|
2331
2439
|
import { promises as fs4 } from "fs";
|
|
2332
2440
|
import { diffLines } from "diff";
|
|
@@ -2345,7 +2453,7 @@ function normalizePath(filePath) {
|
|
|
2345
2453
|
}
|
|
2346
2454
|
filePath = filePath.replace(/\//g, "\\");
|
|
2347
2455
|
}
|
|
2348
|
-
return
|
|
2456
|
+
return path6.normalize(resolveWorkspacePath(filePath));
|
|
2349
2457
|
} catch (e) {
|
|
2350
2458
|
throw new Error(`Failed to normalize path "${filePath}": ${e.message}`);
|
|
2351
2459
|
}
|
|
@@ -2606,7 +2714,7 @@ async function editTool(args) {
|
|
|
2606
2714
|
};
|
|
2607
2715
|
}
|
|
2608
2716
|
const cwd = process.cwd();
|
|
2609
|
-
if (!normalizedFilePath.startsWith(cwd) && !
|
|
2717
|
+
if (!normalizedFilePath.startsWith(cwd) && !path6.isAbsolute(file_path)) {
|
|
2610
2718
|
return {
|
|
2611
2719
|
success: false,
|
|
2612
2720
|
error: `Invalid parameters: file_path must be within the current working directory or be an absolute path.`,
|
|
@@ -2627,11 +2735,11 @@ async function editTool(args) {
|
|
|
2627
2735
|
file_path: normalizedFilePath
|
|
2628
2736
|
};
|
|
2629
2737
|
}
|
|
2630
|
-
const dirPath =
|
|
2738
|
+
const dirPath = path6.dirname(normalizedFilePath);
|
|
2631
2739
|
await fs4.mkdir(dirPath, { recursive: true });
|
|
2632
2740
|
await fs4.writeFile(normalizedFilePath, editData.newContent, "utf-8");
|
|
2633
|
-
const relativePath =
|
|
2634
|
-
const filename =
|
|
2741
|
+
const relativePath = path6.relative(process.cwd(), normalizedFilePath);
|
|
2742
|
+
const filename = path6.basename(normalizedFilePath);
|
|
2635
2743
|
if (editData.isNewFile) {
|
|
2636
2744
|
return {
|
|
2637
2745
|
success: true,
|
|
@@ -2686,7 +2794,7 @@ function message(args) {
|
|
|
2686
2794
|
|
|
2687
2795
|
// src/app/agent/tools/natives/ls.ts
|
|
2688
2796
|
import { promises as fs5 } from "fs";
|
|
2689
|
-
import
|
|
2797
|
+
import path7 from "path";
|
|
2690
2798
|
var DEFAULT_IGNORE = /* @__PURE__ */ new Set([
|
|
2691
2799
|
".git",
|
|
2692
2800
|
".gitignore",
|
|
@@ -2714,7 +2822,7 @@ async function ls(args) {
|
|
|
2714
2822
|
max_depth
|
|
2715
2823
|
} = args;
|
|
2716
2824
|
try {
|
|
2717
|
-
const basePath =
|
|
2825
|
+
const basePath = path7.resolve(directory_path);
|
|
2718
2826
|
if (!(await fs5.stat(basePath)).isDirectory()) {
|
|
2719
2827
|
throw new Error(`Directory '${directory_path}' not found.`);
|
|
2720
2828
|
}
|
|
@@ -2727,8 +2835,8 @@ async function ls(args) {
|
|
|
2727
2835
|
const entries = await fs5.readdir(currentDir, { withFileTypes: true });
|
|
2728
2836
|
for (const entry of entries) {
|
|
2729
2837
|
const entryName = entry.name;
|
|
2730
|
-
const fullPath =
|
|
2731
|
-
const posixPath = fullPath.split(
|
|
2838
|
+
const fullPath = path7.join(currentDir, entryName);
|
|
2839
|
+
const posixPath = fullPath.split(path7.sep).join("/");
|
|
2732
2840
|
const isHidden = entryName.startsWith(".");
|
|
2733
2841
|
if (allIgnorePatterns.has(entryName) || isHidden && !show_hidden) {
|
|
2734
2842
|
continue;
|
|
@@ -2739,7 +2847,7 @@ async function ls(args) {
|
|
|
2739
2847
|
await walk(fullPath, currentDepth + 1);
|
|
2740
2848
|
}
|
|
2741
2849
|
} else if (entry.isFile()) {
|
|
2742
|
-
if (!normalizedExtensions || normalizedExtensions.includes(
|
|
2850
|
+
if (!normalizedExtensions || normalizedExtensions.includes(path7.extname(entryName).toLowerCase())) {
|
|
2743
2851
|
allFiles.push(posixPath);
|
|
2744
2852
|
}
|
|
2745
2853
|
}
|
|
@@ -2750,7 +2858,7 @@ async function ls(args) {
|
|
|
2750
2858
|
allDirs.sort();
|
|
2751
2859
|
return {
|
|
2752
2860
|
success: true,
|
|
2753
|
-
path: basePath.split(
|
|
2861
|
+
path: basePath.split(path7.sep).join("/"),
|
|
2754
2862
|
recursive,
|
|
2755
2863
|
total_files: allFiles.length,
|
|
2756
2864
|
total_directories: allDirs.length,
|
|
@@ -2766,17 +2874,19 @@ async function ls(args) {
|
|
|
2766
2874
|
}
|
|
2767
2875
|
|
|
2768
2876
|
// src/app/agent/tools/natives/readLines.ts
|
|
2877
|
+
init_sandbox_policy();
|
|
2769
2878
|
import { promises as fs6 } from "fs";
|
|
2770
2879
|
async function readLines(args) {
|
|
2771
2880
|
const { filepath, start_line, end_line } = args;
|
|
2772
2881
|
try {
|
|
2773
|
-
|
|
2882
|
+
const resolvedPath = resolveWorkspacePath(filepath);
|
|
2883
|
+
if (!(await fs6.stat(resolvedPath)).isFile()) {
|
|
2774
2884
|
throw new Error(`File '${filepath}' not found or is not a file.`);
|
|
2775
2885
|
}
|
|
2776
2886
|
if (start_line < 1 || end_line < start_line) {
|
|
2777
2887
|
throw new Error("Invalid line range. start_line must be >= 1 and end_line must be >= start_line.");
|
|
2778
2888
|
}
|
|
2779
|
-
const fileContent = await fs6.readFile(
|
|
2889
|
+
const fileContent = await fs6.readFile(resolvedPath, "utf-8");
|
|
2780
2890
|
const lines = fileContent.split("\n");
|
|
2781
2891
|
const total_lines = lines.length;
|
|
2782
2892
|
const startIndex = start_line - 1;
|
|
@@ -2789,7 +2899,7 @@ async function readLines(args) {
|
|
|
2789
2899
|
const content = contentLines.join("\n");
|
|
2790
2900
|
return {
|
|
2791
2901
|
success: true,
|
|
2792
|
-
filepath,
|
|
2902
|
+
filepath: resolvedPath,
|
|
2793
2903
|
content,
|
|
2794
2904
|
lines_read: contentLines.length,
|
|
2795
2905
|
start_line,
|
|
@@ -2827,178 +2937,209 @@ async function countLines(args) {
|
|
|
2827
2937
|
}
|
|
2828
2938
|
}
|
|
2829
2939
|
|
|
2830
|
-
// src/app/agent/
|
|
2831
|
-
|
|
2832
|
-
import
|
|
2833
|
-
|
|
2834
|
-
var
|
|
2835
|
-
function
|
|
2836
|
-
|
|
2940
|
+
// src/app/agent/runtime/task_store.ts
|
|
2941
|
+
init_sandbox_policy();
|
|
2942
|
+
import fs8 from "fs";
|
|
2943
|
+
import path8 from "path";
|
|
2944
|
+
var cache = null;
|
|
2945
|
+
function getStorePath() {
|
|
2946
|
+
const policy = getSandboxPolicy();
|
|
2947
|
+
return path8.join(policy.workspaceRoot, ".bluma", "task_state.json");
|
|
2837
2948
|
}
|
|
2838
|
-
function
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
taskStore = parsed.tasks;
|
|
2846
|
-
nextId = parsed.nextId || taskStore.length + 1;
|
|
2847
|
-
}
|
|
2848
|
-
}
|
|
2849
|
-
} catch {
|
|
2850
|
-
}
|
|
2949
|
+
function getDefaultState() {
|
|
2950
|
+
return {
|
|
2951
|
+
tasks: [],
|
|
2952
|
+
nextId: 1,
|
|
2953
|
+
activeTask: null,
|
|
2954
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2955
|
+
};
|
|
2851
2956
|
}
|
|
2852
|
-
function
|
|
2957
|
+
function ensureLoaded() {
|
|
2958
|
+
if (cache) {
|
|
2959
|
+
return cache;
|
|
2960
|
+
}
|
|
2961
|
+
const storePath = getStorePath();
|
|
2853
2962
|
try {
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2963
|
+
if (fs8.existsSync(storePath)) {
|
|
2964
|
+
const raw = fs8.readFileSync(storePath, "utf-8");
|
|
2965
|
+
const parsed = JSON.parse(raw);
|
|
2966
|
+
cache = {
|
|
2967
|
+
tasks: Array.isArray(parsed.tasks) ? parsed.tasks : [],
|
|
2968
|
+
nextId: typeof parsed.nextId === "number" ? parsed.nextId : 1,
|
|
2969
|
+
activeTask: parsed.activeTask ?? null,
|
|
2970
|
+
updatedAt: typeof parsed.updatedAt === "string" ? parsed.updatedAt : (/* @__PURE__ */ new Date()).toISOString()
|
|
2971
|
+
};
|
|
2972
|
+
return cache;
|
|
2858
2973
|
}
|
|
2859
|
-
fs8.writeFileSync(filePath, JSON.stringify({
|
|
2860
|
-
tasks: taskStore,
|
|
2861
|
-
nextId,
|
|
2862
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2863
|
-
}, null, 2));
|
|
2864
2974
|
} catch {
|
|
2865
2975
|
}
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
const
|
|
2871
|
-
|
|
2976
|
+
cache = getDefaultState();
|
|
2977
|
+
return cache;
|
|
2978
|
+
}
|
|
2979
|
+
function persist(state) {
|
|
2980
|
+
const storePath = getStorePath();
|
|
2981
|
+
fs8.mkdirSync(path8.dirname(storePath), { recursive: true });
|
|
2982
|
+
state.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2983
|
+
fs8.writeFileSync(storePath, JSON.stringify(state, null, 2), "utf-8");
|
|
2984
|
+
cache = state;
|
|
2985
|
+
}
|
|
2986
|
+
function updateTaskStore(mutator) {
|
|
2987
|
+
const current = ensureLoaded();
|
|
2988
|
+
const clone = {
|
|
2989
|
+
tasks: current.tasks.map((task) => ({ ...task })),
|
|
2990
|
+
nextId: current.nextId,
|
|
2991
|
+
activeTask: current.activeTask ? { ...current.activeTask } : null,
|
|
2992
|
+
updatedAt: current.updatedAt
|
|
2993
|
+
};
|
|
2994
|
+
mutator(clone);
|
|
2995
|
+
persist(clone);
|
|
2996
|
+
return clone;
|
|
2997
|
+
}
|
|
2998
|
+
function calculateTaskStats(tasks) {
|
|
2999
|
+
const total = tasks.length;
|
|
3000
|
+
const pending = tasks.filter((t) => t.status === "pending").length;
|
|
3001
|
+
const inProgress = tasks.filter((t) => t.status === "in_progress").length;
|
|
3002
|
+
const completed = tasks.filter((t) => t.status === "completed").length;
|
|
2872
3003
|
const progress = total > 0 ? Math.round(completed / total * 100) : 0;
|
|
2873
3004
|
return { total, pending, inProgress, completed, progress };
|
|
2874
3005
|
}
|
|
3006
|
+
function buildTaskSnapshot() {
|
|
3007
|
+
const state = ensureLoaded();
|
|
3008
|
+
return {
|
|
3009
|
+
tasks: state.tasks.map((task) => ({ ...task })),
|
|
3010
|
+
activeTask: state.activeTask ? { ...state.activeTask } : null,
|
|
3011
|
+
stats: calculateTaskStats(state.tasks),
|
|
3012
|
+
updatedAt: state.updatedAt
|
|
3013
|
+
};
|
|
3014
|
+
}
|
|
3015
|
+
|
|
3016
|
+
// src/app/agent/tools/natives/todo.ts
|
|
2875
3017
|
function validateDescription(desc) {
|
|
2876
|
-
if (!desc || typeof desc !== "string")
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
if (desc.trim().length === 0) {
|
|
2880
|
-
return "Description cannot be empty";
|
|
2881
|
-
}
|
|
2882
|
-
if (desc.length > 500) {
|
|
2883
|
-
return "Description too long (max 500 chars)";
|
|
2884
|
-
}
|
|
3018
|
+
if (!desc || typeof desc !== "string") return "Description is required";
|
|
3019
|
+
if (desc.trim().length === 0) return "Description cannot be empty";
|
|
3020
|
+
if (desc.length > 500) return "Description too long (max 500 chars)";
|
|
2885
3021
|
return null;
|
|
2886
3022
|
}
|
|
3023
|
+
function generateProgressBar(percent) {
|
|
3024
|
+
const width = 10;
|
|
3025
|
+
const filled = Math.round(percent / 100 * width);
|
|
3026
|
+
return "[" + "=".repeat(filled) + " ".repeat(width - filled) + "]";
|
|
3027
|
+
}
|
|
2887
3028
|
function createResult(success, message2) {
|
|
3029
|
+
const snapshot = buildTaskSnapshot();
|
|
2888
3030
|
return {
|
|
2889
3031
|
success,
|
|
2890
3032
|
message: message2,
|
|
2891
|
-
tasks:
|
|
2892
|
-
|
|
3033
|
+
tasks: snapshot.tasks,
|
|
3034
|
+
activeTask: snapshot.activeTask,
|
|
3035
|
+
stats: snapshot.stats
|
|
2893
3036
|
};
|
|
2894
3037
|
}
|
|
2895
|
-
function
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
3038
|
+
function syncTasks(tasks) {
|
|
3039
|
+
updateTaskStore((state) => {
|
|
3040
|
+
state.tasks = [];
|
|
3041
|
+
state.nextId = 1;
|
|
3042
|
+
for (const task of tasks || []) {
|
|
3043
|
+
state.tasks.push({
|
|
3044
|
+
id: state.nextId++,
|
|
3045
|
+
description: task.description,
|
|
3046
|
+
status: task.isComplete ? "completed" : "pending",
|
|
3047
|
+
priority: task.priority || "medium",
|
|
3048
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3049
|
+
completedAt: task.isComplete ? (/* @__PURE__ */ new Date()).toISOString() : void 0
|
|
3050
|
+
});
|
|
3051
|
+
}
|
|
3052
|
+
});
|
|
3053
|
+
const snapshot = buildTaskSnapshot();
|
|
3054
|
+
const progressBar = generateProgressBar(snapshot.stats.progress);
|
|
3055
|
+
return createResult(
|
|
3056
|
+
true,
|
|
3057
|
+
`Synced ${snapshot.tasks.length} tasks ${progressBar} ${snapshot.stats.progress}%`
|
|
3058
|
+
);
|
|
2903
3059
|
}
|
|
2904
3060
|
function addTasks(tasks) {
|
|
2905
3061
|
if (!tasks || tasks.length === 0) {
|
|
2906
3062
|
return createResult(false, "No tasks provided");
|
|
2907
3063
|
}
|
|
2908
|
-
loadTasksFromFile();
|
|
2909
3064
|
for (const task of tasks) {
|
|
2910
3065
|
const error = validateDescription(task.description);
|
|
2911
|
-
if (error) {
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
const
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
3066
|
+
if (error) return createResult(false, `Invalid task: ${error}`);
|
|
3067
|
+
}
|
|
3068
|
+
updateTaskStore((state) => {
|
|
3069
|
+
for (const task of tasks) {
|
|
3070
|
+
state.tasks.push({
|
|
3071
|
+
id: state.nextId++,
|
|
3072
|
+
description: task.description.trim(),
|
|
3073
|
+
status: task.isComplete ? "completed" : "pending",
|
|
3074
|
+
priority: task.priority || "medium",
|
|
3075
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3076
|
+
completedAt: task.isComplete ? (/* @__PURE__ */ new Date()).toISOString() : void 0
|
|
3077
|
+
});
|
|
3078
|
+
}
|
|
3079
|
+
});
|
|
2925
3080
|
return createResult(true, `Added ${tasks.length} task(s)`);
|
|
2926
3081
|
}
|
|
2927
3082
|
function completeTask(taskId) {
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
3083
|
+
let found = false;
|
|
3084
|
+
let description = "";
|
|
3085
|
+
updateTaskStore((state) => {
|
|
3086
|
+
const task = state.tasks.find((item) => item.id === taskId);
|
|
3087
|
+
if (!task) return;
|
|
3088
|
+
found = true;
|
|
3089
|
+
description = task.description;
|
|
3090
|
+
task.status = "completed";
|
|
3091
|
+
task.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3092
|
+
});
|
|
3093
|
+
return found ? createResult(true, `Completed: ${description}`) : createResult(false, `Task #${taskId} not found`);
|
|
2937
3094
|
}
|
|
2938
3095
|
function updateTask(taskId, description, priority) {
|
|
2939
|
-
loadTasksFromFile();
|
|
2940
|
-
const task = taskStore.find((t) => t.id === taskId);
|
|
2941
|
-
if (!task) {
|
|
2942
|
-
return createResult(false, `Task #${taskId} not found`);
|
|
2943
|
-
}
|
|
2944
3096
|
if (description) {
|
|
2945
3097
|
const error = validateDescription(description);
|
|
2946
|
-
if (error)
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
3098
|
+
if (error) return createResult(false, error);
|
|
3099
|
+
}
|
|
3100
|
+
let found = false;
|
|
3101
|
+
updateTaskStore((state) => {
|
|
3102
|
+
const task = state.tasks.find((item) => item.id === taskId);
|
|
3103
|
+
if (!task) return;
|
|
3104
|
+
found = true;
|
|
3105
|
+
if (description) task.description = description.trim();
|
|
3106
|
+
if (priority) task.priority = priority;
|
|
3107
|
+
});
|
|
3108
|
+
return found ? createResult(true, `Updated task #${taskId}`) : createResult(false, `Task #${taskId} not found`);
|
|
2956
3109
|
}
|
|
2957
3110
|
function removeTask(taskId) {
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
return createResult(true, `Removed: ${
|
|
3111
|
+
let removedDescription = "";
|
|
3112
|
+
updateTaskStore((state) => {
|
|
3113
|
+
const index = state.tasks.findIndex((item) => item.id === taskId);
|
|
3114
|
+
if (index === -1) return;
|
|
3115
|
+
removedDescription = state.tasks[index].description;
|
|
3116
|
+
state.tasks.splice(index, 1);
|
|
3117
|
+
});
|
|
3118
|
+
return removedDescription ? createResult(true, `Removed: ${removedDescription}`) : createResult(false, `Task #${taskId} not found`);
|
|
2966
3119
|
}
|
|
2967
3120
|
function clearCompleted() {
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
3121
|
+
let removed = 0;
|
|
3122
|
+
updateTaskStore((state) => {
|
|
3123
|
+
const before = state.tasks.length;
|
|
3124
|
+
state.tasks = state.tasks.filter((task) => task.status !== "completed");
|
|
3125
|
+
removed = before - state.tasks.length;
|
|
3126
|
+
});
|
|
2973
3127
|
return createResult(true, `Cleared ${removed} completed task(s)`);
|
|
2974
3128
|
}
|
|
2975
|
-
function
|
|
2976
|
-
const
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
3129
|
+
function listTasks() {
|
|
3130
|
+
const snapshot = buildTaskSnapshot();
|
|
3131
|
+
if (snapshot.tasks.length === 0) {
|
|
3132
|
+
return createResult(true, "No tasks yet. Use add action to create tasks.");
|
|
3133
|
+
}
|
|
3134
|
+
const progressBar = generateProgressBar(snapshot.stats.progress);
|
|
3135
|
+
return createResult(
|
|
3136
|
+
true,
|
|
3137
|
+
`${snapshot.stats.total} tasks ${progressBar} ${snapshot.stats.progress}%`
|
|
3138
|
+
);
|
|
2980
3139
|
}
|
|
2981
3140
|
async function todo(args) {
|
|
2982
3141
|
if ("tasks" in args && !("action" in args)) {
|
|
2983
|
-
|
|
2984
|
-
taskStore = [];
|
|
2985
|
-
nextId = 1;
|
|
2986
|
-
if (args.tasks && args.tasks.length > 0) {
|
|
2987
|
-
for (const task of args.tasks) {
|
|
2988
|
-
taskStore.push({
|
|
2989
|
-
id: nextId++,
|
|
2990
|
-
description: task.description,
|
|
2991
|
-
status: task.isComplete ? "completed" : "pending",
|
|
2992
|
-
priority: "medium",
|
|
2993
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2994
|
-
completedAt: task.isComplete ? (/* @__PURE__ */ new Date()).toISOString() : void 0
|
|
2995
|
-
});
|
|
2996
|
-
}
|
|
2997
|
-
}
|
|
2998
|
-
saveTasksToFile();
|
|
2999
|
-
const stats = calculateStats();
|
|
3000
|
-
const progressBar = generateProgressBar(stats.progress);
|
|
3001
|
-
return createResult(true, `Synced ${taskStore.length} tasks ${progressBar} ${stats.progress}%`);
|
|
3142
|
+
return syncTasks(args.tasks);
|
|
3002
3143
|
}
|
|
3003
3144
|
const fullArgs = args;
|
|
3004
3145
|
switch (fullArgs.action) {
|
|
@@ -3007,31 +3148,22 @@ async function todo(args) {
|
|
|
3007
3148
|
case "add":
|
|
3008
3149
|
return addTasks(fullArgs.tasks);
|
|
3009
3150
|
case "complete":
|
|
3010
|
-
|
|
3011
|
-
return createResult(false, "taskId required for complete action");
|
|
3012
|
-
}
|
|
3013
|
-
return completeTask(fullArgs.taskId);
|
|
3151
|
+
return fullArgs.taskId ? completeTask(fullArgs.taskId) : createResult(false, "taskId required for complete action");
|
|
3014
3152
|
case "update":
|
|
3015
|
-
|
|
3016
|
-
return createResult(false, "taskId required for update action");
|
|
3017
|
-
}
|
|
3018
|
-
return updateTask(fullArgs.taskId, fullArgs.description, fullArgs.priority);
|
|
3153
|
+
return fullArgs.taskId ? updateTask(fullArgs.taskId, fullArgs.description, fullArgs.priority) : createResult(false, "taskId required for update action");
|
|
3019
3154
|
case "remove":
|
|
3020
|
-
|
|
3021
|
-
return createResult(false, "taskId required for remove action");
|
|
3022
|
-
}
|
|
3023
|
-
return removeTask(fullArgs.taskId);
|
|
3155
|
+
return fullArgs.taskId ? removeTask(fullArgs.taskId) : createResult(false, "taskId required for remove action");
|
|
3024
3156
|
case "clear":
|
|
3025
3157
|
return clearCompleted();
|
|
3026
3158
|
case "sync":
|
|
3027
|
-
return
|
|
3159
|
+
return syncTasks(fullArgs.tasks);
|
|
3028
3160
|
default:
|
|
3029
3161
|
return createResult(false, `Unknown action: ${fullArgs.action}`);
|
|
3030
3162
|
}
|
|
3031
3163
|
}
|
|
3032
3164
|
|
|
3033
3165
|
// src/app/agent/tools/natives/find_by_name.ts
|
|
3034
|
-
import
|
|
3166
|
+
import path9 from "path";
|
|
3035
3167
|
import { promises as fsPromises } from "fs";
|
|
3036
3168
|
var DEFAULT_IGNORE_PATTERNS = [
|
|
3037
3169
|
"node_modules",
|
|
@@ -3071,7 +3203,7 @@ function shouldIgnore(name, ignorePatterns, includeHidden) {
|
|
|
3071
3203
|
}
|
|
3072
3204
|
function matchesExtensions(filename, extensions) {
|
|
3073
3205
|
if (!extensions || extensions.length === 0) return true;
|
|
3074
|
-
const ext =
|
|
3206
|
+
const ext = path9.extname(filename).toLowerCase();
|
|
3075
3207
|
return extensions.some((e) => {
|
|
3076
3208
|
const normalizedExt = e.startsWith(".") ? e.toLowerCase() : `.${e.toLowerCase()}`;
|
|
3077
3209
|
return ext === normalizedExt;
|
|
@@ -3093,8 +3225,8 @@ async function searchDirectory(dir, pattern, baseDir, options, results) {
|
|
|
3093
3225
|
if (shouldIgnore(name, options.ignorePatterns, options.includeHidden)) {
|
|
3094
3226
|
continue;
|
|
3095
3227
|
}
|
|
3096
|
-
const fullPath =
|
|
3097
|
-
const relativePath =
|
|
3228
|
+
const fullPath = path9.join(dir, name);
|
|
3229
|
+
const relativePath = path9.relative(baseDir, fullPath);
|
|
3098
3230
|
if (entry.isDirectory()) {
|
|
3099
3231
|
if (pattern.test(name)) {
|
|
3100
3232
|
results.push({
|
|
@@ -3150,7 +3282,7 @@ async function findByName(args) {
|
|
|
3150
3282
|
error: "Pattern is required and must be a string"
|
|
3151
3283
|
};
|
|
3152
3284
|
}
|
|
3153
|
-
const resolvedDir =
|
|
3285
|
+
const resolvedDir = path9.resolve(directory);
|
|
3154
3286
|
try {
|
|
3155
3287
|
const stats = await fsPromises.stat(resolvedDir);
|
|
3156
3288
|
if (!stats.isDirectory()) {
|
|
@@ -3211,7 +3343,7 @@ async function findByName(args) {
|
|
|
3211
3343
|
}
|
|
3212
3344
|
|
|
3213
3345
|
// src/app/agent/tools/natives/grep_search.ts
|
|
3214
|
-
import
|
|
3346
|
+
import path10 from "path";
|
|
3215
3347
|
import { promises as fsPromises2 } from "fs";
|
|
3216
3348
|
var MAX_RESULTS3 = 100;
|
|
3217
3349
|
var MAX_FILE_SIZE2 = 1024 * 1024;
|
|
@@ -3294,8 +3426,8 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
3294
3426
|
"Rakefile"
|
|
3295
3427
|
]);
|
|
3296
3428
|
function isTextFile(filepath) {
|
|
3297
|
-
const ext =
|
|
3298
|
-
const basename =
|
|
3429
|
+
const ext = path10.extname(filepath).toLowerCase();
|
|
3430
|
+
const basename = path10.basename(filepath);
|
|
3299
3431
|
if (TEXT_EXTENSIONS.has(ext)) return true;
|
|
3300
3432
|
if (TEXT_EXTENSIONS.has(basename)) return true;
|
|
3301
3433
|
if (basename.startsWith(".") && !ext) return true;
|
|
@@ -3340,7 +3472,7 @@ async function searchFile(filepath, baseDir, pattern, contextLines, matches, max
|
|
|
3340
3472
|
if (stats.size > MAX_FILE_SIZE2) return 0;
|
|
3341
3473
|
const content = await fsPromises2.readFile(filepath, "utf-8");
|
|
3342
3474
|
const lines = content.split("\n");
|
|
3343
|
-
const relativePath =
|
|
3475
|
+
const relativePath = path10.relative(baseDir, filepath);
|
|
3344
3476
|
for (let i = 0; i < lines.length && matches.length < maxResults; i++) {
|
|
3345
3477
|
const line = lines[i];
|
|
3346
3478
|
pattern.lastIndex = 0;
|
|
@@ -3380,7 +3512,7 @@ async function searchDirectory2(dir, baseDir, pattern, includePatterns, contextL
|
|
|
3380
3512
|
if (matches.length >= maxResults) break;
|
|
3381
3513
|
const name = entry.name;
|
|
3382
3514
|
if (shouldIgnore2(name)) continue;
|
|
3383
|
-
const fullPath =
|
|
3515
|
+
const fullPath = path10.join(dir, name);
|
|
3384
3516
|
if (entry.isDirectory()) {
|
|
3385
3517
|
await searchDirectory2(fullPath, baseDir, pattern, includePatterns, contextLines, matches, maxResults, stats);
|
|
3386
3518
|
} else if (entry.isFile()) {
|
|
@@ -3429,7 +3561,7 @@ async function grepSearch(args) {
|
|
|
3429
3561
|
error: "Search path is required"
|
|
3430
3562
|
};
|
|
3431
3563
|
}
|
|
3432
|
-
const resolvedPath =
|
|
3564
|
+
const resolvedPath = path10.resolve(searchPath);
|
|
3433
3565
|
let stats;
|
|
3434
3566
|
try {
|
|
3435
3567
|
stats = await fsPromises2.stat(resolvedPath);
|
|
@@ -3477,7 +3609,7 @@ async function grepSearch(args) {
|
|
|
3477
3609
|
);
|
|
3478
3610
|
} else if (stats.isFile()) {
|
|
3479
3611
|
searchStats.filesSearched = 1;
|
|
3480
|
-
const found = await searchFile(resolvedPath,
|
|
3612
|
+
const found = await searchFile(resolvedPath, path10.dirname(resolvedPath), pattern, context_lines, matches, max_results);
|
|
3481
3613
|
if (found > 0) searchStats.filesWithMatches = 1;
|
|
3482
3614
|
}
|
|
3483
3615
|
return {
|
|
@@ -3506,7 +3638,7 @@ async function grepSearch(args) {
|
|
|
3506
3638
|
}
|
|
3507
3639
|
|
|
3508
3640
|
// src/app/agent/tools/natives/view_file_outline.ts
|
|
3509
|
-
import
|
|
3641
|
+
import path11 from "path";
|
|
3510
3642
|
import { promises as fsPromises3 } from "fs";
|
|
3511
3643
|
var LANGUAGE_MAP = {
|
|
3512
3644
|
".ts": "typescript",
|
|
@@ -3620,7 +3752,7 @@ var PATTERNS = {
|
|
|
3620
3752
|
]
|
|
3621
3753
|
};
|
|
3622
3754
|
function detectLanguage(filepath) {
|
|
3623
|
-
const ext =
|
|
3755
|
+
const ext = path11.extname(filepath).toLowerCase();
|
|
3624
3756
|
return LANGUAGE_MAP[ext] || "unknown";
|
|
3625
3757
|
}
|
|
3626
3758
|
function determineItemType(line, language) {
|
|
@@ -3716,7 +3848,7 @@ async function viewFileOutline(args) {
|
|
|
3716
3848
|
error: "file_path is required and must be a string"
|
|
3717
3849
|
};
|
|
3718
3850
|
}
|
|
3719
|
-
const resolvedPath =
|
|
3851
|
+
const resolvedPath = path11.resolve(file_path);
|
|
3720
3852
|
let content;
|
|
3721
3853
|
try {
|
|
3722
3854
|
content = await fsPromises3.readFile(resolvedPath, "utf-8");
|
|
@@ -3756,27 +3888,28 @@ async function viewFileOutline(args) {
|
|
|
3756
3888
|
}
|
|
3757
3889
|
}
|
|
3758
3890
|
|
|
3759
|
-
// src/app/agent/
|
|
3891
|
+
// src/app/agent/runtime/native_tool_catalog.ts
|
|
3760
3892
|
init_async_command();
|
|
3761
3893
|
|
|
3762
3894
|
// src/app/agent/tools/natives/task_boundary.ts
|
|
3763
|
-
|
|
3895
|
+
init_sandbox_policy();
|
|
3896
|
+
import path12 from "path";
|
|
3764
3897
|
import { promises as fs9 } from "fs";
|
|
3765
3898
|
import os6 from "os";
|
|
3766
|
-
var currentTask = null;
|
|
3767
3899
|
var artifactsDir = null;
|
|
3768
3900
|
async function getArtifactsDir() {
|
|
3769
3901
|
if (artifactsDir) return artifactsDir;
|
|
3902
|
+
const policy = getSandboxPolicy();
|
|
3770
3903
|
const homeDir = os6.homedir();
|
|
3771
|
-
const baseDir =
|
|
3904
|
+
const baseDir = policy.isSandbox ? path12.join(policy.workspaceRoot, "artifacts") : path12.join(homeDir, ".bluma", "artifacts");
|
|
3772
3905
|
const sessionId = Date.now().toString(36) + Math.random().toString(36).substr(2, 5);
|
|
3773
|
-
artifactsDir =
|
|
3906
|
+
artifactsDir = path12.join(baseDir, sessionId);
|
|
3774
3907
|
await fs9.mkdir(artifactsDir, { recursive: true });
|
|
3775
3908
|
return artifactsDir;
|
|
3776
3909
|
}
|
|
3777
3910
|
async function updateTaskFile(task) {
|
|
3778
3911
|
const dir = await getArtifactsDir();
|
|
3779
|
-
const taskFile =
|
|
3912
|
+
const taskFile = path12.join(dir, "task.md");
|
|
3780
3913
|
const content = `# ${task.taskName}
|
|
3781
3914
|
|
|
3782
3915
|
**Mode:** ${task.mode}
|
|
@@ -3821,32 +3954,58 @@ async function taskBoundary(args) {
|
|
|
3821
3954
|
};
|
|
3822
3955
|
}
|
|
3823
3956
|
const now = Date.now();
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3957
|
+
let currentTask = null;
|
|
3958
|
+
updateTaskStore((state) => {
|
|
3959
|
+
if (state.activeTask && state.activeTask.taskName === task_name) {
|
|
3960
|
+
state.activeTask.mode = mode;
|
|
3961
|
+
state.activeTask.status = task_status;
|
|
3962
|
+
state.activeTask.summary = task_summary || state.activeTask.summary;
|
|
3963
|
+
state.activeTask.updateTime = now;
|
|
3964
|
+
state.activeTask.stepCount++;
|
|
3965
|
+
} else {
|
|
3966
|
+
state.activeTask = {
|
|
3967
|
+
taskName: task_name,
|
|
3968
|
+
mode,
|
|
3969
|
+
status: task_status,
|
|
3970
|
+
summary: task_summary || "",
|
|
3971
|
+
startTime: now,
|
|
3972
|
+
updateTime: now,
|
|
3973
|
+
stepCount: 1
|
|
3974
|
+
};
|
|
3975
|
+
}
|
|
3976
|
+
currentTask = state.activeTask;
|
|
3977
|
+
});
|
|
3978
|
+
if (!currentTask) {
|
|
3979
|
+
return {
|
|
3980
|
+
success: false,
|
|
3981
|
+
task_name,
|
|
3982
|
+
mode,
|
|
3983
|
+
status: task_status,
|
|
3984
|
+
message: "Failed to persist active task"
|
|
3985
|
+
};
|
|
3986
|
+
}
|
|
3987
|
+
const snapshot = buildTaskSnapshot();
|
|
3988
|
+
const persistedTask = snapshot.activeTask;
|
|
3989
|
+
if (!persistedTask) {
|
|
3990
|
+
return {
|
|
3991
|
+
success: false,
|
|
3992
|
+
task_name,
|
|
3833
3993
|
mode,
|
|
3834
3994
|
status: task_status,
|
|
3835
|
-
|
|
3836
|
-
startTime: now,
|
|
3837
|
-
updateTime: now,
|
|
3838
|
-
stepCount: 1
|
|
3995
|
+
message: "Task persisted without an active snapshot"
|
|
3839
3996
|
};
|
|
3840
3997
|
}
|
|
3841
|
-
await updateTaskFile(
|
|
3998
|
+
await updateTaskFile(persistedTask);
|
|
3842
3999
|
const dir = await getArtifactsDir();
|
|
3843
4000
|
return {
|
|
3844
4001
|
success: true,
|
|
3845
|
-
task_name:
|
|
3846
|
-
mode:
|
|
3847
|
-
status:
|
|
4002
|
+
task_name: persistedTask.taskName,
|
|
4003
|
+
mode: persistedTask.mode,
|
|
4004
|
+
status: persistedTask.status,
|
|
3848
4005
|
message: `Task "${task_name}" is now in ${mode} mode. Status: ${task_status}`,
|
|
3849
|
-
artifacts_dir: dir
|
|
4006
|
+
artifacts_dir: dir,
|
|
4007
|
+
activeTask: snapshot.activeTask,
|
|
4008
|
+
stats: snapshot.stats
|
|
3850
4009
|
};
|
|
3851
4010
|
} catch (error) {
|
|
3852
4011
|
return {
|
|
@@ -3868,7 +4027,7 @@ async function createArtifact(args) {
|
|
|
3868
4027
|
return { success: false, error: "content is required" };
|
|
3869
4028
|
}
|
|
3870
4029
|
const dir = await getArtifactsDir();
|
|
3871
|
-
const filepath =
|
|
4030
|
+
const filepath = path12.join(dir, filename);
|
|
3872
4031
|
await fs9.writeFile(filepath, content, "utf-8");
|
|
3873
4032
|
return {
|
|
3874
4033
|
success: true,
|
|
@@ -3888,7 +4047,7 @@ async function readArtifact(args) {
|
|
|
3888
4047
|
return { success: false, error: "filename is required" };
|
|
3889
4048
|
}
|
|
3890
4049
|
const dir = await getArtifactsDir();
|
|
3891
|
-
const filepath =
|
|
4050
|
+
const filepath = path12.join(dir, filename);
|
|
3892
4051
|
const content = await fs9.readFile(filepath, "utf-8");
|
|
3893
4052
|
return {
|
|
3894
4053
|
success: true,
|
|
@@ -4259,7 +4418,7 @@ ${skill.content}`;
|
|
|
4259
4418
|
|
|
4260
4419
|
// src/app/agent/tools/natives/coding_memory.ts
|
|
4261
4420
|
import * as fs10 from "fs";
|
|
4262
|
-
import * as
|
|
4421
|
+
import * as path13 from "path";
|
|
4263
4422
|
import os7 from "os";
|
|
4264
4423
|
var PROMPT_DEFAULT_MAX_TOTAL = 1e4;
|
|
4265
4424
|
var PROMPT_DEFAULT_MAX_NOTES = 25;
|
|
@@ -4268,13 +4427,13 @@ function readCodingMemoryForPrompt(options) {
|
|
|
4268
4427
|
const maxTotal = options?.maxTotalChars ?? PROMPT_DEFAULT_MAX_TOTAL;
|
|
4269
4428
|
const maxNotes = options?.maxNotes ?? PROMPT_DEFAULT_MAX_NOTES;
|
|
4270
4429
|
const preview = options?.previewCharsPerNote ?? PROMPT_DEFAULT_PREVIEW;
|
|
4271
|
-
const globalPath =
|
|
4272
|
-
const legacyPath =
|
|
4430
|
+
const globalPath = path13.join(os7.homedir(), ".bluma", "coding_memory.json");
|
|
4431
|
+
const legacyPath = path13.join(process.cwd(), ".bluma", "coding_memory.json");
|
|
4273
4432
|
let raw = null;
|
|
4274
4433
|
try {
|
|
4275
4434
|
if (fs10.existsSync(globalPath)) {
|
|
4276
4435
|
raw = fs10.readFileSync(globalPath, "utf-8");
|
|
4277
|
-
} else if (
|
|
4436
|
+
} else if (path13.resolve(globalPath) !== path13.resolve(legacyPath) && fs10.existsSync(legacyPath)) {
|
|
4278
4437
|
raw = fs10.readFileSync(legacyPath, "utf-8");
|
|
4279
4438
|
}
|
|
4280
4439
|
} catch {
|
|
@@ -4310,29 +4469,29 @@ ${block}` : block;
|
|
|
4310
4469
|
return parts.join("");
|
|
4311
4470
|
}
|
|
4312
4471
|
var memoryStore = [];
|
|
4313
|
-
var
|
|
4472
|
+
var nextId = 1;
|
|
4314
4473
|
var loaded = false;
|
|
4315
4474
|
function getMemoryFilePath() {
|
|
4316
|
-
return
|
|
4475
|
+
return path13.join(os7.homedir(), ".bluma", "coding_memory.json");
|
|
4317
4476
|
}
|
|
4318
4477
|
function getLegacyMemoryFilePath() {
|
|
4319
|
-
return
|
|
4478
|
+
return path13.join(process.cwd(), ".bluma", "coding_memory.json");
|
|
4320
4479
|
}
|
|
4321
4480
|
function loadMemoryFromFile() {
|
|
4322
4481
|
if (loaded) return;
|
|
4323
4482
|
loaded = true;
|
|
4324
4483
|
memoryStore = [];
|
|
4325
|
-
|
|
4484
|
+
nextId = 1;
|
|
4326
4485
|
try {
|
|
4327
4486
|
const filePath = getMemoryFilePath();
|
|
4328
4487
|
const legacy = getLegacyMemoryFilePath();
|
|
4329
|
-
const legacyDistinct =
|
|
4488
|
+
const legacyDistinct = path13.resolve(legacy) !== path13.resolve(filePath);
|
|
4330
4489
|
const readIntoStore = (p) => {
|
|
4331
4490
|
const raw = fs10.readFileSync(p, "utf-8");
|
|
4332
4491
|
const parsed = JSON.parse(raw);
|
|
4333
4492
|
if (Array.isArray(parsed.entries)) {
|
|
4334
4493
|
memoryStore = parsed.entries;
|
|
4335
|
-
|
|
4494
|
+
nextId = typeof parsed.nextId === "number" ? parsed.nextId : memoryStore.length + 1;
|
|
4336
4495
|
}
|
|
4337
4496
|
};
|
|
4338
4497
|
if (fs10.existsSync(filePath)) {
|
|
@@ -4346,19 +4505,19 @@ function loadMemoryFromFile() {
|
|
|
4346
4505
|
}
|
|
4347
4506
|
} catch {
|
|
4348
4507
|
memoryStore = [];
|
|
4349
|
-
|
|
4508
|
+
nextId = 1;
|
|
4350
4509
|
}
|
|
4351
4510
|
}
|
|
4352
4511
|
function saveMemoryToFile() {
|
|
4353
4512
|
try {
|
|
4354
4513
|
const filePath = getMemoryFilePath();
|
|
4355
|
-
const dir =
|
|
4514
|
+
const dir = path13.dirname(filePath);
|
|
4356
4515
|
if (!fs10.existsSync(dir)) {
|
|
4357
4516
|
fs10.mkdirSync(dir, { recursive: true });
|
|
4358
4517
|
}
|
|
4359
4518
|
const payload = {
|
|
4360
4519
|
entries: memoryStore,
|
|
4361
|
-
nextId
|
|
4520
|
+
nextId,
|
|
4362
4521
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4363
4522
|
};
|
|
4364
4523
|
fs10.writeFileSync(filePath, JSON.stringify(payload, null, 2));
|
|
@@ -4387,7 +4546,7 @@ function addNote(args) {
|
|
|
4387
4546
|
};
|
|
4388
4547
|
}
|
|
4389
4548
|
const entry = {
|
|
4390
|
-
id:
|
|
4549
|
+
id: nextId++,
|
|
4391
4550
|
note,
|
|
4392
4551
|
tags: normalizeTags(args.tags),
|
|
4393
4552
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -4512,44 +4671,698 @@ function updateNote(args) {
|
|
|
4512
4671
|
if (hasTags) {
|
|
4513
4672
|
entry.tags = normalizeTags(args.tags);
|
|
4514
4673
|
}
|
|
4515
|
-
saveMemoryToFile();
|
|
4516
|
-
return {
|
|
4517
|
-
success: true,
|
|
4518
|
-
message: `Updated coding memory id=${id}`,
|
|
4519
|
-
entries: memoryStore
|
|
4520
|
-
};
|
|
4674
|
+
saveMemoryToFile();
|
|
4675
|
+
return {
|
|
4676
|
+
success: true,
|
|
4677
|
+
message: `Updated coding memory id=${id}`,
|
|
4678
|
+
entries: memoryStore
|
|
4679
|
+
};
|
|
4680
|
+
}
|
|
4681
|
+
async function coding_memory(args) {
|
|
4682
|
+
const action = args.action;
|
|
4683
|
+
switch (action) {
|
|
4684
|
+
case "add":
|
|
4685
|
+
return addNote(args);
|
|
4686
|
+
case "list":
|
|
4687
|
+
return listNotes();
|
|
4688
|
+
case "search":
|
|
4689
|
+
return searchNotes(args);
|
|
4690
|
+
case "remove":
|
|
4691
|
+
return removeNote(args);
|
|
4692
|
+
case "update":
|
|
4693
|
+
return updateNote(args);
|
|
4694
|
+
default:
|
|
4695
|
+
return {
|
|
4696
|
+
success: false,
|
|
4697
|
+
message: `Unknown action: ${String(action)}`,
|
|
4698
|
+
entries: memoryStore
|
|
4699
|
+
};
|
|
4700
|
+
}
|
|
4701
|
+
}
|
|
4702
|
+
|
|
4703
|
+
// src/app/agent/tools/natives/file_write.ts
|
|
4704
|
+
init_sandbox_policy();
|
|
4705
|
+
import { promises as fs11 } from "fs";
|
|
4706
|
+
import path14 from "path";
|
|
4707
|
+
async function fileWrite(args) {
|
|
4708
|
+
const {
|
|
4709
|
+
filepath,
|
|
4710
|
+
content,
|
|
4711
|
+
overwrite = true,
|
|
4712
|
+
create_directories = true
|
|
4713
|
+
} = args;
|
|
4714
|
+
try {
|
|
4715
|
+
if (!filepath || typeof filepath !== "string") {
|
|
4716
|
+
return { success: false, error: "filepath is required" };
|
|
4717
|
+
}
|
|
4718
|
+
if (content === void 0 || content === null) {
|
|
4719
|
+
return { success: false, error: "content is required" };
|
|
4720
|
+
}
|
|
4721
|
+
const resolvedPath = resolveWorkspacePath(filepath);
|
|
4722
|
+
const dir = path14.dirname(resolvedPath);
|
|
4723
|
+
let existed = false;
|
|
4724
|
+
try {
|
|
4725
|
+
const st = await fs11.stat(resolvedPath);
|
|
4726
|
+
existed = st.isFile();
|
|
4727
|
+
} catch {
|
|
4728
|
+
existed = false;
|
|
4729
|
+
}
|
|
4730
|
+
if (existed && !overwrite) {
|
|
4731
|
+
return {
|
|
4732
|
+
success: false,
|
|
4733
|
+
error: `File already exists and overwrite=false: ${resolvedPath}`
|
|
4734
|
+
};
|
|
4735
|
+
}
|
|
4736
|
+
if (create_directories) {
|
|
4737
|
+
await fs11.mkdir(dir, { recursive: true });
|
|
4738
|
+
}
|
|
4739
|
+
await fs11.writeFile(resolvedPath, String(content), "utf-8");
|
|
4740
|
+
const bytes = Buffer.byteLength(String(content), "utf-8");
|
|
4741
|
+
return {
|
|
4742
|
+
success: true,
|
|
4743
|
+
filepath: resolvedPath,
|
|
4744
|
+
bytes_written: bytes,
|
|
4745
|
+
created: !existed,
|
|
4746
|
+
overwritten: existed
|
|
4747
|
+
};
|
|
4748
|
+
} catch (error) {
|
|
4749
|
+
return { success: false, error: error.message || String(error) };
|
|
4750
|
+
}
|
|
4751
|
+
}
|
|
4752
|
+
|
|
4753
|
+
// src/app/agent/tools/natives/web_fetch.ts
|
|
4754
|
+
import http2 from "http";
|
|
4755
|
+
import https2 from "https";
|
|
4756
|
+
var DEFAULT_MAX_CHARS = 12e3;
|
|
4757
|
+
var REQUEST_TIMEOUT_MS = 15e3;
|
|
4758
|
+
function fetchUrl(url) {
|
|
4759
|
+
return new Promise((resolve2, reject) => {
|
|
4760
|
+
const client = url.startsWith("https://") ? https2 : http2;
|
|
4761
|
+
const req = client.get(
|
|
4762
|
+
url,
|
|
4763
|
+
{
|
|
4764
|
+
headers: {
|
|
4765
|
+
"User-Agent": "bluma-cli/0.1",
|
|
4766
|
+
Accept: "text/plain,text/html,application/json;q=0.9,*/*;q=0.5"
|
|
4767
|
+
},
|
|
4768
|
+
timeout: REQUEST_TIMEOUT_MS
|
|
4769
|
+
},
|
|
4770
|
+
(res) => {
|
|
4771
|
+
if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
4772
|
+
fetchUrl(res.headers.location).then(resolve2).catch(reject);
|
|
4773
|
+
return;
|
|
4774
|
+
}
|
|
4775
|
+
let body = "";
|
|
4776
|
+
res.on("data", (chunk) => {
|
|
4777
|
+
body += chunk.toString();
|
|
4778
|
+
});
|
|
4779
|
+
res.on("end", () => {
|
|
4780
|
+
resolve2({
|
|
4781
|
+
statusCode: res.statusCode,
|
|
4782
|
+
contentType: res.headers["content-type"],
|
|
4783
|
+
body
|
|
4784
|
+
});
|
|
4785
|
+
});
|
|
4786
|
+
}
|
|
4787
|
+
);
|
|
4788
|
+
req.on("error", reject);
|
|
4789
|
+
req.on("timeout", () => {
|
|
4790
|
+
req.destroy(new Error("Request timeout"));
|
|
4791
|
+
});
|
|
4792
|
+
});
|
|
4793
|
+
}
|
|
4794
|
+
function stripHtml(html) {
|
|
4795
|
+
return html.replace(/<script[\s\S]*?<\/script>/gi, "").replace(/<style[\s\S]*?<\/style>/gi, "").replace(/<[^>]+>/g, " ").replace(/ /g, " ").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/\s+/g, " ").trim();
|
|
4796
|
+
}
|
|
4797
|
+
async function webFetch(args) {
|
|
4798
|
+
const maxChars = Math.max(500, Math.min(args.max_chars ?? DEFAULT_MAX_CHARS, 5e4));
|
|
4799
|
+
const url = String(args.url || "").trim();
|
|
4800
|
+
if (!/^https?:\/\//i.test(url)) {
|
|
4801
|
+
return {
|
|
4802
|
+
success: false,
|
|
4803
|
+
url,
|
|
4804
|
+
error: "url must start with http:// or https://"
|
|
4805
|
+
};
|
|
4806
|
+
}
|
|
4807
|
+
try {
|
|
4808
|
+
const response = await fetchUrl(url);
|
|
4809
|
+
const contentType = response.contentType || "unknown";
|
|
4810
|
+
const raw = /html/i.test(contentType) ? stripHtml(response.body) : response.body.trim();
|
|
4811
|
+
const truncated = raw.length > maxChars;
|
|
4812
|
+
const content = truncated ? `${raw.slice(0, maxChars)}
|
|
4813
|
+
|
|
4814
|
+
[...truncated...]` : raw;
|
|
4815
|
+
return {
|
|
4816
|
+
success: true,
|
|
4817
|
+
url,
|
|
4818
|
+
status_code: response.statusCode,
|
|
4819
|
+
content_type: contentType,
|
|
4820
|
+
content,
|
|
4821
|
+
truncated
|
|
4822
|
+
};
|
|
4823
|
+
} catch (error) {
|
|
4824
|
+
return {
|
|
4825
|
+
success: false,
|
|
4826
|
+
url,
|
|
4827
|
+
error: error.message || String(error)
|
|
4828
|
+
};
|
|
4829
|
+
}
|
|
4830
|
+
}
|
|
4831
|
+
|
|
4832
|
+
// src/app/agent/tools/natives/agent_coordination.ts
|
|
4833
|
+
import fs13 from "fs";
|
|
4834
|
+
import os9 from "os";
|
|
4835
|
+
import path16 from "path";
|
|
4836
|
+
import { spawn as spawn3 } from "child_process";
|
|
4837
|
+
import { v4 as uuidv43 } from "uuid";
|
|
4838
|
+
|
|
4839
|
+
// src/app/agent/runtime/session_registry.ts
|
|
4840
|
+
import fs12 from "fs";
|
|
4841
|
+
import os8 from "os";
|
|
4842
|
+
import path15 from "path";
|
|
4843
|
+
function getRegistryDir() {
|
|
4844
|
+
return path15.join(process.env.HOME || os8.homedir(), ".bluma", "registry");
|
|
4845
|
+
}
|
|
4846
|
+
function getRegistryFile() {
|
|
4847
|
+
return path15.join(getRegistryDir(), "sessions.json");
|
|
4848
|
+
}
|
|
4849
|
+
function ensureRegistryDir() {
|
|
4850
|
+
fs12.mkdirSync(getRegistryDir(), { recursive: true });
|
|
4851
|
+
}
|
|
4852
|
+
function readRegistry() {
|
|
4853
|
+
ensureRegistryDir();
|
|
4854
|
+
const file = getRegistryFile();
|
|
4855
|
+
if (!fs12.existsSync(file)) {
|
|
4856
|
+
return { entries: [] };
|
|
4857
|
+
}
|
|
4858
|
+
try {
|
|
4859
|
+
return JSON.parse(fs12.readFileSync(file, "utf-8"));
|
|
4860
|
+
} catch {
|
|
4861
|
+
return { entries: [] };
|
|
4862
|
+
}
|
|
4863
|
+
}
|
|
4864
|
+
function writeRegistry(state) {
|
|
4865
|
+
ensureRegistryDir();
|
|
4866
|
+
fs12.writeFileSync(getRegistryFile(), JSON.stringify(state, null, 2), "utf-8");
|
|
4867
|
+
}
|
|
4868
|
+
function getSessionLogPath(sessionId) {
|
|
4869
|
+
ensureRegistryDir();
|
|
4870
|
+
return path15.join(getRegistryDir(), `${sessionId}.jsonl`);
|
|
4871
|
+
}
|
|
4872
|
+
function registerSession(entry) {
|
|
4873
|
+
const state = readRegistry();
|
|
4874
|
+
const nextEntry = {
|
|
4875
|
+
...entry,
|
|
4876
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4877
|
+
logFile: getSessionLogPath(entry.sessionId)
|
|
4878
|
+
};
|
|
4879
|
+
state.entries = state.entries.filter((item) => item.sessionId !== entry.sessionId);
|
|
4880
|
+
state.entries.unshift(nextEntry);
|
|
4881
|
+
writeRegistry(state);
|
|
4882
|
+
return nextEntry;
|
|
4883
|
+
}
|
|
4884
|
+
function updateSession(sessionId, patch) {
|
|
4885
|
+
const state = readRegistry();
|
|
4886
|
+
const index = state.entries.findIndex((entry) => entry.sessionId === sessionId);
|
|
4887
|
+
if (index === -1) return null;
|
|
4888
|
+
const nextEntry = {
|
|
4889
|
+
...state.entries[index],
|
|
4890
|
+
...patch,
|
|
4891
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4892
|
+
};
|
|
4893
|
+
state.entries[index] = nextEntry;
|
|
4894
|
+
writeRegistry(state);
|
|
4895
|
+
return nextEntry;
|
|
4896
|
+
}
|
|
4897
|
+
function listSessions() {
|
|
4898
|
+
return readRegistry().entries;
|
|
4899
|
+
}
|
|
4900
|
+
function getSession(sessionId) {
|
|
4901
|
+
return readRegistry().entries.find((entry) => entry.sessionId === sessionId) || null;
|
|
4902
|
+
}
|
|
4903
|
+
function appendSessionLog(sessionId, payload) {
|
|
4904
|
+
const logFile = getSessionLogPath(sessionId);
|
|
4905
|
+
fs12.appendFileSync(logFile, `${JSON.stringify(payload)}
|
|
4906
|
+
`, "utf-8");
|
|
4907
|
+
}
|
|
4908
|
+
function readSessionLog(sessionId) {
|
|
4909
|
+
const logFile = getSessionLogPath(sessionId);
|
|
4910
|
+
if (!fs12.existsSync(logFile)) return [];
|
|
4911
|
+
return fs12.readFileSync(logFile, "utf-8").split("\n").filter(Boolean);
|
|
4912
|
+
}
|
|
4913
|
+
|
|
4914
|
+
// src/app/agent/tools/natives/agent_coordination.ts
|
|
4915
|
+
function buildWorkerPayload(sessionId, args, parentSessionId) {
|
|
4916
|
+
return {
|
|
4917
|
+
message_id: sessionId,
|
|
4918
|
+
session_id: sessionId,
|
|
4919
|
+
from_agent: parentSessionId || "interactive",
|
|
4920
|
+
to_agent: "bluma-worker",
|
|
4921
|
+
action: "worker_task",
|
|
4922
|
+
context: {
|
|
4923
|
+
user_request: args.task,
|
|
4924
|
+
coordinator_context: args.context || null,
|
|
4925
|
+
worker_title: args.title || null,
|
|
4926
|
+
worker_role: args.agent_type || "worker"
|
|
4927
|
+
},
|
|
4928
|
+
metadata: {
|
|
4929
|
+
sandbox: process.env.BLUMA_SANDBOX === "true",
|
|
4930
|
+
sandbox_name: process.env.BLUMA_SANDBOX_NAME || void 0,
|
|
4931
|
+
coordinator_worker: true,
|
|
4932
|
+
parent_session_id: parentSessionId
|
|
4933
|
+
}
|
|
4934
|
+
};
|
|
4935
|
+
}
|
|
4936
|
+
function extractLatestResult(sessionId) {
|
|
4937
|
+
const lines = readSessionLog(sessionId);
|
|
4938
|
+
for (let index = lines.length - 1; index >= 0; index -= 1) {
|
|
4939
|
+
try {
|
|
4940
|
+
const parsed = JSON.parse(lines[index]);
|
|
4941
|
+
if (parsed.event_type === "result") {
|
|
4942
|
+
return parsed;
|
|
4943
|
+
}
|
|
4944
|
+
} catch {
|
|
4945
|
+
}
|
|
4946
|
+
}
|
|
4947
|
+
return null;
|
|
4948
|
+
}
|
|
4949
|
+
function toAgentSummary(entry) {
|
|
4950
|
+
return {
|
|
4951
|
+
session_id: entry.sessionId,
|
|
4952
|
+
title: entry.title,
|
|
4953
|
+
kind: entry.kind,
|
|
4954
|
+
status: entry.status,
|
|
4955
|
+
started_at: entry.startedAt,
|
|
4956
|
+
updated_at: entry.updatedAt,
|
|
4957
|
+
pid: entry.pid || null,
|
|
4958
|
+
metadata: entry.metadata || {}
|
|
4959
|
+
};
|
|
4960
|
+
}
|
|
4961
|
+
async function spawnAgent(args) {
|
|
4962
|
+
if (!args?.task || typeof args.task !== "string") {
|
|
4963
|
+
return { success: false, error: "task is required" };
|
|
4964
|
+
}
|
|
4965
|
+
const entrypoint = process.argv[1];
|
|
4966
|
+
if (!entrypoint) {
|
|
4967
|
+
return { success: false, error: "Unable to resolve CLI entrypoint for worker spawn" };
|
|
4968
|
+
}
|
|
4969
|
+
const sessionId = uuidv43();
|
|
4970
|
+
const parentSessionId = process.env.BLUMA_SESSION_ID || null;
|
|
4971
|
+
const title = args.title || `worker:${args.agent_type || "worker"}`;
|
|
4972
|
+
const payload = buildWorkerPayload(sessionId, args, parentSessionId);
|
|
4973
|
+
const payloadDir = fs13.mkdtempSync(path16.join(os9.tmpdir(), "bluma-worker-"));
|
|
4974
|
+
const payloadPath = path16.join(payloadDir, `${sessionId}.json`);
|
|
4975
|
+
fs13.writeFileSync(payloadPath, JSON.stringify(payload, null, 2), "utf-8");
|
|
4976
|
+
registerSession({
|
|
4977
|
+
sessionId,
|
|
4978
|
+
kind: "agent",
|
|
4979
|
+
status: "running",
|
|
4980
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4981
|
+
workdir: process.cwd(),
|
|
4982
|
+
title,
|
|
4983
|
+
metadata: {
|
|
4984
|
+
action: "worker_task",
|
|
4985
|
+
background: true,
|
|
4986
|
+
coordinator_worker: true,
|
|
4987
|
+
parent_session_id: parentSessionId,
|
|
4988
|
+
agent_type: args.agent_type || "worker"
|
|
4989
|
+
}
|
|
4990
|
+
});
|
|
4991
|
+
const child = spawn3(
|
|
4992
|
+
process.execPath,
|
|
4993
|
+
[entrypoint, "agent", "--input-file", payloadPath, "--background-worker", "--registry-session", sessionId],
|
|
4994
|
+
{
|
|
4995
|
+
detached: true,
|
|
4996
|
+
stdio: "ignore",
|
|
4997
|
+
cwd: process.cwd(),
|
|
4998
|
+
env: {
|
|
4999
|
+
...process.env,
|
|
5000
|
+
BLUMA_PARENT_SESSION_ID: parentSessionId || ""
|
|
5001
|
+
}
|
|
5002
|
+
}
|
|
5003
|
+
);
|
|
5004
|
+
child.unref();
|
|
5005
|
+
updateSession(sessionId, { pid: child.pid });
|
|
5006
|
+
return {
|
|
5007
|
+
success: true,
|
|
5008
|
+
session_id: sessionId,
|
|
5009
|
+
pid: child.pid || null,
|
|
5010
|
+
parent_session_id: parentSessionId,
|
|
5011
|
+
title,
|
|
5012
|
+
status: "running"
|
|
5013
|
+
};
|
|
5014
|
+
}
|
|
5015
|
+
async function waitAgent(args) {
|
|
5016
|
+
const sessionId = args?.session_id;
|
|
5017
|
+
if (!sessionId || typeof sessionId !== "string") {
|
|
5018
|
+
return { success: false, error: "session_id is required" };
|
|
5019
|
+
}
|
|
5020
|
+
const timeoutMs = Math.max(1e3, Number(args.timeout_ms || 3e4));
|
|
5021
|
+
const pollIntervalMs = Math.max(200, Number(args.poll_interval_ms || 1e3));
|
|
5022
|
+
const deadline = Date.now() + timeoutMs;
|
|
5023
|
+
while (Date.now() < deadline) {
|
|
5024
|
+
const session2 = getSession(sessionId);
|
|
5025
|
+
if (!session2) {
|
|
5026
|
+
return { success: false, error: `Unknown session: ${sessionId}` };
|
|
5027
|
+
}
|
|
5028
|
+
if (session2.status !== "running") {
|
|
5029
|
+
return {
|
|
5030
|
+
success: true,
|
|
5031
|
+
completed: true,
|
|
5032
|
+
session: toAgentSummary(session2),
|
|
5033
|
+
result: extractLatestResult(sessionId)
|
|
5034
|
+
};
|
|
5035
|
+
}
|
|
5036
|
+
await new Promise((resolve2) => setTimeout(resolve2, pollIntervalMs));
|
|
5037
|
+
}
|
|
5038
|
+
const session = getSession(sessionId);
|
|
5039
|
+
if (!session) {
|
|
5040
|
+
return { success: false, error: `Unknown session: ${sessionId}` };
|
|
5041
|
+
}
|
|
5042
|
+
return {
|
|
5043
|
+
success: true,
|
|
5044
|
+
completed: false,
|
|
5045
|
+
session: toAgentSummary(session),
|
|
5046
|
+
result: extractLatestResult(sessionId),
|
|
5047
|
+
message: `Timed out after ${timeoutMs}ms while waiting for agent ${sessionId}.`
|
|
5048
|
+
};
|
|
5049
|
+
}
|
|
5050
|
+
async function listAgents(args = {}) {
|
|
5051
|
+
const entries = listSessions().filter((entry) => entry.kind === "agent").filter((entry) => {
|
|
5052
|
+
if (args.parent_session_id) {
|
|
5053
|
+
return entry.metadata?.parent_session_id === args.parent_session_id;
|
|
5054
|
+
}
|
|
5055
|
+
return true;
|
|
5056
|
+
}).filter((entry) => {
|
|
5057
|
+
if (args.status) {
|
|
5058
|
+
return entry.status === args.status;
|
|
5059
|
+
}
|
|
5060
|
+
return true;
|
|
5061
|
+
}).map(toAgentSummary);
|
|
5062
|
+
return {
|
|
5063
|
+
success: true,
|
|
5064
|
+
count: entries.length,
|
|
5065
|
+
agents: entries
|
|
5066
|
+
};
|
|
5067
|
+
}
|
|
5068
|
+
|
|
5069
|
+
// src/app/agent/runtime/native_tool_catalog.ts
|
|
5070
|
+
var NATIVE_TOOL_ENTRIES = [
|
|
5071
|
+
{
|
|
5072
|
+
metadata: {
|
|
5073
|
+
name: "message",
|
|
5074
|
+
category: "communication",
|
|
5075
|
+
riskLevel: "safe",
|
|
5076
|
+
autoApproveInLocal: true,
|
|
5077
|
+
autoApproveInSandbox: true,
|
|
5078
|
+
description: "Deliver progress or result messages to the user."
|
|
5079
|
+
},
|
|
5080
|
+
implementation: message
|
|
5081
|
+
},
|
|
5082
|
+
{
|
|
5083
|
+
metadata: {
|
|
5084
|
+
name: "todo",
|
|
5085
|
+
category: "planning",
|
|
5086
|
+
riskLevel: "safe",
|
|
5087
|
+
autoApproveInLocal: true,
|
|
5088
|
+
autoApproveInSandbox: true,
|
|
5089
|
+
description: "Track a task list for the current objective."
|
|
5090
|
+
},
|
|
5091
|
+
implementation: todo
|
|
5092
|
+
},
|
|
5093
|
+
{
|
|
5094
|
+
metadata: {
|
|
5095
|
+
name: "task_boundary",
|
|
5096
|
+
category: "planning",
|
|
5097
|
+
riskLevel: "safe",
|
|
5098
|
+
autoApproveInLocal: true,
|
|
5099
|
+
autoApproveInSandbox: true,
|
|
5100
|
+
description: "Track the current task mode and execution boundary."
|
|
5101
|
+
},
|
|
5102
|
+
implementation: taskBoundary
|
|
5103
|
+
},
|
|
5104
|
+
{
|
|
5105
|
+
metadata: {
|
|
5106
|
+
name: "create_artifact",
|
|
5107
|
+
category: "artifact",
|
|
5108
|
+
riskLevel: "write",
|
|
5109
|
+
autoApproveInLocal: true,
|
|
5110
|
+
autoApproveInSandbox: true,
|
|
5111
|
+
description: "Write a generated artifact into the artifact output area."
|
|
5112
|
+
},
|
|
5113
|
+
implementation: createArtifact
|
|
5114
|
+
},
|
|
5115
|
+
{
|
|
5116
|
+
metadata: {
|
|
5117
|
+
name: "read_artifact",
|
|
5118
|
+
category: "artifact",
|
|
5119
|
+
riskLevel: "safe",
|
|
5120
|
+
autoApproveInLocal: true,
|
|
5121
|
+
autoApproveInSandbox: true,
|
|
5122
|
+
description: "Read an artifact from the artifact output area."
|
|
5123
|
+
},
|
|
5124
|
+
implementation: readArtifact
|
|
5125
|
+
},
|
|
5126
|
+
{
|
|
5127
|
+
metadata: {
|
|
5128
|
+
name: "ls_tool",
|
|
5129
|
+
category: "filesystem",
|
|
5130
|
+
riskLevel: "safe",
|
|
5131
|
+
autoApproveInLocal: true,
|
|
5132
|
+
autoApproveInSandbox: true,
|
|
5133
|
+
description: "List files and directories."
|
|
5134
|
+
},
|
|
5135
|
+
implementation: ls
|
|
5136
|
+
},
|
|
5137
|
+
{
|
|
5138
|
+
metadata: {
|
|
5139
|
+
name: "count_file_lines",
|
|
5140
|
+
category: "filesystem",
|
|
5141
|
+
riskLevel: "safe",
|
|
5142
|
+
autoApproveInLocal: true,
|
|
5143
|
+
autoApproveInSandbox: true,
|
|
5144
|
+
description: "Count lines in a text file."
|
|
5145
|
+
},
|
|
5146
|
+
implementation: countLines
|
|
5147
|
+
},
|
|
5148
|
+
{
|
|
5149
|
+
metadata: {
|
|
5150
|
+
name: "read_file_lines",
|
|
5151
|
+
category: "filesystem",
|
|
5152
|
+
riskLevel: "safe",
|
|
5153
|
+
autoApproveInLocal: true,
|
|
5154
|
+
autoApproveInSandbox: true,
|
|
5155
|
+
description: "Read a slice of a text file."
|
|
5156
|
+
},
|
|
5157
|
+
implementation: readLines
|
|
5158
|
+
},
|
|
5159
|
+
{
|
|
5160
|
+
metadata: {
|
|
5161
|
+
name: "find_by_name",
|
|
5162
|
+
category: "filesystem",
|
|
5163
|
+
riskLevel: "safe",
|
|
5164
|
+
autoApproveInLocal: true,
|
|
5165
|
+
autoApproveInSandbox: true,
|
|
5166
|
+
description: "Find files by glob pattern."
|
|
5167
|
+
},
|
|
5168
|
+
implementation: findByName
|
|
5169
|
+
},
|
|
5170
|
+
{
|
|
5171
|
+
metadata: {
|
|
5172
|
+
name: "grep_search",
|
|
5173
|
+
category: "filesystem",
|
|
5174
|
+
riskLevel: "safe",
|
|
5175
|
+
autoApproveInLocal: true,
|
|
5176
|
+
autoApproveInSandbox: true,
|
|
5177
|
+
description: "Search file contents."
|
|
5178
|
+
},
|
|
5179
|
+
implementation: grepSearch
|
|
5180
|
+
},
|
|
5181
|
+
{
|
|
5182
|
+
metadata: {
|
|
5183
|
+
name: "view_file_outline",
|
|
5184
|
+
category: "filesystem",
|
|
5185
|
+
riskLevel: "safe",
|
|
5186
|
+
autoApproveInLocal: true,
|
|
5187
|
+
autoApproveInSandbox: true,
|
|
5188
|
+
description: "Inspect the outline of a source file."
|
|
5189
|
+
},
|
|
5190
|
+
implementation: viewFileOutline
|
|
5191
|
+
},
|
|
5192
|
+
{
|
|
5193
|
+
metadata: {
|
|
5194
|
+
name: "edit_tool",
|
|
5195
|
+
category: "filesystem",
|
|
5196
|
+
riskLevel: "write",
|
|
5197
|
+
autoApproveInLocal: false,
|
|
5198
|
+
autoApproveInSandbox: true,
|
|
5199
|
+
description: "Edit or create files in the workspace."
|
|
5200
|
+
},
|
|
5201
|
+
implementation: editTool
|
|
5202
|
+
},
|
|
5203
|
+
{
|
|
5204
|
+
metadata: {
|
|
5205
|
+
name: "file_write",
|
|
5206
|
+
category: "filesystem",
|
|
5207
|
+
riskLevel: "write",
|
|
5208
|
+
autoApproveInLocal: false,
|
|
5209
|
+
autoApproveInSandbox: true,
|
|
5210
|
+
description: "Write full file contents directly into the workspace."
|
|
5211
|
+
},
|
|
5212
|
+
implementation: fileWrite
|
|
5213
|
+
},
|
|
5214
|
+
{
|
|
5215
|
+
metadata: {
|
|
5216
|
+
name: "shell_command",
|
|
5217
|
+
category: "execution",
|
|
5218
|
+
riskLevel: "execute",
|
|
5219
|
+
autoApproveInLocal: false,
|
|
5220
|
+
autoApproveInSandbox: true,
|
|
5221
|
+
description: "Execute a shell command in the workspace."
|
|
5222
|
+
},
|
|
5223
|
+
implementation: runCommandAsync
|
|
5224
|
+
},
|
|
5225
|
+
{
|
|
5226
|
+
metadata: {
|
|
5227
|
+
name: "command_status",
|
|
5228
|
+
category: "execution",
|
|
5229
|
+
riskLevel: "safe",
|
|
5230
|
+
autoApproveInLocal: true,
|
|
5231
|
+
autoApproveInSandbox: true,
|
|
5232
|
+
description: "Inspect the status of an async command."
|
|
5233
|
+
},
|
|
5234
|
+
implementation: commandStatus
|
|
5235
|
+
},
|
|
5236
|
+
{
|
|
5237
|
+
metadata: {
|
|
5238
|
+
name: "send_command_input",
|
|
5239
|
+
category: "execution",
|
|
5240
|
+
riskLevel: "execute",
|
|
5241
|
+
autoApproveInLocal: false,
|
|
5242
|
+
autoApproveInSandbox: true,
|
|
5243
|
+
description: "Send stdin to a running command."
|
|
5244
|
+
},
|
|
5245
|
+
implementation: sendCommandInput
|
|
5246
|
+
},
|
|
5247
|
+
{
|
|
5248
|
+
metadata: {
|
|
5249
|
+
name: "kill_command",
|
|
5250
|
+
category: "execution",
|
|
5251
|
+
riskLevel: "execute",
|
|
5252
|
+
autoApproveInLocal: false,
|
|
5253
|
+
autoApproveInSandbox: true,
|
|
5254
|
+
description: "Terminate a running command."
|
|
5255
|
+
},
|
|
5256
|
+
implementation: killCommand
|
|
5257
|
+
},
|
|
5258
|
+
{
|
|
5259
|
+
metadata: {
|
|
5260
|
+
name: "spawn_agent",
|
|
5261
|
+
category: "execution",
|
|
5262
|
+
riskLevel: "execute",
|
|
5263
|
+
autoApproveInLocal: false,
|
|
5264
|
+
autoApproveInSandbox: true,
|
|
5265
|
+
description: "Spawn a background worker agent for a bounded subtask."
|
|
5266
|
+
},
|
|
5267
|
+
implementation: spawnAgent
|
|
5268
|
+
},
|
|
5269
|
+
{
|
|
5270
|
+
metadata: {
|
|
5271
|
+
name: "wait_agent",
|
|
5272
|
+
category: "execution",
|
|
5273
|
+
riskLevel: "safe",
|
|
5274
|
+
autoApproveInLocal: true,
|
|
5275
|
+
autoApproveInSandbox: true,
|
|
5276
|
+
description: "Wait for a worker agent session to finish and collect its result."
|
|
5277
|
+
},
|
|
5278
|
+
implementation: waitAgent
|
|
5279
|
+
},
|
|
5280
|
+
{
|
|
5281
|
+
metadata: {
|
|
5282
|
+
name: "list_agents",
|
|
5283
|
+
category: "execution",
|
|
5284
|
+
riskLevel: "safe",
|
|
5285
|
+
autoApproveInLocal: true,
|
|
5286
|
+
autoApproveInSandbox: true,
|
|
5287
|
+
description: "List worker and agent sessions known to the coordinator."
|
|
5288
|
+
},
|
|
5289
|
+
implementation: listAgents
|
|
5290
|
+
},
|
|
5291
|
+
{
|
|
5292
|
+
metadata: {
|
|
5293
|
+
name: "search_web",
|
|
5294
|
+
category: "knowledge",
|
|
5295
|
+
riskLevel: "network",
|
|
5296
|
+
autoApproveInLocal: true,
|
|
5297
|
+
autoApproveInSandbox: true,
|
|
5298
|
+
description: "Search external sources through the configured provider."
|
|
5299
|
+
},
|
|
5300
|
+
implementation: searchWeb
|
|
5301
|
+
},
|
|
5302
|
+
{
|
|
5303
|
+
metadata: {
|
|
5304
|
+
name: "web_fetch",
|
|
5305
|
+
category: "knowledge",
|
|
5306
|
+
riskLevel: "network",
|
|
5307
|
+
autoApproveInLocal: true,
|
|
5308
|
+
autoApproveInSandbox: true,
|
|
5309
|
+
description: "Fetch the contents of a remote URL for analysis."
|
|
5310
|
+
},
|
|
5311
|
+
implementation: webFetch
|
|
5312
|
+
},
|
|
5313
|
+
{
|
|
5314
|
+
metadata: {
|
|
5315
|
+
name: "load_skill",
|
|
5316
|
+
category: "knowledge",
|
|
5317
|
+
riskLevel: "safe",
|
|
5318
|
+
autoApproveInLocal: true,
|
|
5319
|
+
autoApproveInSandbox: true,
|
|
5320
|
+
description: "Load a pluggable skill module."
|
|
5321
|
+
},
|
|
5322
|
+
implementation: loadSkill
|
|
5323
|
+
},
|
|
5324
|
+
{
|
|
5325
|
+
metadata: {
|
|
5326
|
+
name: "coding_memory",
|
|
5327
|
+
category: "knowledge",
|
|
5328
|
+
riskLevel: "safe",
|
|
5329
|
+
autoApproveInLocal: true,
|
|
5330
|
+
autoApproveInSandbox: true,
|
|
5331
|
+
description: "Persist or retrieve durable project notes."
|
|
5332
|
+
},
|
|
5333
|
+
implementation: coding_memory
|
|
5334
|
+
}
|
|
5335
|
+
];
|
|
5336
|
+
var TOOL_METADATA_MAP = new Map(
|
|
5337
|
+
NATIVE_TOOL_ENTRIES.map((entry) => [entry.metadata.name, entry.metadata])
|
|
5338
|
+
);
|
|
5339
|
+
var TOOL_IMPLEMENTATION_MAP = new Map(
|
|
5340
|
+
NATIVE_TOOL_ENTRIES.map((entry) => [entry.metadata.name, entry.implementation])
|
|
5341
|
+
);
|
|
5342
|
+
function getNativeToolMetadata(toolName) {
|
|
5343
|
+
return TOOL_METADATA_MAP.get(toolName);
|
|
4521
5344
|
}
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
return {
|
|
4537
|
-
success: false,
|
|
4538
|
-
message: `Unknown action: ${String(action)}`,
|
|
4539
|
-
entries: memoryStore
|
|
4540
|
-
};
|
|
4541
|
-
}
|
|
5345
|
+
function getNativeToolImplementation(toolName) {
|
|
5346
|
+
return TOOL_IMPLEMENTATION_MAP.get(toolName);
|
|
5347
|
+
}
|
|
5348
|
+
function getAllNativeToolMetadata() {
|
|
5349
|
+
return NATIVE_TOOL_ENTRIES.map((entry) => entry.metadata);
|
|
5350
|
+
}
|
|
5351
|
+
function applyMetadataToToolDefinitions(toolDefinitions) {
|
|
5352
|
+
return toolDefinitions.map((definition) => {
|
|
5353
|
+
const toolName = definition.function.name;
|
|
5354
|
+
return {
|
|
5355
|
+
...definition,
|
|
5356
|
+
metadata: getNativeToolMetadata(toolName)
|
|
5357
|
+
};
|
|
5358
|
+
});
|
|
4542
5359
|
}
|
|
4543
5360
|
|
|
4544
5361
|
// src/app/agent/tool_invoker.ts
|
|
4545
5362
|
var ToolInvoker = class {
|
|
4546
|
-
// Mapa privado para associar nomes de ferramentas às suas funções de implementação.
|
|
4547
|
-
toolImplementations;
|
|
4548
5363
|
// Propriedade privada para armazenar as definições de ferramentas carregadas do JSON.
|
|
4549
5364
|
toolDefinitions = [];
|
|
4550
5365
|
constructor() {
|
|
4551
|
-
this.toolImplementations = /* @__PURE__ */ new Map();
|
|
4552
|
-
this.registerTools();
|
|
4553
5366
|
}
|
|
4554
5367
|
/**
|
|
4555
5368
|
* Carrega as definições de ferramentas do arquivo de configuração `native_tools.json`.
|
|
@@ -4558,41 +5371,16 @@ var ToolInvoker = class {
|
|
|
4558
5371
|
async initialize() {
|
|
4559
5372
|
try {
|
|
4560
5373
|
const __filename = fileURLToPath(import.meta.url);
|
|
4561
|
-
const __dirname =
|
|
4562
|
-
const configPath =
|
|
4563
|
-
const fileContent = await
|
|
5374
|
+
const __dirname = path17.dirname(__filename);
|
|
5375
|
+
const configPath = path17.resolve(__dirname, "config", "native_tools.json");
|
|
5376
|
+
const fileContent = await fs14.readFile(configPath, "utf-8");
|
|
4564
5377
|
const config2 = JSON.parse(fileContent);
|
|
4565
|
-
this.toolDefinitions = config2.nativeTools;
|
|
5378
|
+
this.toolDefinitions = applyMetadataToToolDefinitions(config2.nativeTools);
|
|
4566
5379
|
} catch (error) {
|
|
4567
5380
|
console.error("[ToolInvoker] Erro cr\xEDtico ao carregar 'native_tools.json'. As ferramentas nativas n\xE3o estar\xE3o dispon\xEDveis.", error);
|
|
4568
5381
|
this.toolDefinitions = [];
|
|
4569
5382
|
}
|
|
4570
5383
|
}
|
|
4571
|
-
/**
|
|
4572
|
-
* Registra as implementações de todas as ferramentas nativas.
|
|
4573
|
-
* Este método mapeia o nome da ferramenta (string) para a função TypeScript que a executa.
|
|
4574
|
-
*/
|
|
4575
|
-
registerTools() {
|
|
4576
|
-
this.toolImplementations.set("edit_tool", editTool);
|
|
4577
|
-
this.toolImplementations.set("ls_tool", ls);
|
|
4578
|
-
this.toolImplementations.set("count_file_lines", countLines);
|
|
4579
|
-
this.toolImplementations.set("read_file_lines", readLines);
|
|
4580
|
-
this.toolImplementations.set("find_by_name", findByName);
|
|
4581
|
-
this.toolImplementations.set("grep_search", grepSearch);
|
|
4582
|
-
this.toolImplementations.set("view_file_outline", viewFileOutline);
|
|
4583
|
-
this.toolImplementations.set("shell_command", runCommandAsync);
|
|
4584
|
-
this.toolImplementations.set("command_status", commandStatus);
|
|
4585
|
-
this.toolImplementations.set("send_command_input", sendCommandInput);
|
|
4586
|
-
this.toolImplementations.set("kill_command", killCommand);
|
|
4587
|
-
this.toolImplementations.set("message", message);
|
|
4588
|
-
this.toolImplementations.set("todo", todo);
|
|
4589
|
-
this.toolImplementations.set("task_boundary", taskBoundary);
|
|
4590
|
-
this.toolImplementations.set("create_artifact", createArtifact);
|
|
4591
|
-
this.toolImplementations.set("read_artifact", readArtifact);
|
|
4592
|
-
this.toolImplementations.set("search_web", searchWeb);
|
|
4593
|
-
this.toolImplementations.set("load_skill", loadSkill);
|
|
4594
|
-
this.toolImplementations.set("coding_memory", coding_memory);
|
|
4595
|
-
}
|
|
4596
5384
|
/**
|
|
4597
5385
|
* Retorna a lista de definições de todas as ferramentas nativas carregadas.
|
|
4598
5386
|
* O MCPClient usará esta função para obter a lista de ferramentas locais.
|
|
@@ -4600,6 +5388,12 @@ var ToolInvoker = class {
|
|
|
4600
5388
|
getToolDefinitions() {
|
|
4601
5389
|
return this.toolDefinitions;
|
|
4602
5390
|
}
|
|
5391
|
+
getToolMetadata(toolName) {
|
|
5392
|
+
return getNativeToolMetadata(toolName);
|
|
5393
|
+
}
|
|
5394
|
+
getAllToolMetadata() {
|
|
5395
|
+
return getAllNativeToolMetadata();
|
|
5396
|
+
}
|
|
4603
5397
|
/**
|
|
4604
5398
|
* Invoca uma ferramenta nativa pelo nome com os argumentos fornecidos.
|
|
4605
5399
|
* @param toolName O nome da ferramenta a ser invocada.
|
|
@@ -4607,7 +5401,7 @@ var ToolInvoker = class {
|
|
|
4607
5401
|
* @returns O resultado da execução da ferramenta.
|
|
4608
5402
|
*/
|
|
4609
5403
|
async invoke(toolName, args) {
|
|
4610
|
-
const implementation =
|
|
5404
|
+
const implementation = getNativeToolImplementation(toolName);
|
|
4611
5405
|
if (!implementation) {
|
|
4612
5406
|
return { error: `Error: Native tool "${toolName}" not found.` };
|
|
4613
5407
|
}
|
|
@@ -4621,9 +5415,9 @@ var ToolInvoker = class {
|
|
|
4621
5415
|
};
|
|
4622
5416
|
|
|
4623
5417
|
// src/app/agent/tools/mcp/mcp_client.ts
|
|
4624
|
-
import { promises as
|
|
4625
|
-
import
|
|
4626
|
-
import
|
|
5418
|
+
import { promises as fs15 } from "fs";
|
|
5419
|
+
import path18 from "path";
|
|
5420
|
+
import os10 from "os";
|
|
4627
5421
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
4628
5422
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
4629
5423
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
@@ -4650,9 +5444,9 @@ var MCPClient = class {
|
|
|
4650
5444
|
});
|
|
4651
5445
|
}
|
|
4652
5446
|
const __filename = fileURLToPath2(import.meta.url);
|
|
4653
|
-
const __dirname =
|
|
4654
|
-
const defaultConfigPath =
|
|
4655
|
-
const userConfigPath =
|
|
5447
|
+
const __dirname = path18.dirname(__filename);
|
|
5448
|
+
const defaultConfigPath = path18.resolve(__dirname, "config", "bluma-mcp.json");
|
|
5449
|
+
const userConfigPath = path18.join(os10.homedir(), ".bluma", "bluma-mcp.json");
|
|
4656
5450
|
const defaultConfig = await this.loadMcpConfig(defaultConfigPath, "Default");
|
|
4657
5451
|
const userConfig = await this.loadMcpConfig(userConfigPath, "User");
|
|
4658
5452
|
const mergedConfig = {
|
|
@@ -4686,7 +5480,7 @@ var MCPClient = class {
|
|
|
4686
5480
|
}
|
|
4687
5481
|
async loadMcpConfig(configPath, configType) {
|
|
4688
5482
|
try {
|
|
4689
|
-
const fileContent = await
|
|
5483
|
+
const fileContent = await fs15.readFile(configPath, "utf-8");
|
|
4690
5484
|
const processedContent = this.replaceEnvPlaceholders(fileContent);
|
|
4691
5485
|
return JSON.parse(processedContent);
|
|
4692
5486
|
} catch (error) {
|
|
@@ -4705,7 +5499,7 @@ var MCPClient = class {
|
|
|
4705
5499
|
async connectToStdioServer(serverName, config2) {
|
|
4706
5500
|
let commandToExecute = config2.command;
|
|
4707
5501
|
let argsToExecute = config2.args || [];
|
|
4708
|
-
const isWindows =
|
|
5502
|
+
const isWindows = os10.platform() === "win32";
|
|
4709
5503
|
if (!isWindows && commandToExecute.toLowerCase() === "cmd") {
|
|
4710
5504
|
if (argsToExecute.length >= 2 && argsToExecute[0].toLowerCase() === "/c") {
|
|
4711
5505
|
commandToExecute = argsToExecute[1];
|
|
@@ -4770,7 +5564,13 @@ var MCPClient = class {
|
|
|
4770
5564
|
const route = this.toolToServerMap.get(name);
|
|
4771
5565
|
if (!route) continue;
|
|
4772
5566
|
const source = route.server === "native" ? "native" : "mcp";
|
|
4773
|
-
detailed.push({
|
|
5567
|
+
detailed.push({
|
|
5568
|
+
...tool,
|
|
5569
|
+
source,
|
|
5570
|
+
server: route.server,
|
|
5571
|
+
originalName: route.originalName,
|
|
5572
|
+
metadata: source === "native" ? this.nativeToolInvoker.getToolMetadata(route.originalName) : void 0
|
|
5573
|
+
});
|
|
4774
5574
|
}
|
|
4775
5575
|
return detailed;
|
|
4776
5576
|
}
|
|
@@ -4821,13 +5621,13 @@ var AdvancedFeedbackSystem = class {
|
|
|
4821
5621
|
};
|
|
4822
5622
|
|
|
4823
5623
|
// src/app/agent/bluma/core/bluma.ts
|
|
4824
|
-
import
|
|
4825
|
-
import { v4 as
|
|
5624
|
+
import path23 from "path";
|
|
5625
|
+
import { v4 as uuidv44 } from "uuid";
|
|
4826
5626
|
|
|
4827
5627
|
// src/app/agent/session_manager/session_manager.ts
|
|
4828
|
-
import
|
|
4829
|
-
import
|
|
4830
|
-
import { promises as
|
|
5628
|
+
import path19 from "path";
|
|
5629
|
+
import os11 from "os";
|
|
5630
|
+
import { promises as fs16 } from "fs";
|
|
4831
5631
|
var fileLocks = /* @__PURE__ */ new Map();
|
|
4832
5632
|
async function withFileLock(file, fn) {
|
|
4833
5633
|
const prev = fileLocks.get(file) || Promise.resolve();
|
|
@@ -4863,13 +5663,13 @@ function debouncedSave(sessionFile, history, memory) {
|
|
|
4863
5663
|
function expandHome(p) {
|
|
4864
5664
|
if (!p) return p;
|
|
4865
5665
|
if (p.startsWith("~")) {
|
|
4866
|
-
return
|
|
5666
|
+
return path19.join(os11.homedir(), p.slice(1));
|
|
4867
5667
|
}
|
|
4868
5668
|
return p;
|
|
4869
5669
|
}
|
|
4870
5670
|
function getPreferredAppDir() {
|
|
4871
|
-
const fixed =
|
|
4872
|
-
return
|
|
5671
|
+
const fixed = path19.join(os11.homedir(), ".bluma");
|
|
5672
|
+
return path19.resolve(expandHome(fixed));
|
|
4873
5673
|
}
|
|
4874
5674
|
async function safeRenameWithRetry(src, dest, maxRetries = 6) {
|
|
4875
5675
|
let attempt = 0;
|
|
@@ -4877,10 +5677,10 @@ async function safeRenameWithRetry(src, dest, maxRetries = 6) {
|
|
|
4877
5677
|
const isWin = process.platform === "win32";
|
|
4878
5678
|
while (attempt <= maxRetries) {
|
|
4879
5679
|
try {
|
|
4880
|
-
const dir =
|
|
4881
|
-
await
|
|
5680
|
+
const dir = path19.dirname(dest);
|
|
5681
|
+
await fs16.mkdir(dir, { recursive: true }).catch(() => {
|
|
4882
5682
|
});
|
|
4883
|
-
await
|
|
5683
|
+
await fs16.rename(src, dest);
|
|
4884
5684
|
return;
|
|
4885
5685
|
} catch (e) {
|
|
4886
5686
|
lastErr = e;
|
|
@@ -4893,13 +5693,13 @@ async function safeRenameWithRetry(src, dest, maxRetries = 6) {
|
|
|
4893
5693
|
}
|
|
4894
5694
|
}
|
|
4895
5695
|
try {
|
|
4896
|
-
await
|
|
4897
|
-
const data = await
|
|
4898
|
-
const dir =
|
|
4899
|
-
await
|
|
5696
|
+
await fs16.access(src);
|
|
5697
|
+
const data = await fs16.readFile(src);
|
|
5698
|
+
const dir = path19.dirname(dest);
|
|
5699
|
+
await fs16.mkdir(dir, { recursive: true }).catch(() => {
|
|
4900
5700
|
});
|
|
4901
|
-
await
|
|
4902
|
-
await
|
|
5701
|
+
await fs16.writeFile(dest, data);
|
|
5702
|
+
await fs16.unlink(src).catch(() => {
|
|
4903
5703
|
});
|
|
4904
5704
|
return;
|
|
4905
5705
|
} catch (fallbackErr) {
|
|
@@ -4912,16 +5712,16 @@ async function safeRenameWithRetry(src, dest, maxRetries = 6) {
|
|
|
4912
5712
|
}
|
|
4913
5713
|
async function ensureSessionDir() {
|
|
4914
5714
|
const appDir = getPreferredAppDir();
|
|
4915
|
-
const sessionDir =
|
|
4916
|
-
await
|
|
5715
|
+
const sessionDir = path19.join(appDir, "sessions");
|
|
5716
|
+
await fs16.mkdir(sessionDir, { recursive: true });
|
|
4917
5717
|
return sessionDir;
|
|
4918
5718
|
}
|
|
4919
5719
|
async function loadOrcreateSession(sessionId) {
|
|
4920
5720
|
const sessionDir = await ensureSessionDir();
|
|
4921
|
-
const sessionFile =
|
|
5721
|
+
const sessionFile = path19.join(sessionDir, `${sessionId}.json`);
|
|
4922
5722
|
try {
|
|
4923
|
-
await
|
|
4924
|
-
const fileContent = await
|
|
5723
|
+
await fs16.access(sessionFile);
|
|
5724
|
+
const fileContent = await fs16.readFile(sessionFile, "utf-8");
|
|
4925
5725
|
const sessionData = JSON.parse(fileContent);
|
|
4926
5726
|
const memory = {
|
|
4927
5727
|
historyAnchor: sessionData.history_anchor ?? null,
|
|
@@ -4934,7 +5734,7 @@ async function loadOrcreateSession(sessionId) {
|
|
|
4934
5734
|
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4935
5735
|
conversation_history: []
|
|
4936
5736
|
};
|
|
4937
|
-
await
|
|
5737
|
+
await fs16.writeFile(sessionFile, JSON.stringify(newSessionData, null, 2), "utf-8");
|
|
4938
5738
|
const emptyMemory = {
|
|
4939
5739
|
historyAnchor: null,
|
|
4940
5740
|
compressedTurnSliceCount: 0
|
|
@@ -4946,12 +5746,12 @@ async function doSaveSessionHistory(sessionFile, history, memory) {
|
|
|
4946
5746
|
await withFileLock(sessionFile, async () => {
|
|
4947
5747
|
let sessionData;
|
|
4948
5748
|
try {
|
|
4949
|
-
const dir =
|
|
4950
|
-
await
|
|
5749
|
+
const dir = path19.dirname(sessionFile);
|
|
5750
|
+
await fs16.mkdir(dir, { recursive: true });
|
|
4951
5751
|
} catch {
|
|
4952
5752
|
}
|
|
4953
5753
|
try {
|
|
4954
|
-
const fileContent = await
|
|
5754
|
+
const fileContent = await fs16.readFile(sessionFile, "utf-8");
|
|
4955
5755
|
sessionData = JSON.parse(fileContent);
|
|
4956
5756
|
} catch (error) {
|
|
4957
5757
|
const code = error && error.code;
|
|
@@ -4962,14 +5762,14 @@ async function doSaveSessionHistory(sessionFile, history, memory) {
|
|
|
4962
5762
|
console.warn(`An unknown error occurred while reading ${sessionFile}. Re-initializing.`, error);
|
|
4963
5763
|
}
|
|
4964
5764
|
}
|
|
4965
|
-
const sessionId =
|
|
5765
|
+
const sessionId = path19.basename(sessionFile, ".json");
|
|
4966
5766
|
sessionData = {
|
|
4967
5767
|
session_id: sessionId,
|
|
4968
5768
|
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4969
5769
|
conversation_history: []
|
|
4970
5770
|
};
|
|
4971
5771
|
try {
|
|
4972
|
-
await
|
|
5772
|
+
await fs16.writeFile(sessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
|
|
4973
5773
|
} catch {
|
|
4974
5774
|
}
|
|
4975
5775
|
}
|
|
@@ -4985,7 +5785,7 @@ async function doSaveSessionHistory(sessionFile, history, memory) {
|
|
|
4985
5785
|
}
|
|
4986
5786
|
const tempSessionFile = `${sessionFile}.${Date.now()}.tmp`;
|
|
4987
5787
|
try {
|
|
4988
|
-
await
|
|
5788
|
+
await fs16.writeFile(tempSessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
|
|
4989
5789
|
await safeRenameWithRetry(tempSessionFile, sessionFile);
|
|
4990
5790
|
} catch (writeError) {
|
|
4991
5791
|
if (writeError instanceof Error) {
|
|
@@ -4994,7 +5794,7 @@ async function doSaveSessionHistory(sessionFile, history, memory) {
|
|
|
4994
5794
|
console.error(`An unknown fatal error occurred while saving session to ${sessionFile}:`, writeError);
|
|
4995
5795
|
}
|
|
4996
5796
|
try {
|
|
4997
|
-
await
|
|
5797
|
+
await fs16.unlink(tempSessionFile);
|
|
4998
5798
|
} catch {
|
|
4999
5799
|
}
|
|
5000
5800
|
}
|
|
@@ -5011,15 +5811,15 @@ async function saveSessionHistory(sessionFile, history, memory) {
|
|
|
5011
5811
|
}
|
|
5012
5812
|
|
|
5013
5813
|
// src/app/agent/core/prompt/prompt_builder.ts
|
|
5014
|
-
import
|
|
5015
|
-
import
|
|
5016
|
-
import
|
|
5814
|
+
import os13 from "os";
|
|
5815
|
+
import fs19 from "fs";
|
|
5816
|
+
import path22 from "path";
|
|
5017
5817
|
import { execSync as execSync2 } from "child_process";
|
|
5018
5818
|
|
|
5019
5819
|
// src/app/agent/skills/skill_loader.ts
|
|
5020
|
-
import
|
|
5021
|
-
import
|
|
5022
|
-
import
|
|
5820
|
+
import fs17 from "fs";
|
|
5821
|
+
import path20 from "path";
|
|
5822
|
+
import os12 from "os";
|
|
5023
5823
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
5024
5824
|
var SkillLoader = class _SkillLoader {
|
|
5025
5825
|
bundledSkillsDir;
|
|
@@ -5028,8 +5828,8 @@ var SkillLoader = class _SkillLoader {
|
|
|
5028
5828
|
cache = /* @__PURE__ */ new Map();
|
|
5029
5829
|
conflicts = [];
|
|
5030
5830
|
constructor(projectRoot, bundledDir) {
|
|
5031
|
-
this.projectSkillsDir =
|
|
5032
|
-
this.globalSkillsDir =
|
|
5831
|
+
this.projectSkillsDir = path20.join(projectRoot, ".bluma", "skills");
|
|
5832
|
+
this.globalSkillsDir = path20.join(os12.homedir(), ".bluma", "skills");
|
|
5033
5833
|
this.bundledSkillsDir = bundledDir || _SkillLoader.resolveBundledDir();
|
|
5034
5834
|
}
|
|
5035
5835
|
/**
|
|
@@ -5038,48 +5838,48 @@ var SkillLoader = class _SkillLoader {
|
|
|
5038
5838
|
*/
|
|
5039
5839
|
static resolveBundledDir() {
|
|
5040
5840
|
if (process.env.JEST_WORKER_ID !== void 0 || process.env.NODE_ENV === "test") {
|
|
5041
|
-
return
|
|
5841
|
+
return path20.join(process.cwd(), "dist", "config", "skills");
|
|
5042
5842
|
}
|
|
5043
5843
|
const candidates = [];
|
|
5044
5844
|
const push = (p) => {
|
|
5045
|
-
const abs =
|
|
5845
|
+
const abs = path20.resolve(p);
|
|
5046
5846
|
if (!candidates.includes(abs)) {
|
|
5047
5847
|
candidates.push(abs);
|
|
5048
5848
|
}
|
|
5049
5849
|
};
|
|
5050
5850
|
let argvBundled = null;
|
|
5051
5851
|
try {
|
|
5052
|
-
const bundleDir =
|
|
5053
|
-
push(
|
|
5852
|
+
const bundleDir = path20.dirname(fileURLToPath3(import.meta.url));
|
|
5853
|
+
push(path20.join(bundleDir, "config", "skills"));
|
|
5054
5854
|
} catch {
|
|
5055
5855
|
}
|
|
5056
5856
|
const argv1 = process.argv[1];
|
|
5057
5857
|
if (argv1 && !argv1.startsWith("-")) {
|
|
5058
5858
|
try {
|
|
5059
5859
|
let resolved = argv1;
|
|
5060
|
-
if (
|
|
5061
|
-
resolved =
|
|
5062
|
-
} else if (!
|
|
5063
|
-
resolved =
|
|
5860
|
+
if (path20.isAbsolute(argv1) && fs17.existsSync(argv1)) {
|
|
5861
|
+
resolved = fs17.realpathSync(argv1);
|
|
5862
|
+
} else if (!path20.isAbsolute(argv1)) {
|
|
5863
|
+
resolved = path20.resolve(process.cwd(), argv1);
|
|
5064
5864
|
}
|
|
5065
|
-
const scriptDir =
|
|
5066
|
-
argvBundled =
|
|
5865
|
+
const scriptDir = path20.dirname(resolved);
|
|
5866
|
+
argvBundled = path20.join(scriptDir, "config", "skills");
|
|
5067
5867
|
push(argvBundled);
|
|
5068
5868
|
} catch {
|
|
5069
5869
|
}
|
|
5070
5870
|
}
|
|
5071
5871
|
for (const abs of candidates) {
|
|
5072
|
-
if (
|
|
5872
|
+
if (fs17.existsSync(abs)) {
|
|
5073
5873
|
return abs;
|
|
5074
5874
|
}
|
|
5075
5875
|
}
|
|
5076
5876
|
try {
|
|
5077
|
-
return
|
|
5877
|
+
return path20.join(path20.dirname(fileURLToPath3(import.meta.url)), "config", "skills");
|
|
5078
5878
|
} catch {
|
|
5079
5879
|
if (argvBundled) {
|
|
5080
5880
|
return argvBundled;
|
|
5081
5881
|
}
|
|
5082
|
-
return
|
|
5882
|
+
return path20.join(os12.homedir(), ".bluma", "__bundled_skills_unresolved__");
|
|
5083
5883
|
}
|
|
5084
5884
|
}
|
|
5085
5885
|
/**
|
|
@@ -5108,8 +5908,8 @@ var SkillLoader = class _SkillLoader {
|
|
|
5108
5908
|
this.conflicts.push({
|
|
5109
5909
|
name: skill.name,
|
|
5110
5910
|
userSource: source,
|
|
5111
|
-
userPath:
|
|
5112
|
-
bundledPath:
|
|
5911
|
+
userPath: path20.join(dir, skill.name, "SKILL.md"),
|
|
5912
|
+
bundledPath: path20.join(this.bundledSkillsDir, skill.name, "SKILL.md")
|
|
5113
5913
|
});
|
|
5114
5914
|
continue;
|
|
5115
5915
|
}
|
|
@@ -5117,20 +5917,20 @@ var SkillLoader = class _SkillLoader {
|
|
|
5117
5917
|
}
|
|
5118
5918
|
}
|
|
5119
5919
|
listFromDir(dir, source) {
|
|
5120
|
-
if (!
|
|
5920
|
+
if (!fs17.existsSync(dir)) return [];
|
|
5121
5921
|
try {
|
|
5122
|
-
return
|
|
5123
|
-
const fullPath =
|
|
5124
|
-
return
|
|
5125
|
-
}).map((d) => this.loadMetadataFromPath(
|
|
5922
|
+
return fs17.readdirSync(dir).filter((d) => {
|
|
5923
|
+
const fullPath = path20.join(dir, d);
|
|
5924
|
+
return fs17.statSync(fullPath).isDirectory() && fs17.existsSync(path20.join(fullPath, "SKILL.md"));
|
|
5925
|
+
}).map((d) => this.loadMetadataFromPath(path20.join(dir, d, "SKILL.md"), d, source)).filter((m) => m !== null);
|
|
5126
5926
|
} catch {
|
|
5127
5927
|
return [];
|
|
5128
5928
|
}
|
|
5129
5929
|
}
|
|
5130
5930
|
loadMetadataFromPath(skillPath, skillName, source) {
|
|
5131
|
-
if (!
|
|
5931
|
+
if (!fs17.existsSync(skillPath)) return null;
|
|
5132
5932
|
try {
|
|
5133
|
-
const raw =
|
|
5933
|
+
const raw = fs17.readFileSync(skillPath, "utf-8");
|
|
5134
5934
|
const parsed = this.parseFrontmatter(raw);
|
|
5135
5935
|
return {
|
|
5136
5936
|
name: parsed.name || skillName,
|
|
@@ -5152,12 +5952,12 @@ var SkillLoader = class _SkillLoader {
|
|
|
5152
5952
|
*/
|
|
5153
5953
|
load(name) {
|
|
5154
5954
|
if (this.cache.has(name)) return this.cache.get(name);
|
|
5155
|
-
const bundledPath =
|
|
5156
|
-
const projectPath =
|
|
5157
|
-
const globalPath =
|
|
5158
|
-
const existsBundled =
|
|
5159
|
-
const existsProject =
|
|
5160
|
-
const existsGlobal =
|
|
5955
|
+
const bundledPath = path20.join(this.bundledSkillsDir, name, "SKILL.md");
|
|
5956
|
+
const projectPath = path20.join(this.projectSkillsDir, name, "SKILL.md");
|
|
5957
|
+
const globalPath = path20.join(this.globalSkillsDir, name, "SKILL.md");
|
|
5958
|
+
const existsBundled = fs17.existsSync(bundledPath);
|
|
5959
|
+
const existsProject = fs17.existsSync(projectPath);
|
|
5960
|
+
const existsGlobal = fs17.existsSync(globalPath);
|
|
5161
5961
|
if (existsBundled && (existsProject || existsGlobal)) {
|
|
5162
5962
|
const conflictSource = existsProject ? "project" : "global";
|
|
5163
5963
|
const conflictPath = existsProject ? projectPath : globalPath;
|
|
@@ -5196,9 +5996,9 @@ var SkillLoader = class _SkillLoader {
|
|
|
5196
5996
|
}
|
|
5197
5997
|
loadFromPath(skillPath, name, source) {
|
|
5198
5998
|
try {
|
|
5199
|
-
const raw =
|
|
5999
|
+
const raw = fs17.readFileSync(skillPath, "utf-8");
|
|
5200
6000
|
const parsed = this.parseFrontmatter(raw);
|
|
5201
|
-
const skillDir =
|
|
6001
|
+
const skillDir = path20.dirname(skillPath);
|
|
5202
6002
|
return {
|
|
5203
6003
|
name: parsed.name || name,
|
|
5204
6004
|
description: parsed.description || "",
|
|
@@ -5207,22 +6007,22 @@ var SkillLoader = class _SkillLoader {
|
|
|
5207
6007
|
version: parsed.version,
|
|
5208
6008
|
author: parsed.author,
|
|
5209
6009
|
license: parsed.license,
|
|
5210
|
-
references: this.scanAssets(
|
|
5211
|
-
scripts: this.scanAssets(
|
|
6010
|
+
references: this.scanAssets(path20.join(skillDir, "references")),
|
|
6011
|
+
scripts: this.scanAssets(path20.join(skillDir, "scripts"))
|
|
5212
6012
|
};
|
|
5213
6013
|
} catch {
|
|
5214
6014
|
return null;
|
|
5215
6015
|
}
|
|
5216
6016
|
}
|
|
5217
6017
|
scanAssets(dir) {
|
|
5218
|
-
if (!
|
|
6018
|
+
if (!fs17.existsSync(dir)) return [];
|
|
5219
6019
|
try {
|
|
5220
|
-
return
|
|
5221
|
-
const fp =
|
|
5222
|
-
return
|
|
6020
|
+
return fs17.readdirSync(dir).filter((f) => {
|
|
6021
|
+
const fp = path20.join(dir, f);
|
|
6022
|
+
return fs17.statSync(fp).isFile();
|
|
5223
6023
|
}).map((f) => ({
|
|
5224
6024
|
name: f,
|
|
5225
|
-
path:
|
|
6025
|
+
path: path20.resolve(dir, f)
|
|
5226
6026
|
}));
|
|
5227
6027
|
} catch {
|
|
5228
6028
|
return [];
|
|
@@ -5279,10 +6079,10 @@ var SkillLoader = class _SkillLoader {
|
|
|
5279
6079
|
this.cache.clear();
|
|
5280
6080
|
}
|
|
5281
6081
|
exists(name) {
|
|
5282
|
-
const bundledPath =
|
|
5283
|
-
const projectPath =
|
|
5284
|
-
const globalPath =
|
|
5285
|
-
return
|
|
6082
|
+
const bundledPath = path20.join(this.bundledSkillsDir, name, "SKILL.md");
|
|
6083
|
+
const projectPath = path20.join(this.projectSkillsDir, name, "SKILL.md");
|
|
6084
|
+
const globalPath = path20.join(this.globalSkillsDir, name, "SKILL.md");
|
|
6085
|
+
return fs17.existsSync(bundledPath) || fs17.existsSync(projectPath) || fs17.existsSync(globalPath);
|
|
5286
6086
|
}
|
|
5287
6087
|
/**
|
|
5288
6088
|
* Retorna conflitos detetados (skills do utilizador com mesmo nome de nativas).
|
|
@@ -5314,8 +6114,8 @@ var SkillLoader = class _SkillLoader {
|
|
|
5314
6114
|
};
|
|
5315
6115
|
|
|
5316
6116
|
// src/app/agent/core/prompt/workspace_snapshot.ts
|
|
5317
|
-
import
|
|
5318
|
-
import
|
|
6117
|
+
import fs18 from "fs";
|
|
6118
|
+
import path21 from "path";
|
|
5319
6119
|
import { execSync } from "child_process";
|
|
5320
6120
|
var LIMITS = {
|
|
5321
6121
|
readme: 1e4,
|
|
@@ -5330,10 +6130,10 @@ var LIMITS = {
|
|
|
5330
6130
|
};
|
|
5331
6131
|
function safeReadFile(filePath, maxChars) {
|
|
5332
6132
|
try {
|
|
5333
|
-
if (!
|
|
5334
|
-
const st =
|
|
6133
|
+
if (!fs18.existsSync(filePath)) return null;
|
|
6134
|
+
const st = fs18.statSync(filePath);
|
|
5335
6135
|
if (!st.isFile()) return null;
|
|
5336
|
-
const raw =
|
|
6136
|
+
const raw = fs18.readFileSync(filePath, "utf8");
|
|
5337
6137
|
if (raw.length <= maxChars) return raw;
|
|
5338
6138
|
return `${raw.slice(0, maxChars)}
|
|
5339
6139
|
|
|
@@ -5344,7 +6144,7 @@ function safeReadFile(filePath, maxChars) {
|
|
|
5344
6144
|
}
|
|
5345
6145
|
function tryReadReadme(cwd) {
|
|
5346
6146
|
for (const name of ["README.md", "README.MD", "readme.md", "Readme.md"]) {
|
|
5347
|
-
const c = safeReadFile(
|
|
6147
|
+
const c = safeReadFile(path21.join(cwd, name), LIMITS.readme);
|
|
5348
6148
|
if (c) return `(${name})
|
|
5349
6149
|
${c}`;
|
|
5350
6150
|
}
|
|
@@ -5352,14 +6152,14 @@ ${c}`;
|
|
|
5352
6152
|
}
|
|
5353
6153
|
function tryReadBluMaMd(cwd) {
|
|
5354
6154
|
const paths = [
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
6155
|
+
path21.join(cwd, "BluMa.md"),
|
|
6156
|
+
path21.join(cwd, "BLUMA.md"),
|
|
6157
|
+
path21.join(cwd, ".bluma", "BluMa.md")
|
|
5358
6158
|
];
|
|
5359
6159
|
for (const p of paths) {
|
|
5360
6160
|
const c = safeReadFile(p, LIMITS.blumaMd);
|
|
5361
6161
|
if (c) {
|
|
5362
|
-
const rel =
|
|
6162
|
+
const rel = path21.relative(cwd, p) || p;
|
|
5363
6163
|
return `(${rel})
|
|
5364
6164
|
${c}`;
|
|
5365
6165
|
}
|
|
@@ -5367,10 +6167,10 @@ ${c}`;
|
|
|
5367
6167
|
return null;
|
|
5368
6168
|
}
|
|
5369
6169
|
function summarizePackageJson(cwd) {
|
|
5370
|
-
const p =
|
|
6170
|
+
const p = path21.join(cwd, "package.json");
|
|
5371
6171
|
try {
|
|
5372
|
-
if (!
|
|
5373
|
-
const pkg = JSON.parse(
|
|
6172
|
+
if (!fs18.existsSync(p)) return null;
|
|
6173
|
+
const pkg = JSON.parse(fs18.readFileSync(p, "utf8"));
|
|
5374
6174
|
const scripts = pkg.scripts;
|
|
5375
6175
|
let scriptKeys = "";
|
|
5376
6176
|
if (scripts && typeof scripts === "object" && !Array.isArray(scripts)) {
|
|
@@ -5403,7 +6203,7 @@ function summarizePackageJson(cwd) {
|
|
|
5403
6203
|
}
|
|
5404
6204
|
function topLevelListing(cwd) {
|
|
5405
6205
|
try {
|
|
5406
|
-
const names =
|
|
6206
|
+
const names = fs18.readdirSync(cwd, { withFileTypes: true });
|
|
5407
6207
|
const sorted = [...names].sort((a, b) => a.name.localeCompare(b.name));
|
|
5408
6208
|
const limited = sorted.slice(0, LIMITS.topDirEntries);
|
|
5409
6209
|
const lines = limited.map((d) => `${d.name}${d.isDirectory() ? "/" : ""}`);
|
|
@@ -5461,7 +6261,7 @@ function buildWorkspaceSnapshot(cwd) {
|
|
|
5461
6261
|
parts.push(pkg);
|
|
5462
6262
|
parts.push("```\n");
|
|
5463
6263
|
}
|
|
5464
|
-
const py = safeReadFile(
|
|
6264
|
+
const py = safeReadFile(path21.join(cwd, "pyproject.toml"), LIMITS.pyproject);
|
|
5465
6265
|
if (py) {
|
|
5466
6266
|
parts.push("### pyproject.toml (excerpt)\n```toml");
|
|
5467
6267
|
parts.push(py);
|
|
@@ -5479,15 +6279,15 @@ function buildWorkspaceSnapshot(cwd) {
|
|
|
5479
6279
|
parts.push(bluma);
|
|
5480
6280
|
parts.push("```\n");
|
|
5481
6281
|
}
|
|
5482
|
-
const contrib = safeReadFile(
|
|
6282
|
+
const contrib = safeReadFile(path21.join(cwd, "CONTRIBUTING.md"), LIMITS.contributing);
|
|
5483
6283
|
if (contrib) {
|
|
5484
6284
|
parts.push("### CONTRIBUTING.md (excerpt)\n```markdown");
|
|
5485
6285
|
parts.push(contrib);
|
|
5486
6286
|
parts.push("```\n");
|
|
5487
6287
|
}
|
|
5488
|
-
const chlog = safeReadFile(
|
|
6288
|
+
const chlog = safeReadFile(path21.join(cwd, "CHANGELOG.md"), LIMITS.changelog);
|
|
5489
6289
|
if (!chlog) {
|
|
5490
|
-
const alt = safeReadFile(
|
|
6290
|
+
const alt = safeReadFile(path21.join(cwd, "CHANGES.md"), LIMITS.changelog);
|
|
5491
6291
|
if (alt) {
|
|
5492
6292
|
parts.push("### CHANGES.md (excerpt)\n```markdown");
|
|
5493
6293
|
parts.push(alt);
|
|
@@ -5550,10 +6350,10 @@ function getGitBranch(dir) {
|
|
|
5550
6350
|
}
|
|
5551
6351
|
function getPackageManager(dir) {
|
|
5552
6352
|
try {
|
|
5553
|
-
if (
|
|
5554
|
-
if (
|
|
5555
|
-
if (
|
|
5556
|
-
if (
|
|
6353
|
+
if (fs19.existsSync(path22.join(dir, "pnpm-lock.yaml"))) return "pnpm";
|
|
6354
|
+
if (fs19.existsSync(path22.join(dir, "yarn.lock"))) return "yarn";
|
|
6355
|
+
if (fs19.existsSync(path22.join(dir, "bun.lockb"))) return "bun";
|
|
6356
|
+
if (fs19.existsSync(path22.join(dir, "package-lock.json"))) return "npm";
|
|
5557
6357
|
return "unknown";
|
|
5558
6358
|
} catch {
|
|
5559
6359
|
return "unknown";
|
|
@@ -5561,9 +6361,9 @@ function getPackageManager(dir) {
|
|
|
5561
6361
|
}
|
|
5562
6362
|
function getProjectType(dir) {
|
|
5563
6363
|
try {
|
|
5564
|
-
const files =
|
|
6364
|
+
const files = fs19.readdirSync(dir);
|
|
5565
6365
|
if (files.includes("package.json")) {
|
|
5566
|
-
const pkg = JSON.parse(
|
|
6366
|
+
const pkg = JSON.parse(fs19.readFileSync(path22.join(dir, "package.json"), "utf-8"));
|
|
5567
6367
|
if (pkg.dependencies?.next || pkg.devDependencies?.next) return "Next.js";
|
|
5568
6368
|
if (pkg.dependencies?.react || pkg.devDependencies?.react) return "React";
|
|
5569
6369
|
if (pkg.dependencies?.express || pkg.devDependencies?.express) return "Express";
|
|
@@ -5582,9 +6382,9 @@ function getProjectType(dir) {
|
|
|
5582
6382
|
}
|
|
5583
6383
|
function getTestFramework(dir) {
|
|
5584
6384
|
try {
|
|
5585
|
-
const pkgPath =
|
|
5586
|
-
if (
|
|
5587
|
-
const pkg = JSON.parse(
|
|
6385
|
+
const pkgPath = path22.join(dir, "package.json");
|
|
6386
|
+
if (fs19.existsSync(pkgPath)) {
|
|
6387
|
+
const pkg = JSON.parse(fs19.readFileSync(pkgPath, "utf-8"));
|
|
5588
6388
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
5589
6389
|
if (deps.jest) return "jest";
|
|
5590
6390
|
if (deps.vitest) return "vitest";
|
|
@@ -5593,7 +6393,7 @@ function getTestFramework(dir) {
|
|
|
5593
6393
|
if (deps["@playwright/test"]) return "playwright";
|
|
5594
6394
|
if (deps.cypress) return "cypress";
|
|
5595
6395
|
}
|
|
5596
|
-
if (
|
|
6396
|
+
if (fs19.existsSync(path22.join(dir, "pytest.ini")) || fs19.existsSync(path22.join(dir, "conftest.py"))) return "pytest";
|
|
5597
6397
|
return "unknown";
|
|
5598
6398
|
} catch {
|
|
5599
6399
|
return "unknown";
|
|
@@ -5601,9 +6401,9 @@ function getTestFramework(dir) {
|
|
|
5601
6401
|
}
|
|
5602
6402
|
function getTestCommand(dir) {
|
|
5603
6403
|
try {
|
|
5604
|
-
const pkgPath =
|
|
5605
|
-
if (
|
|
5606
|
-
const pkg = JSON.parse(
|
|
6404
|
+
const pkgPath = path22.join(dir, "package.json");
|
|
6405
|
+
if (fs19.existsSync(pkgPath)) {
|
|
6406
|
+
const pkg = JSON.parse(fs19.readFileSync(pkgPath, "utf-8"));
|
|
5607
6407
|
if (pkg.scripts?.test) return `npm test`;
|
|
5608
6408
|
if (pkg.scripts?.["test:unit"]) return `npm run test:unit`;
|
|
5609
6409
|
}
|
|
@@ -5815,6 +6615,12 @@ This is your **long-term scratchpad** (usually \`~/.bluma/coding_memory.json\`).
|
|
|
5815
6615
|
5. **Verify** - Check build, lint, and git status
|
|
5816
6616
|
6. **Summarize** - Report results and any follow-up actions
|
|
5817
6617
|
|
|
6618
|
+
### For delegated / parallel work:
|
|
6619
|
+
1. **Keep the blocking task local** - Do not delegate the very next thing you need.
|
|
6620
|
+
2. **Spawn bounded workers** - Use \`spawn_agent\` only for concrete side tasks with a clear output.
|
|
6621
|
+
3. **Track workers explicitly** - Use \`wait_agent\` when blocked on a delegated result; use \`list_agents\` to inspect worker state.
|
|
6622
|
+
4. **Integrate evidence** - Treat worker results like any other tool output: verify before claiming success.
|
|
6623
|
+
|
|
5818
6624
|
### For debugging / incidents (follow \`<engineering_mindset>\`):
|
|
5819
6625
|
1. **Reproduce** \u2014 run the same command or test the user (or the repo) uses; capture full output via \`command_status\`.
|
|
5820
6626
|
2. **Localise** \u2014 trace to a specific file/line; read that code with tools before changing anything.
|
|
@@ -5844,6 +6650,7 @@ Run tests when modifying code. If a testing skill is listed in available_skills,
|
|
|
5844
6650
|
- **For edit_tool**: Provide exact content with correct whitespace (read first!)
|
|
5845
6651
|
- **Truncated CLI preview** (user may press Ctrl+O for more lines): still not a substitute for \`read_file_lines\` \u2014 use the tool for authoritative content before editing
|
|
5846
6652
|
- **Check file exists** before attempting edits
|
|
6653
|
+
- **Delegate only bounded work** - If you use \`spawn_agent\`, give the worker one concrete subtask and later collect it with \`wait_agent\`
|
|
5847
6654
|
|
|
5848
6655
|
### Safe Auto-Approved Tools (no confirmation needed):
|
|
5849
6656
|
- message
|
|
@@ -5851,10 +6658,13 @@ Run tests when modifying code. If a testing skill is listed in available_skills,
|
|
|
5851
6658
|
- read_file_lines
|
|
5852
6659
|
- count_file_lines
|
|
5853
6660
|
- todo
|
|
6661
|
+
- wait_agent
|
|
6662
|
+
- list_agents
|
|
5854
6663
|
|
|
5855
6664
|
### Require Confirmation:
|
|
5856
6665
|
- shell_command (except safe commands)
|
|
5857
6666
|
- edit_tool (always shows diff preview)
|
|
6667
|
+
- spawn_agent (outside sandbox)
|
|
5858
6668
|
</tool_rules>
|
|
5859
6669
|
|
|
5860
6670
|
---
|
|
@@ -6054,18 +6864,20 @@ You are NOT talking directly to a human; all inputs come from JSON payloads prov
|
|
|
6054
6864
|
- ALL outputs must be deterministic, concise and structured for machine parsing.
|
|
6055
6865
|
- You own this workspace like a senior developer owns their machine: produce, deliver, clean up.
|
|
6056
6866
|
|
|
6057
|
-
### Execution Capabilities (
|
|
6867
|
+
### Execution Capabilities (Workspace-first)
|
|
6058
6868
|
|
|
6059
6869
|
You are allowed to:
|
|
6060
|
-
-
|
|
6061
|
-
-
|
|
6062
|
-
- Use
|
|
6870
|
+
- Read, create, edit and overwrite files INSIDE the job workspace.
|
|
6871
|
+
- Use \`shell_command\` for non-interactive build, test, conversion and packaging workflows.
|
|
6872
|
+
- Use language/toolchain commands that are relevant to the repo or job (Python, Node, npm, bun, uv, pytest, etc.) when they are available in the sandbox image.
|
|
6873
|
+
- Fetch exact remote pages with \`web_fetch\` and search external sources with \`search_web\` when the task needs it.
|
|
6874
|
+
- Produce deliverables directly inside the workspace and stage final outputs in \`./artifacts/\`.
|
|
6063
6875
|
|
|
6064
6876
|
You are NOT allowed to:
|
|
6065
|
-
-
|
|
6066
|
-
-
|
|
6067
|
-
-
|
|
6068
|
-
-
|
|
6877
|
+
- Escape the workspace root or assume access to the host machine outside the sandbox.
|
|
6878
|
+
- Change host-level system configuration, users, permissions, mounts or network policy.
|
|
6879
|
+
- Use interactive terminal applications or flows that require human stdin.
|
|
6880
|
+
- Expose secrets, tokens, or environment dumps.
|
|
6069
6881
|
|
|
6070
6882
|
### File Lifecycle in Sandbox (CRITICAL)
|
|
6071
6883
|
|
|
@@ -6073,8 +6885,8 @@ You are working in an **isolated job workspace**. Treat it as your personal deve
|
|
|
6073
6885
|
Follow this workflow for every task that produces deliverables:
|
|
6074
6886
|
|
|
6075
6887
|
**Step 1 \u2014 Analyse** the request and plan what files you need to generate.
|
|
6076
|
-
**Step 2 \u2014
|
|
6077
|
-
**Step 3 \u2014 Execute the
|
|
6888
|
+
**Step 2 \u2014 Create or modify workspace files** needed for the job (scripts, templates, configs, source files, etc.).
|
|
6889
|
+
**Step 3 \u2014 Execute the workflow** via tools (\`shell_command\`, \`file_write\`, \`edit_tool\`, etc.).
|
|
6078
6890
|
**Step 4 \u2014 Move or create final documents** inside \`./artifacts/\` directory.
|
|
6079
6891
|
**Step 5 \u2014 Attach deliverables** \u2014 In your final \`message\` tool call (\`message_type: "result"\`), include the **absolute paths** of every deliverable file in the \`attachments\` array.
|
|
6080
6892
|
**Step 6 \u2014 Clean up** \u2014 Delete all temporary scripts, intermediate files and working data that are NOT final artifacts.
|
|
@@ -6128,9 +6940,9 @@ You MUST treat all environment variables, API keys, tokens and credentials as **
|
|
|
6128
6940
|
|
|
6129
6941
|
### Summary
|
|
6130
6942
|
|
|
6131
|
-
In sandbox mode you are a
|
|
6943
|
+
In sandbox mode you are a workspace-focused, non-interactive, deterministic agent that:
|
|
6132
6944
|
1. Analyses the job request.
|
|
6133
|
-
2.
|
|
6945
|
+
2. Uses the workspace and tools autonomously to produce deliverables.
|
|
6134
6946
|
3. Places all final documents in \`./artifacts/\` and lists them in \`attachments[]\`.
|
|
6135
6947
|
4. Cleans up all temporary files.
|
|
6136
6948
|
5. NEVER reveals environment variables, secrets, or internal infrastructure details.
|
|
@@ -6139,12 +6951,12 @@ In sandbox mode you are a Python-focused, non-interactive, deterministic agent t
|
|
|
6139
6951
|
function getUnifiedSystemPrompt(availableSkills) {
|
|
6140
6952
|
const cwd = process.cwd();
|
|
6141
6953
|
const env = {
|
|
6142
|
-
os_type:
|
|
6143
|
-
os_version:
|
|
6144
|
-
architecture:
|
|
6954
|
+
os_type: os13.type(),
|
|
6955
|
+
os_version: os13.release(),
|
|
6956
|
+
architecture: os13.arch(),
|
|
6145
6957
|
workdir: cwd,
|
|
6146
6958
|
shell_type: process.env.SHELL || process.env.COMSPEC || "unknown",
|
|
6147
|
-
username:
|
|
6959
|
+
username: os13.userInfo().username,
|
|
6148
6960
|
current_date: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
|
|
6149
6961
|
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
6150
6962
|
is_git_repo: isGitRepo(cwd) ? "yes" : "no",
|
|
@@ -6333,8 +7145,8 @@ ${memorySnapshot.trim().length > 0 ? memorySnapshot : "(No entries yet. Use codi
|
|
|
6333
7145
|
}
|
|
6334
7146
|
function isGitRepo(dir) {
|
|
6335
7147
|
try {
|
|
6336
|
-
const gitPath =
|
|
6337
|
-
return
|
|
7148
|
+
const gitPath = path22.join(dir, ".git");
|
|
7149
|
+
return fs19.existsSync(gitPath) && fs19.lstatSync(gitPath).isDirectory();
|
|
6338
7150
|
} catch {
|
|
6339
7151
|
return false;
|
|
6340
7152
|
}
|
|
@@ -6602,7 +7414,7 @@ async function createApiContextWindow(fullHistory, currentAnchor, compressedTurn
|
|
|
6602
7414
|
}
|
|
6603
7415
|
|
|
6604
7416
|
// src/app/agent/core/llm/llm.ts
|
|
6605
|
-
import
|
|
7417
|
+
import os14 from "os";
|
|
6606
7418
|
import OpenAI from "openai";
|
|
6607
7419
|
function defaultBlumaUserContextInput(sessionId, userMessage) {
|
|
6608
7420
|
const msg = String(userMessage || "").slice(0, 300);
|
|
@@ -6619,7 +7431,7 @@ function defaultBlumaUserContextInput(sessionId, userMessage) {
|
|
|
6619
7431
|
}
|
|
6620
7432
|
function getPreferredMacAddress() {
|
|
6621
7433
|
try {
|
|
6622
|
-
const ifaces =
|
|
7434
|
+
const ifaces = os14.networkInterfaces();
|
|
6623
7435
|
for (const name of Object.keys(ifaces)) {
|
|
6624
7436
|
const addrs = ifaces[name];
|
|
6625
7437
|
if (!addrs) continue;
|
|
@@ -6634,7 +7446,7 @@ function getPreferredMacAddress() {
|
|
|
6634
7446
|
} catch {
|
|
6635
7447
|
}
|
|
6636
7448
|
try {
|
|
6637
|
-
return `host:${
|
|
7449
|
+
return `host:${os14.hostname()}`;
|
|
6638
7450
|
} catch {
|
|
6639
7451
|
return "unknown";
|
|
6640
7452
|
}
|
|
@@ -6644,7 +7456,7 @@ function defaultInteractiveCliUserContextInput(sessionId, userMessage) {
|
|
|
6644
7456
|
const machineId = getPreferredMacAddress();
|
|
6645
7457
|
let userName = null;
|
|
6646
7458
|
try {
|
|
6647
|
-
userName =
|
|
7459
|
+
userName = os14.userInfo().username || null;
|
|
6648
7460
|
} catch {
|
|
6649
7461
|
userName = null;
|
|
6650
7462
|
}
|
|
@@ -6971,6 +7783,29 @@ var ToolCallNormalizer = class {
|
|
|
6971
7783
|
}
|
|
6972
7784
|
};
|
|
6973
7785
|
|
|
7786
|
+
// src/app/agent/runtime/tool_execution_policy.ts
|
|
7787
|
+
init_sandbox_policy();
|
|
7788
|
+
function decideToolExecution(toolName) {
|
|
7789
|
+
const policy = getSandboxPolicy();
|
|
7790
|
+
const metadata = getNativeToolMetadata(toolName);
|
|
7791
|
+
if (!metadata) {
|
|
7792
|
+
return {
|
|
7793
|
+
toolName,
|
|
7794
|
+
autoApprove: false,
|
|
7795
|
+
requiresConfirmation: true,
|
|
7796
|
+
reason: "Unknown tool metadata; require confirmation by default."
|
|
7797
|
+
};
|
|
7798
|
+
}
|
|
7799
|
+
const autoApprove = policy.isSandbox ? metadata.autoApproveInSandbox : metadata.autoApproveInLocal;
|
|
7800
|
+
return {
|
|
7801
|
+
toolName,
|
|
7802
|
+
metadata,
|
|
7803
|
+
autoApprove,
|
|
7804
|
+
requiresConfirmation: !autoApprove,
|
|
7805
|
+
reason: autoApprove ? policy.isSandbox ? "Tool auto-approved inside workspace sandbox." : "Tool marked safe for local autonomous execution." : "Tool requires confirmation outside sandbox mode."
|
|
7806
|
+
};
|
|
7807
|
+
}
|
|
7808
|
+
|
|
6974
7809
|
// src/app/agent/bluma/core/bluma.ts
|
|
6975
7810
|
var BluMaAgent = class {
|
|
6976
7811
|
llm;
|
|
@@ -7092,7 +7927,7 @@ var BluMaAgent = class {
|
|
|
7092
7927
|
this.isInterrupted = false;
|
|
7093
7928
|
this.factorRouterTurnClosed = false;
|
|
7094
7929
|
const inputText = String(userInput.content || "").trim();
|
|
7095
|
-
const turnId =
|
|
7930
|
+
const turnId = uuidv44();
|
|
7096
7931
|
this.activeTurnContext = {
|
|
7097
7932
|
...userContextInput,
|
|
7098
7933
|
turnId,
|
|
@@ -7178,7 +8013,8 @@ var BluMaAgent = class {
|
|
|
7178
8013
|
type: "tool_call",
|
|
7179
8014
|
tool_name: toolName,
|
|
7180
8015
|
arguments: toolArgs,
|
|
7181
|
-
preview: previewContent
|
|
8016
|
+
preview: previewContent,
|
|
8017
|
+
tool_policy: decideToolExecution(toolName)
|
|
7182
8018
|
});
|
|
7183
8019
|
try {
|
|
7184
8020
|
if (this.isInterrupted) {
|
|
@@ -7252,7 +8088,7 @@ var BluMaAgent = class {
|
|
|
7252
8088
|
|
|
7253
8089
|
${editData.error.display}`;
|
|
7254
8090
|
}
|
|
7255
|
-
const filename =
|
|
8091
|
+
const filename = path23.basename(toolArgs.file_path);
|
|
7256
8092
|
return createDiff(filename, editData.currentContent || "", editData.newContent);
|
|
7257
8093
|
} catch (e) {
|
|
7258
8094
|
return `An unexpected error occurred while generating the edit preview: ${e.message}`;
|
|
@@ -7379,29 +8215,27 @@ ${editData.error.display}`;
|
|
|
7379
8215
|
await this._continueConversation();
|
|
7380
8216
|
return;
|
|
7381
8217
|
}
|
|
7382
|
-
const isSandbox = process.env.BLUMA_SANDBOX === "true";
|
|
7383
|
-
const autoApprovedTools = [
|
|
7384
|
-
"message",
|
|
7385
|
-
"ls_tool",
|
|
7386
|
-
"count_file_lines",
|
|
7387
|
-
"read_file_lines",
|
|
7388
|
-
"todo",
|
|
7389
|
-
"load_skill",
|
|
7390
|
-
"search_web",
|
|
7391
|
-
"coding_memory"
|
|
7392
|
-
];
|
|
7393
8218
|
const toolToCall = validToolCalls[0];
|
|
7394
|
-
const
|
|
7395
|
-
if (
|
|
8219
|
+
const decision = decideToolExecution(toolToCall.function.name);
|
|
8220
|
+
if (decision.autoApprove) {
|
|
7396
8221
|
await this.handleToolResponse({ type: "user_decision_execute", tool_calls: validToolCalls });
|
|
7397
8222
|
} else {
|
|
7398
8223
|
const toolName = toolToCall.function.name;
|
|
7399
8224
|
if (toolName === "edit_tool") {
|
|
7400
8225
|
const args = JSON.parse(toolToCall.function.arguments);
|
|
7401
8226
|
const previewContent = await this._generateEditPreview(args);
|
|
7402
|
-
this.eventBus.emit("backend_message", {
|
|
8227
|
+
this.eventBus.emit("backend_message", {
|
|
8228
|
+
type: "confirmation_request",
|
|
8229
|
+
tool_calls: validToolCalls,
|
|
8230
|
+
preview: previewContent,
|
|
8231
|
+
tool_policy: decision
|
|
8232
|
+
});
|
|
7403
8233
|
} else {
|
|
7404
|
-
this.eventBus.emit("backend_message", {
|
|
8234
|
+
this.eventBus.emit("backend_message", {
|
|
8235
|
+
type: "confirmation_request",
|
|
8236
|
+
tool_calls: validToolCalls,
|
|
8237
|
+
tool_policy: decision
|
|
8238
|
+
});
|
|
7405
8239
|
}
|
|
7406
8240
|
}
|
|
7407
8241
|
} else if (trimmedText) {
|
|
@@ -7451,29 +8285,27 @@ ${editData.error.display}`;
|
|
|
7451
8285
|
await this._continueConversation();
|
|
7452
8286
|
return;
|
|
7453
8287
|
}
|
|
7454
|
-
const isSandbox = process.env.BLUMA_SANDBOX === "true";
|
|
7455
|
-
const autoApprovedTools = [
|
|
7456
|
-
"message",
|
|
7457
|
-
"ls_tool",
|
|
7458
|
-
"count_file_lines",
|
|
7459
|
-
"read_file_lines",
|
|
7460
|
-
"todo",
|
|
7461
|
-
"load_skill",
|
|
7462
|
-
"search_web",
|
|
7463
|
-
"coding_memory"
|
|
7464
|
-
];
|
|
7465
8288
|
const toolToCall = validToolCalls[0];
|
|
7466
|
-
const
|
|
7467
|
-
if (
|
|
8289
|
+
const decision = decideToolExecution(toolToCall.function.name);
|
|
8290
|
+
if (decision.autoApprove) {
|
|
7468
8291
|
await this.handleToolResponse({ type: "user_decision_execute", tool_calls: validToolCalls });
|
|
7469
8292
|
} else {
|
|
7470
8293
|
const toolName = toolToCall.function.name;
|
|
7471
8294
|
if (toolName === "edit_tool") {
|
|
7472
8295
|
const args = JSON.parse(toolToCall.function.arguments);
|
|
7473
8296
|
const previewContent = await this._generateEditPreview(args);
|
|
7474
|
-
this.eventBus.emit("backend_message", {
|
|
8297
|
+
this.eventBus.emit("backend_message", {
|
|
8298
|
+
type: "confirmation_request",
|
|
8299
|
+
tool_calls: validToolCalls,
|
|
8300
|
+
preview: previewContent,
|
|
8301
|
+
tool_policy: decision
|
|
8302
|
+
});
|
|
7475
8303
|
} else {
|
|
7476
|
-
this.eventBus.emit("backend_message", {
|
|
8304
|
+
this.eventBus.emit("backend_message", {
|
|
8305
|
+
type: "confirmation_request",
|
|
8306
|
+
tool_calls: validToolCalls,
|
|
8307
|
+
tool_policy: decision
|
|
8308
|
+
});
|
|
7477
8309
|
}
|
|
7478
8310
|
}
|
|
7479
8311
|
} else if (typeof message2.content === "string" && message2.content.trim()) {
|
|
@@ -7504,13 +8336,13 @@ function getSubAgentByCommand(cmd) {
|
|
|
7504
8336
|
}
|
|
7505
8337
|
|
|
7506
8338
|
// src/app/agent/subagents/init/init_subagent.ts
|
|
7507
|
-
import { v4 as
|
|
8339
|
+
import { v4 as uuidv46 } from "uuid";
|
|
7508
8340
|
|
|
7509
8341
|
// src/app/agent/subagents/base_llm_subagent.ts
|
|
7510
|
-
import { v4 as
|
|
8342
|
+
import { v4 as uuidv45 } from "uuid";
|
|
7511
8343
|
|
|
7512
8344
|
// src/app/agent/subagents/init/init_system_prompt.ts
|
|
7513
|
-
import
|
|
8345
|
+
import os15 from "os";
|
|
7514
8346
|
var SYSTEM_PROMPT2 = `
|
|
7515
8347
|
|
|
7516
8348
|
### YOU ARE BluMa CLI \u2014 INIT SUBAGENT \u2014 AUTONOMOUS SENIOR SOFTWARE ENGINEER @ NOMADENGENUITY
|
|
@@ -7673,12 +8505,12 @@ Rule Summary:
|
|
|
7673
8505
|
function getInitPrompt() {
|
|
7674
8506
|
const now = /* @__PURE__ */ new Date();
|
|
7675
8507
|
const collectedData = {
|
|
7676
|
-
os_type:
|
|
7677
|
-
os_version:
|
|
7678
|
-
architecture:
|
|
8508
|
+
os_type: os15.type(),
|
|
8509
|
+
os_version: os15.release(),
|
|
8510
|
+
architecture: os15.arch(),
|
|
7679
8511
|
workdir: process.cwd(),
|
|
7680
8512
|
shell_type: process.env.SHELL || process.env.COMSPEC || "Unknown",
|
|
7681
|
-
username:
|
|
8513
|
+
username: os15.userInfo().username || "Unknown",
|
|
7682
8514
|
current_date: now.toISOString().split("T")[0],
|
|
7683
8515
|
// Formato YYYY-MM-DD
|
|
7684
8516
|
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || "Unknown",
|
|
@@ -7723,7 +8555,7 @@ var BaseLLMSubAgent = class {
|
|
|
7723
8555
|
await this.initializeHistory();
|
|
7724
8556
|
const rawUser = typeof input === "string" ? input : JSON.stringify(input);
|
|
7725
8557
|
const base = ctx.blumaUserContextInput ?? defaultBlumaUserContextInput(`subagent:${this.id}`, rawUser.slice(0, 300));
|
|
7726
|
-
const turnId =
|
|
8558
|
+
const turnId = uuidv45();
|
|
7727
8559
|
this.subagentTurnContext = {
|
|
7728
8560
|
...base,
|
|
7729
8561
|
turnId,
|
|
@@ -7784,6 +8616,14 @@ ${editData.error.display}`;
|
|
|
7784
8616
|
const message2 = response.choices[0].message;
|
|
7785
8617
|
this.history.push(message2);
|
|
7786
8618
|
if (message2.tool_calls) {
|
|
8619
|
+
const decision = decideToolExecution(message2.tool_calls[0].function.name);
|
|
8620
|
+
if (!decision.autoApprove) {
|
|
8621
|
+
this.emitEvent("error", {
|
|
8622
|
+
message: `Subagent tool "${message2.tool_calls[0].function.name}" requires confirmation outside sandbox mode.`
|
|
8623
|
+
});
|
|
8624
|
+
this.emitEvent("done", { status: "blocked_confirmation" });
|
|
8625
|
+
return;
|
|
8626
|
+
}
|
|
7787
8627
|
await this._handleToolExecution({ type: "user_decision_execute", tool_calls: message2.tool_calls });
|
|
7788
8628
|
const lastToolName = message2.tool_calls[0].function.name;
|
|
7789
8629
|
if (!lastToolName.includes("agent_end_turn") && !this.isInterrupted) {
|
|
@@ -7822,7 +8662,8 @@ ${editData.error.display}`;
|
|
|
7822
8662
|
this.emitEvent("tool_call", {
|
|
7823
8663
|
tool_name: toolName,
|
|
7824
8664
|
arguments: toolArgs,
|
|
7825
|
-
preview: previewContent
|
|
8665
|
+
preview: previewContent,
|
|
8666
|
+
tool_policy: decideToolExecution(toolName)
|
|
7826
8667
|
});
|
|
7827
8668
|
try {
|
|
7828
8669
|
if (this.isInterrupted) {
|
|
@@ -7856,7 +8697,7 @@ ${editData.error.display}`;
|
|
|
7856
8697
|
|
|
7857
8698
|
// src/app/agent/subagents/init/init_subagent.ts
|
|
7858
8699
|
var InitAgentImpl = class extends BaseLLMSubAgent {
|
|
7859
|
-
id =
|
|
8700
|
+
id = "init";
|
|
7860
8701
|
capabilities = ["/init"];
|
|
7861
8702
|
async execute(input, ctx) {
|
|
7862
8703
|
this.ctx = ctx;
|
|
@@ -7869,7 +8710,7 @@ var InitAgentImpl = class extends BaseLLMSubAgent {
|
|
|
7869
8710
|
const base = ctx.blumaUserContextInput ?? defaultBlumaUserContextInput(`subagent:${this.id}`, preview);
|
|
7870
8711
|
this.subagentTurnContext = {
|
|
7871
8712
|
...base,
|
|
7872
|
-
turnId:
|
|
8713
|
+
turnId: uuidv46(),
|
|
7873
8714
|
sessionId: base.sessionId || `subagent:${this.id}`
|
|
7874
8715
|
};
|
|
7875
8716
|
const seed = `
|
|
@@ -7879,7 +8720,11 @@ var InitAgentImpl = class extends BaseLLMSubAgent {
|
|
|
7879
8720
|
Use only evidence gathered via tools; do not invent content.
|
|
7880
8721
|
If overwriting an existing BluMa.md is required, follow non-destructive policies and request confirmation as per protocol.
|
|
7881
8722
|
`;
|
|
7882
|
-
const
|
|
8723
|
+
const initialInput = typeof input === "string" ? input.trim() : JSON.stringify(input ?? "").trim();
|
|
8724
|
+
const combined = initialInput ? `${seed}
|
|
8725
|
+
|
|
8726
|
+
User request for init:
|
|
8727
|
+
${initialInput}` : seed;
|
|
7883
8728
|
this.history.push({ role: "user", content: combined });
|
|
7884
8729
|
await this._continueConversation();
|
|
7885
8730
|
return { history: this.history };
|
|
@@ -7959,14 +8804,14 @@ var RouteManager = class {
|
|
|
7959
8804
|
this.subAgents = subAgents;
|
|
7960
8805
|
this.core = core;
|
|
7961
8806
|
}
|
|
7962
|
-
registerRoute(
|
|
7963
|
-
this.routeHandlers.set(
|
|
8807
|
+
registerRoute(path27, handler) {
|
|
8808
|
+
this.routeHandlers.set(path27, handler);
|
|
7964
8809
|
}
|
|
7965
8810
|
async handleRoute(payload) {
|
|
7966
8811
|
const inputText = String(payload.content || "").trim();
|
|
7967
8812
|
const { userContext } = payload;
|
|
7968
|
-
for (const [
|
|
7969
|
-
if (inputText ===
|
|
8813
|
+
for (const [path27, handler] of this.routeHandlers) {
|
|
8814
|
+
if (inputText === path27 || inputText.startsWith(`${path27} `)) {
|
|
7970
8815
|
return handler({ content: inputText, userContext });
|
|
7971
8816
|
}
|
|
7972
8817
|
}
|
|
@@ -7975,7 +8820,7 @@ var RouteManager = class {
|
|
|
7975
8820
|
};
|
|
7976
8821
|
|
|
7977
8822
|
// src/app/agent/agent.ts
|
|
7978
|
-
var globalEnvPath =
|
|
8823
|
+
var globalEnvPath = path24.join(os16.homedir(), ".bluma", ".env");
|
|
7979
8824
|
dotenv.config({ path: globalEnvPath });
|
|
7980
8825
|
var Agent = class {
|
|
7981
8826
|
sessionId;
|
|
@@ -8163,7 +9008,7 @@ var WorkingTimer = memo5(WorkingTimerComponent);
|
|
|
8163
9008
|
|
|
8164
9009
|
// src/app/ui/components/ToolCallDisplay.tsx
|
|
8165
9010
|
import { memo as memo6 } from "react";
|
|
8166
|
-
import { Box as Box10 } from "ink";
|
|
9011
|
+
import { Box as Box10, Text as Text10 } from "ink";
|
|
8167
9012
|
|
|
8168
9013
|
// src/app/ui/components/toolCallRenderers.tsx
|
|
8169
9014
|
import { Box as Box9, Text as Text9 } from "ink";
|
|
@@ -8199,12 +9044,12 @@ var renderShellCommand2 = ({ args }) => {
|
|
|
8199
9044
|
};
|
|
8200
9045
|
var renderLsTool2 = ({ args }) => {
|
|
8201
9046
|
const parsed = parseArgs(args);
|
|
8202
|
-
const
|
|
9047
|
+
const path27 = parsed.directory_path || ".";
|
|
8203
9048
|
return /* @__PURE__ */ jsxs9(Box9, { children: [
|
|
8204
9049
|
/* @__PURE__ */ jsx9(Text9, { color: BLUMA_TERMINAL.brandBlue, bold: true, children: "ls" }),
|
|
8205
9050
|
/* @__PURE__ */ jsxs9(Text9, { dimColor: true, children: [
|
|
8206
9051
|
" ",
|
|
8207
|
-
|
|
9052
|
+
path27
|
|
8208
9053
|
] })
|
|
8209
9054
|
] });
|
|
8210
9055
|
};
|
|
@@ -8239,6 +9084,22 @@ var renderReadFileLines2 = ({ args }) => {
|
|
|
8239
9084
|
] })
|
|
8240
9085
|
] });
|
|
8241
9086
|
};
|
|
9087
|
+
var renderFileWrite = ({ args }) => {
|
|
9088
|
+
const parsed = parseArgs(args);
|
|
9089
|
+
const filepath = parsed.filepath || "[no file]";
|
|
9090
|
+
const content = typeof parsed.content === "string" ? parsed.content : "";
|
|
9091
|
+
const preview = content.split("\n").slice(0, 3).join(" \xB7 ");
|
|
9092
|
+
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
|
|
9093
|
+
/* @__PURE__ */ jsxs9(Box9, { children: [
|
|
9094
|
+
/* @__PURE__ */ jsx9(Text9, { color: BLUMA_TERMINAL.brandMagenta, bold: true, children: "write" }),
|
|
9095
|
+
/* @__PURE__ */ jsxs9(Text9, { dimColor: true, children: [
|
|
9096
|
+
" ",
|
|
9097
|
+
getBasename(filepath)
|
|
9098
|
+
] })
|
|
9099
|
+
] }),
|
|
9100
|
+
preview ? /* @__PURE__ */ jsx9(Box9, { paddingLeft: 2, children: /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: truncate(preview, 80) }) }) : null
|
|
9101
|
+
] });
|
|
9102
|
+
};
|
|
8242
9103
|
var renderBlumaNotebook = ({ args }) => {
|
|
8243
9104
|
const parsed = parseArgs(args);
|
|
8244
9105
|
const thought = parsed.thought || parsed.content?.thought || "[thinking...]";
|
|
@@ -8340,7 +9201,7 @@ var renderFindByName = ({ args }) => {
|
|
|
8340
9201
|
var renderGrepSearch = ({ args }) => {
|
|
8341
9202
|
const parsed = parseArgs(args);
|
|
8342
9203
|
const query = parsed.query || "";
|
|
8343
|
-
const
|
|
9204
|
+
const path27 = parsed.path || ".";
|
|
8344
9205
|
return /* @__PURE__ */ jsxs9(Box9, { children: [
|
|
8345
9206
|
/* @__PURE__ */ jsx9(Text9, { color: BLUMA_TERMINAL.brandBlue, bold: true, children: "grep" }),
|
|
8346
9207
|
/* @__PURE__ */ jsxs9(Text9, { color: BLUMA_TERMINAL.brandMagenta, children: [
|
|
@@ -8350,7 +9211,7 @@ var renderGrepSearch = ({ args }) => {
|
|
|
8350
9211
|
] }),
|
|
8351
9212
|
/* @__PURE__ */ jsxs9(Text9, { dimColor: true, children: [
|
|
8352
9213
|
" ",
|
|
8353
|
-
|
|
9214
|
+
path27
|
|
8354
9215
|
] })
|
|
8355
9216
|
] });
|
|
8356
9217
|
};
|
|
@@ -8376,6 +9237,54 @@ var renderCommandStatus = ({ args }) => {
|
|
|
8376
9237
|
] })
|
|
8377
9238
|
] });
|
|
8378
9239
|
};
|
|
9240
|
+
var renderWebFetch = ({ args }) => {
|
|
9241
|
+
const parsed = parseArgs(args);
|
|
9242
|
+
const url = parsed.url || "[no url]";
|
|
9243
|
+
return /* @__PURE__ */ jsxs9(Box9, { children: [
|
|
9244
|
+
/* @__PURE__ */ jsx9(Text9, { color: BLUMA_TERMINAL.brandBlue, bold: true, children: "fetch" }),
|
|
9245
|
+
/* @__PURE__ */ jsxs9(Text9, { dimColor: true, children: [
|
|
9246
|
+
" ",
|
|
9247
|
+
truncate(url, 70)
|
|
9248
|
+
] })
|
|
9249
|
+
] });
|
|
9250
|
+
};
|
|
9251
|
+
var renderSpawnAgent = ({ args }) => {
|
|
9252
|
+
const parsed = parseArgs(args);
|
|
9253
|
+
const title = parsed.title || parsed.agent_type || "worker";
|
|
9254
|
+
const task = parsed.task || "[no task]";
|
|
9255
|
+
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
|
|
9256
|
+
/* @__PURE__ */ jsxs9(Box9, { children: [
|
|
9257
|
+
/* @__PURE__ */ jsx9(Text9, { color: BLUMA_TERMINAL.brandMagenta, bold: true, children: "spawn" }),
|
|
9258
|
+
/* @__PURE__ */ jsxs9(Text9, { dimColor: true, children: [
|
|
9259
|
+
" ",
|
|
9260
|
+
title
|
|
9261
|
+
] })
|
|
9262
|
+
] }),
|
|
9263
|
+
/* @__PURE__ */ jsx9(Box9, { paddingLeft: 2, children: /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: truncate(String(task), 80) }) })
|
|
9264
|
+
] });
|
|
9265
|
+
};
|
|
9266
|
+
var renderWaitAgent = ({ args }) => {
|
|
9267
|
+
const parsed = parseArgs(args);
|
|
9268
|
+
const sessionId = parsed.session_id || "[no session]";
|
|
9269
|
+
return /* @__PURE__ */ jsxs9(Box9, { children: [
|
|
9270
|
+
/* @__PURE__ */ jsx9(Text9, { color: BLUMA_TERMINAL.brandBlue, bold: true, children: "wait" }),
|
|
9271
|
+
/* @__PURE__ */ jsxs9(Text9, { color: BLUMA_TERMINAL.brandMagenta, children: [
|
|
9272
|
+
" ",
|
|
9273
|
+
truncate(String(sessionId), 18)
|
|
9274
|
+
] })
|
|
9275
|
+
] });
|
|
9276
|
+
};
|
|
9277
|
+
var renderListAgents = ({ args }) => {
|
|
9278
|
+
const parsed = parseArgs(args);
|
|
9279
|
+
const status = parsed.status ? `status=${parsed.status}` : "all";
|
|
9280
|
+
return /* @__PURE__ */ jsxs9(Box9, { children: [
|
|
9281
|
+
/* @__PURE__ */ jsx9(Text9, { color: BLUMA_TERMINAL.brandBlue, bold: true, children: "agents" }),
|
|
9282
|
+
/* @__PURE__ */ jsxs9(Text9, { dimColor: true, children: [
|
|
9283
|
+
" ",
|
|
9284
|
+
status
|
|
9285
|
+
] })
|
|
9286
|
+
] });
|
|
9287
|
+
};
|
|
8379
9288
|
var renderTaskBoundary = ({ args }) => {
|
|
8380
9289
|
const parsed = parseArgs(args);
|
|
8381
9290
|
const name = parsed.task_name || "[no name]";
|
|
@@ -8442,36 +9351,50 @@ var ToolRenderDisplay = {
|
|
|
8442
9351
|
read_file_lines: renderReadFileLines2,
|
|
8443
9352
|
edit_tool: renderEditToolCall,
|
|
8444
9353
|
todo: renderTodoTool2,
|
|
9354
|
+
file_write: renderFileWrite,
|
|
8445
9355
|
find_by_name: renderFindByName,
|
|
8446
9356
|
grep_search: renderGrepSearch,
|
|
8447
9357
|
view_file_outline: renderViewFileOutline,
|
|
8448
9358
|
command_status: renderCommandStatus,
|
|
9359
|
+
spawn_agent: renderSpawnAgent,
|
|
9360
|
+
wait_agent: renderWaitAgent,
|
|
9361
|
+
list_agents: renderListAgents,
|
|
8449
9362
|
task_boundary: renderTaskBoundary,
|
|
9363
|
+
web_fetch: renderWebFetch,
|
|
8450
9364
|
search_web: renderSearchWeb,
|
|
8451
9365
|
load_skill: renderLoadSkill
|
|
8452
9366
|
};
|
|
8453
9367
|
|
|
8454
9368
|
// src/app/ui/components/ToolCallDisplay.tsx
|
|
8455
|
-
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
8456
|
-
var ToolCallDisplayComponent = ({ toolName, args, preview }) => {
|
|
9369
|
+
import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
9370
|
+
var ToolCallDisplayComponent = ({ toolName, args, preview, toolPolicy }) => {
|
|
8457
9371
|
if (toolName.includes("message") || toolName.includes("task_boundary") || toolName === "todo") {
|
|
8458
9372
|
return null;
|
|
8459
9373
|
}
|
|
8460
9374
|
const Renderer = ToolRenderDisplay[toolName] || ((props) => renderGeneric2({ ...props, toolName }));
|
|
8461
|
-
return /* @__PURE__ */ jsx10(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */
|
|
9375
|
+
return /* @__PURE__ */ jsx10(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", paddingLeft: 1, children: [
|
|
9376
|
+
toolPolicy?.metadata ? /* @__PURE__ */ jsxs10(Text10, { dimColor: true, children: [
|
|
9377
|
+
toolPolicy.metadata.category,
|
|
9378
|
+
" \xB7 ",
|
|
9379
|
+
toolPolicy.metadata.riskLevel,
|
|
9380
|
+
" \xB7 ",
|
|
9381
|
+
toolPolicy.autoApprove ? "auto" : "confirm"
|
|
9382
|
+
] }) : null,
|
|
9383
|
+
/* @__PURE__ */ jsx10(Renderer, { toolName, args, preview })
|
|
9384
|
+
] }) });
|
|
8462
9385
|
};
|
|
8463
9386
|
var ToolCallDisplay = memo6(ToolCallDisplayComponent);
|
|
8464
9387
|
|
|
8465
9388
|
// src/app/ui/components/ToolResultDisplay.tsx
|
|
8466
9389
|
import { memo as memo8, useEffect as useEffect5 } from "react";
|
|
8467
|
-
import { Box as Box12, Text as
|
|
9390
|
+
import { Box as Box12, Text as Text12 } from "ink";
|
|
8468
9391
|
|
|
8469
9392
|
// src/app/ui/components/MarkdownRenderer.tsx
|
|
8470
9393
|
import { cloneElement, isValidElement, memo as memo7 } from "react";
|
|
8471
|
-
import { Box as Box11, Text as
|
|
9394
|
+
import { Box as Box11, Text as Text11 } from "ink";
|
|
8472
9395
|
import { marked } from "marked";
|
|
8473
9396
|
import { highlight } from "cli-highlight";
|
|
8474
|
-
import { jsx as jsx11, jsxs as
|
|
9397
|
+
import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
8475
9398
|
marked.setOptions({ gfm: true });
|
|
8476
9399
|
function styleInlineNodes(nodes, keyPrefix, style) {
|
|
8477
9400
|
return nodes.map(
|
|
@@ -8503,7 +9426,7 @@ function walkInline(tokens, keyBase, opts = {}) {
|
|
|
8503
9426
|
case "text":
|
|
8504
9427
|
out.push(
|
|
8505
9428
|
/* @__PURE__ */ jsx11(
|
|
8506
|
-
|
|
9429
|
+
Text11,
|
|
8507
9430
|
{
|
|
8508
9431
|
bold: opts.bold,
|
|
8509
9432
|
italic: opts.italic,
|
|
@@ -8525,7 +9448,7 @@ function walkInline(tokens, keyBase, opts = {}) {
|
|
|
8525
9448
|
case "codespan":
|
|
8526
9449
|
out.push(
|
|
8527
9450
|
/* @__PURE__ */ jsx11(
|
|
8528
|
-
|
|
9451
|
+
Text11,
|
|
8529
9452
|
{
|
|
8530
9453
|
color: opts.link ? BLUMA_TERMINAL.link : BLUMA_TERMINAL.code,
|
|
8531
9454
|
backgroundColor: opts.link ? void 0 : "black",
|
|
@@ -8540,19 +9463,19 @@ function walkInline(tokens, keyBase, opts = {}) {
|
|
|
8540
9463
|
const L = t;
|
|
8541
9464
|
const inner = walkInline(L.tokens, k + "l", { ...opts, link: true });
|
|
8542
9465
|
out.push(
|
|
8543
|
-
/* @__PURE__ */ jsx11(Box11, { flexDirection: "row", flexWrap: "wrap", children: inner.length > 0 ? inner : /* @__PURE__ */ jsx11(
|
|
9466
|
+
/* @__PURE__ */ jsx11(Box11, { flexDirection: "row", flexWrap: "wrap", children: inner.length > 0 ? inner : /* @__PURE__ */ jsx11(Text11, { color: BLUMA_TERMINAL.link, underline: true, children: L.text }) }, k)
|
|
8544
9467
|
);
|
|
8545
9468
|
break;
|
|
8546
9469
|
}
|
|
8547
9470
|
case "br":
|
|
8548
9471
|
out.push(
|
|
8549
|
-
/* @__PURE__ */ jsx11(
|
|
9472
|
+
/* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "\n" }, k)
|
|
8550
9473
|
);
|
|
8551
9474
|
break;
|
|
8552
9475
|
case "escape":
|
|
8553
9476
|
out.push(
|
|
8554
9477
|
/* @__PURE__ */ jsx11(
|
|
8555
|
-
|
|
9478
|
+
Text11,
|
|
8556
9479
|
{
|
|
8557
9480
|
bold: opts.bold,
|
|
8558
9481
|
italic: opts.italic,
|
|
@@ -8570,7 +9493,7 @@ function walkInline(tokens, keyBase, opts = {}) {
|
|
|
8570
9493
|
case "image": {
|
|
8571
9494
|
const Im = t;
|
|
8572
9495
|
out.push(
|
|
8573
|
-
/* @__PURE__ */
|
|
9496
|
+
/* @__PURE__ */ jsxs11(Text11, { dimColor: true, italic: true, children: [
|
|
8574
9497
|
"[",
|
|
8575
9498
|
Im.text || "img",
|
|
8576
9499
|
"]"
|
|
@@ -8581,7 +9504,7 @@ function walkInline(tokens, keyBase, opts = {}) {
|
|
|
8581
9504
|
default:
|
|
8582
9505
|
if ("text" in t && typeof t.text === "string") {
|
|
8583
9506
|
out.push(
|
|
8584
|
-
/* @__PURE__ */ jsx11(
|
|
9507
|
+
/* @__PURE__ */ jsx11(Text11, { bold: opts.bold, italic: opts.italic, children: t.text }, k)
|
|
8585
9508
|
);
|
|
8586
9509
|
}
|
|
8587
9510
|
}
|
|
@@ -8590,7 +9513,7 @@ function walkInline(tokens, keyBase, opts = {}) {
|
|
|
8590
9513
|
}
|
|
8591
9514
|
function renderParagraph(p, key) {
|
|
8592
9515
|
const nodes = walkInline(p.tokens, key);
|
|
8593
|
-
return /* @__PURE__ */ jsx11(Box11, { marginBottom: 1, flexDirection: "row", flexWrap: "wrap", children: nodes.length > 0 ? nodes : /* @__PURE__ */ jsx11(
|
|
9516
|
+
return /* @__PURE__ */ jsx11(Box11, { marginBottom: 1, flexDirection: "row", flexWrap: "wrap", children: nodes.length > 0 ? nodes : /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: p.text }) }, key);
|
|
8594
9517
|
}
|
|
8595
9518
|
function renderListItemBlocks(item, depth, keyBase) {
|
|
8596
9519
|
if (!item.tokens?.length) {
|
|
@@ -8626,15 +9549,15 @@ function renderListBlock(list, depth, keyBase) {
|
|
|
8626
9549
|
);
|
|
8627
9550
|
const gColor = depth === 0 ? BLUMA_TERMINAL.listBullet : BLUMA_TERMINAL.listBulletSub;
|
|
8628
9551
|
const body = renderListItemBlocks(item, depth, `${keyBase}-it${idx}`);
|
|
8629
|
-
return /* @__PURE__ */
|
|
8630
|
-
/* @__PURE__ */ jsx11(
|
|
8631
|
-
/* @__PURE__ */ jsx11(Box11, { flexDirection: "column", flexGrow: 1, children: body.length > 0 ? body : /* @__PURE__ */ jsx11(
|
|
9552
|
+
return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "row", alignItems: "flex-start", marginBottom: 0, children: [
|
|
9553
|
+
/* @__PURE__ */ jsx11(Text11, { color: gColor, children: (item.task ? glyph : `${glyph} `).padEnd(item.task ? 4 : 3, " ") }),
|
|
9554
|
+
/* @__PURE__ */ jsx11(Box11, { flexDirection: "column", flexGrow: 1, children: body.length > 0 ? body : /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: item.text }) })
|
|
8632
9555
|
] }, `${keyBase}-row-${idx}`);
|
|
8633
9556
|
}) }, keyBase);
|
|
8634
9557
|
}
|
|
8635
9558
|
function renderBlockquote(q, key) {
|
|
8636
|
-
const inner = q.tokens && q.tokens.length > 0 ? renderBlockTokens(q.tokens, `${key}-inner`) : /* @__PURE__ */ jsx11(
|
|
8637
|
-
return /* @__PURE__ */
|
|
9559
|
+
const inner = q.tokens && q.tokens.length > 0 ? renderBlockTokens(q.tokens, `${key}-inner`) : /* @__PURE__ */ jsx11(Text11, { dimColor: true, italic: true, children: q.text });
|
|
9560
|
+
return /* @__PURE__ */ jsxs11(
|
|
8638
9561
|
Box11,
|
|
8639
9562
|
{
|
|
8640
9563
|
flexDirection: "row",
|
|
@@ -8644,7 +9567,7 @@ function renderBlockquote(q, key) {
|
|
|
8644
9567
|
paddingLeft: 1,
|
|
8645
9568
|
paddingY: 0,
|
|
8646
9569
|
children: [
|
|
8647
|
-
/* @__PURE__ */ jsx11(
|
|
9570
|
+
/* @__PURE__ */ jsx11(Text11, { color: BLUMA_TERMINAL.brandMagenta, children: "\u2502 " }),
|
|
8648
9571
|
/* @__PURE__ */ jsx11(Box11, { flexDirection: "column", flexGrow: 1, children: inner })
|
|
8649
9572
|
]
|
|
8650
9573
|
},
|
|
@@ -8663,9 +9586,9 @@ function renderBlockTokens(tokens, keyRoot) {
|
|
|
8663
9586
|
const prefix = h.depth <= 2 ? `${"#".repeat(h.depth)} ` : "";
|
|
8664
9587
|
const inner = walkInline(h.tokens, `${key}-h`);
|
|
8665
9588
|
elements.push(
|
|
8666
|
-
/* @__PURE__ */
|
|
8667
|
-
/* @__PURE__ */ jsx11(
|
|
8668
|
-
inner.length > 0 ? inner : /* @__PURE__ */ jsx11(
|
|
9589
|
+
/* @__PURE__ */ jsxs11(Box11, { marginBottom: 1, flexDirection: "row", flexWrap: "wrap", alignItems: "flex-start", children: [
|
|
9590
|
+
/* @__PURE__ */ jsx11(Text11, { color, bold: true, children: prefix }),
|
|
9591
|
+
inner.length > 0 ? inner : /* @__PURE__ */ jsx11(Text11, { color, bold: true, children: h.text })
|
|
8669
9592
|
] }, key)
|
|
8670
9593
|
);
|
|
8671
9594
|
break;
|
|
@@ -8688,7 +9611,7 @@ function renderBlockTokens(tokens, keyRoot) {
|
|
|
8688
9611
|
highlighted = code.text;
|
|
8689
9612
|
}
|
|
8690
9613
|
elements.push(
|
|
8691
|
-
/* @__PURE__ */
|
|
9614
|
+
/* @__PURE__ */ jsxs11(
|
|
8692
9615
|
Box11,
|
|
8693
9616
|
{
|
|
8694
9617
|
flexDirection: "column",
|
|
@@ -8697,8 +9620,8 @@ function renderBlockTokens(tokens, keyRoot) {
|
|
|
8697
9620
|
borderColor: BLUMA_TERMINAL.panelBorder,
|
|
8698
9621
|
paddingX: 1,
|
|
8699
9622
|
children: [
|
|
8700
|
-
code.lang ? /* @__PURE__ */ jsx11(
|
|
8701
|
-
/* @__PURE__ */ jsx11(
|
|
9623
|
+
code.lang ? /* @__PURE__ */ jsx11(Text11, { color: BLUMA_TERMINAL.codeLabel, dimColor: true, children: code.lang }) : null,
|
|
9624
|
+
/* @__PURE__ */ jsx11(Text11, { dimColor: true, children: highlighted })
|
|
8702
9625
|
]
|
|
8703
9626
|
},
|
|
8704
9627
|
key
|
|
@@ -8712,15 +9635,15 @@ function renderBlockTokens(tokens, keyRoot) {
|
|
|
8712
9635
|
case "table": {
|
|
8713
9636
|
const table = token;
|
|
8714
9637
|
elements.push(
|
|
8715
|
-
/* @__PURE__ */
|
|
9638
|
+
/* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", marginBottom: 1, children: [
|
|
8716
9639
|
/* @__PURE__ */ jsx11(Box11, { flexDirection: "row", children: table.header.map((cell, idx) => {
|
|
8717
9640
|
const headerNodes = walkInline(cell.tokens, `${key}-h${idx}`);
|
|
8718
|
-
const styled = headerNodes.length > 0 ? styleInlineNodes(headerNodes, `${key}-h${idx}`, { bold: true, color: BLUMA_TERMINAL.brandBlue }) : [/* @__PURE__ */ jsx11(
|
|
9641
|
+
const styled = headerNodes.length > 0 ? styleInlineNodes(headerNodes, `${key}-h${idx}`, { bold: true, color: BLUMA_TERMINAL.brandBlue }) : [/* @__PURE__ */ jsx11(Text11, { bold: true, color: BLUMA_TERMINAL.brandBlue, children: cell.text }, `${key}-h${idx}-t`)];
|
|
8719
9642
|
return /* @__PURE__ */ jsx11(Box11, { paddingRight: 2, flexDirection: "row", flexWrap: "wrap", children: styled }, idx);
|
|
8720
9643
|
}) }),
|
|
8721
9644
|
table.rows.map((row, rowIdx) => /* @__PURE__ */ jsx11(Box11, { flexDirection: "row", children: row.map((cell, cellIdx) => {
|
|
8722
9645
|
const cellNodes = walkInline(cell.tokens, `${key}-c${rowIdx}-${cellIdx}`);
|
|
8723
|
-
const styled = cellNodes.length > 0 ? styleInlineNodes(cellNodes, `${key}-c${rowIdx}-${cellIdx}`, { dimColor: true }) : [/* @__PURE__ */ jsx11(
|
|
9646
|
+
const styled = cellNodes.length > 0 ? styleInlineNodes(cellNodes, `${key}-c${rowIdx}-${cellIdx}`, { dimColor: true }) : [/* @__PURE__ */ jsx11(Text11, { dimColor: true, children: cell.text }, `${key}-c${rowIdx}-${cellIdx}-t`)];
|
|
8724
9647
|
return /* @__PURE__ */ jsx11(Box11, { paddingRight: 2, flexDirection: "row", flexWrap: "wrap", children: styled }, cellIdx);
|
|
8725
9648
|
}) }, `${key}-r${rowIdx}`))
|
|
8726
9649
|
] }, key)
|
|
@@ -8729,7 +9652,7 @@ function renderBlockTokens(tokens, keyRoot) {
|
|
|
8729
9652
|
}
|
|
8730
9653
|
case "hr":
|
|
8731
9654
|
elements.push(
|
|
8732
|
-
/* @__PURE__ */ jsx11(Box11, { marginY: 1, children: /* @__PURE__ */ jsx11(
|
|
9655
|
+
/* @__PURE__ */ jsx11(Box11, { marginY: 1, children: /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "\u2500".repeat(42) }) }, key)
|
|
8733
9656
|
);
|
|
8734
9657
|
break;
|
|
8735
9658
|
case "space":
|
|
@@ -8737,7 +9660,7 @@ function renderBlockTokens(tokens, keyRoot) {
|
|
|
8737
9660
|
default:
|
|
8738
9661
|
if ("text" in token && typeof token.text === "string") {
|
|
8739
9662
|
elements.push(
|
|
8740
|
-
/* @__PURE__ */ jsx11(
|
|
9663
|
+
/* @__PURE__ */ jsx11(Text11, { dimColor: true, children: token.text }, key)
|
|
8741
9664
|
);
|
|
8742
9665
|
}
|
|
8743
9666
|
}
|
|
@@ -8824,7 +9747,7 @@ function peekLatestExpandable() {
|
|
|
8824
9747
|
}
|
|
8825
9748
|
|
|
8826
9749
|
// src/app/ui/components/ToolResultDisplay.tsx
|
|
8827
|
-
import { jsx as jsx12, jsxs as
|
|
9750
|
+
import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
8828
9751
|
var parseResult2 = (result) => {
|
|
8829
9752
|
try {
|
|
8830
9753
|
return JSON.parse(result);
|
|
@@ -8846,29 +9769,111 @@ function TodoTaskLine({
|
|
|
8846
9769
|
done,
|
|
8847
9770
|
label
|
|
8848
9771
|
}) {
|
|
8849
|
-
return /* @__PURE__ */
|
|
8850
|
-
/* @__PURE__ */ jsx12(
|
|
8851
|
-
/* @__PURE__ */ jsx12(
|
|
9772
|
+
return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "row", children: [
|
|
9773
|
+
/* @__PURE__ */ jsx12(Text12, { color: done ? BLUMA_TERMINAL.brandBlue : BLUMA_TERMINAL.brandMagenta, children: done ? "\u25A0 " : "\u25A1 " }),
|
|
9774
|
+
/* @__PURE__ */ jsx12(Text12, { dimColor: done, strikethrough: done, color: done ? BLUMA_TERMINAL.muted : void 0, children: label })
|
|
8852
9775
|
] });
|
|
8853
9776
|
}
|
|
8854
9777
|
var ToolResultDisplayComponent = ({ toolName, result }) => {
|
|
8855
9778
|
useEffect5(() => {
|
|
8856
9779
|
refreshExpandableFromToolResult(toolName, result);
|
|
8857
9780
|
}, [toolName, result]);
|
|
8858
|
-
if (toolName.includes("task_boundary")) {
|
|
8859
|
-
return null;
|
|
8860
|
-
}
|
|
8861
9781
|
const parsed = parseResult2(result);
|
|
9782
|
+
if (toolName.includes("task_boundary") && parsed) {
|
|
9783
|
+
const activeTask = parsed.activeTask;
|
|
9784
|
+
const stats = parsed.stats;
|
|
9785
|
+
const msg = typeof parsed.message === "string" ? parsed.message : "";
|
|
9786
|
+
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", paddingLeft: 2, children: [
|
|
9787
|
+
msg ? /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: msg }) : null,
|
|
9788
|
+
activeTask ? /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
9789
|
+
String(activeTask.mode || "EXECUTION"),
|
|
9790
|
+
" \xB7 ",
|
|
9791
|
+
String(activeTask.taskName || ""),
|
|
9792
|
+
activeTask.status ? ` \xB7 ${String(activeTask.status)}` : ""
|
|
9793
|
+
] }) : null,
|
|
9794
|
+
stats ? /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
9795
|
+
String(stats.completed ?? 0),
|
|
9796
|
+
"/",
|
|
9797
|
+
String(stats.total ?? 0),
|
|
9798
|
+
" done \xB7 ",
|
|
9799
|
+
String(stats.progress ?? 0),
|
|
9800
|
+
"%"
|
|
9801
|
+
] }) : null
|
|
9802
|
+
] }) });
|
|
9803
|
+
}
|
|
8862
9804
|
if (toolName.includes("message")) {
|
|
8863
9805
|
const body = parsed?.content?.body ?? parsed?.body ?? parsed?.message;
|
|
8864
9806
|
if (!body) return null;
|
|
8865
9807
|
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsx12(Box12, { paddingLeft: 2, flexDirection: "column", children: /* @__PURE__ */ jsx12(MarkdownRenderer, { markdown: String(body) }) }) });
|
|
8866
9808
|
}
|
|
9809
|
+
if (toolName.includes("file_write") && parsed) {
|
|
9810
|
+
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", paddingLeft: 2, children: [
|
|
9811
|
+
/* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
9812
|
+
parsed.created ? "created" : "updated",
|
|
9813
|
+
" ",
|
|
9814
|
+
String(parsed.filepath || "")
|
|
9815
|
+
] }),
|
|
9816
|
+
parsed.bytes_written != null ? /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
9817
|
+
String(parsed.bytes_written),
|
|
9818
|
+
" bytes"
|
|
9819
|
+
] }) : null
|
|
9820
|
+
] }) });
|
|
9821
|
+
}
|
|
9822
|
+
if (toolName.includes("spawn_agent") && parsed) {
|
|
9823
|
+
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", paddingLeft: 2, children: [
|
|
9824
|
+
/* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
9825
|
+
String(parsed.title || "worker"),
|
|
9826
|
+
" \xB7 ",
|
|
9827
|
+
String(parsed.session_id || "")
|
|
9828
|
+
] }),
|
|
9829
|
+
/* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
9830
|
+
"status ",
|
|
9831
|
+
String(parsed.status || "running"),
|
|
9832
|
+
parsed.pid != null ? ` \xB7 pid ${String(parsed.pid)}` : ""
|
|
9833
|
+
] })
|
|
9834
|
+
] }) });
|
|
9835
|
+
}
|
|
9836
|
+
if (toolName.includes("wait_agent") && parsed) {
|
|
9837
|
+
const session = parsed.session || {};
|
|
9838
|
+
const resultStatus = parsed.result?.status;
|
|
9839
|
+
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", paddingLeft: 2, children: [
|
|
9840
|
+
/* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
9841
|
+
String(session.session_id || ""),
|
|
9842
|
+
" \xB7 ",
|
|
9843
|
+
String(session.status || "")
|
|
9844
|
+
] }),
|
|
9845
|
+
/* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
9846
|
+
parsed.completed ? "completed" : "still running",
|
|
9847
|
+
resultStatus ? ` \xB7 result ${String(resultStatus)}` : ""
|
|
9848
|
+
] })
|
|
9849
|
+
] }) });
|
|
9850
|
+
}
|
|
9851
|
+
if (toolName.includes("list_agents") && parsed) {
|
|
9852
|
+
const agents = Array.isArray(parsed.agents) ? parsed.agents : [];
|
|
9853
|
+
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", paddingLeft: 2, children: [
|
|
9854
|
+
/* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
9855
|
+
String(parsed.count || agents.length),
|
|
9856
|
+
" agents"
|
|
9857
|
+
] }),
|
|
9858
|
+
agents.slice(0, 5).map((agent, i) => {
|
|
9859
|
+
const row = agent;
|
|
9860
|
+
return /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
9861
|
+
String(row.session_id || ""),
|
|
9862
|
+
" \xB7 ",
|
|
9863
|
+
String(row.status || "")
|
|
9864
|
+
] }, i);
|
|
9865
|
+
}),
|
|
9866
|
+
agents.length > 5 ? /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
9867
|
+
"\u2026 +",
|
|
9868
|
+
agents.length - 5
|
|
9869
|
+
] }) : null
|
|
9870
|
+
] }) });
|
|
9871
|
+
}
|
|
8867
9872
|
if (toolName.includes("read_file") && parsed && typeof parsed.content === "string") {
|
|
8868
9873
|
const { lines, truncated } = truncateLines(parsed.content, TOOL_PREVIEW_MAX_LINES);
|
|
8869
|
-
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */
|
|
8870
|
-
lines.map((line, i) => /* @__PURE__ */ jsx12(
|
|
8871
|
-
truncated > 0 ? /* @__PURE__ */
|
|
9874
|
+
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", paddingLeft: 2, children: [
|
|
9875
|
+
lines.map((line, i) => /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: line.slice(0, 120) }, i)),
|
|
9876
|
+
truncated > 0 ? /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
8872
9877
|
"\u2026 +",
|
|
8873
9878
|
truncated,
|
|
8874
9879
|
" lines \xB7 Ctrl+O expand"
|
|
@@ -8881,27 +9886,27 @@ var ToolResultDisplayComponent = ({ toolName, result }) => {
|
|
|
8881
9886
|
const exitCode = parsed.exit_code ?? parsed.exitCode ?? 0;
|
|
8882
9887
|
const status = String(parsed.status || "");
|
|
8883
9888
|
if (parsed.command_id && !output && !stderr && !status) {
|
|
8884
|
-
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsx12(Box12, { paddingLeft: 2, children: /* @__PURE__ */
|
|
9889
|
+
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsx12(Box12, { paddingLeft: 2, children: /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
8885
9890
|
"started #",
|
|
8886
9891
|
String(parsed.command_id).slice(0, 8)
|
|
8887
9892
|
] }) }) });
|
|
8888
9893
|
}
|
|
8889
9894
|
if (status === "running") {
|
|
8890
|
-
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsx12(Box12, { paddingLeft: 2, children: /* @__PURE__ */ jsx12(
|
|
9895
|
+
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsx12(Box12, { paddingLeft: 2, children: /* @__PURE__ */ jsx12(Text12, { color: BLUMA_TERMINAL.warn, dimColor: true, children: "still running\u2026" }) }) });
|
|
8891
9896
|
}
|
|
8892
9897
|
if (!output && !stderr) return null;
|
|
8893
9898
|
const { lines, truncated } = truncateLines(output || stderr, TOOL_PREVIEW_MAX_LINES);
|
|
8894
9899
|
const isError = exitCode !== 0;
|
|
8895
9900
|
const isSuccess = exitCode === 0 && status !== "running";
|
|
8896
9901
|
const lineColor = isError ? BLUMA_TERMINAL.err : isSuccess ? BLUMA_TERMINAL.success : BLUMA_TERMINAL.muted;
|
|
8897
|
-
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */
|
|
8898
|
-
lines.map((line, i) => /* @__PURE__ */ jsx12(
|
|
8899
|
-
truncated > 0 ? /* @__PURE__ */
|
|
9902
|
+
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", paddingLeft: 2, children: [
|
|
9903
|
+
lines.map((line, i) => /* @__PURE__ */ jsx12(Text12, { dimColor: true, color: lineColor, children: line.slice(0, 120) }, i)),
|
|
9904
|
+
truncated > 0 ? /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
8900
9905
|
"\u2026 +",
|
|
8901
9906
|
truncated,
|
|
8902
9907
|
" lines \xB7 Ctrl+O expand"
|
|
8903
9908
|
] }) : null,
|
|
8904
|
-
exitCode !== 0 ? /* @__PURE__ */
|
|
9909
|
+
exitCode !== 0 ? /* @__PURE__ */ jsxs12(Text12, { dimColor: true, color: BLUMA_TERMINAL.err, children: [
|
|
8905
9910
|
"exit ",
|
|
8906
9911
|
exitCode
|
|
8907
9912
|
] }) : null
|
|
@@ -8910,23 +9915,23 @@ var ToolResultDisplayComponent = ({ toolName, result }) => {
|
|
|
8910
9915
|
if ((toolName.includes("grep") || toolName.includes("find_by_name")) && parsed) {
|
|
8911
9916
|
const matches = parsed.matches || parsed.results || parsed.files || [];
|
|
8912
9917
|
if (matches.length === 0) {
|
|
8913
|
-
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsx12(Box12, { paddingLeft: 2, children: /* @__PURE__ */ jsx12(
|
|
9918
|
+
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsx12(Box12, { paddingLeft: 2, children: /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "no matches" }) }) });
|
|
8914
9919
|
}
|
|
8915
|
-
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */
|
|
8916
|
-
/* @__PURE__ */
|
|
9920
|
+
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", paddingLeft: 2, children: [
|
|
9921
|
+
/* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
8917
9922
|
matches.length,
|
|
8918
9923
|
" matches"
|
|
8919
9924
|
] }),
|
|
8920
9925
|
matches.slice(0, 5).map((m, i) => {
|
|
8921
9926
|
const row = m;
|
|
8922
|
-
const
|
|
9927
|
+
const path27 = row.file || row.path || row.name || m;
|
|
8923
9928
|
const line = row.line;
|
|
8924
|
-
return /* @__PURE__ */
|
|
8925
|
-
String(
|
|
9929
|
+
return /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
9930
|
+
String(path27),
|
|
8926
9931
|
line != null ? `:${line}` : ""
|
|
8927
9932
|
] }, i);
|
|
8928
9933
|
}),
|
|
8929
|
-
matches.length > 5 ? /* @__PURE__ */
|
|
9934
|
+
matches.length > 5 ? /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
8930
9935
|
"\u2026 +",
|
|
8931
9936
|
matches.length - 5
|
|
8932
9937
|
] }) : null
|
|
@@ -8935,17 +9940,17 @@ var ToolResultDisplayComponent = ({ toolName, result }) => {
|
|
|
8935
9940
|
if (toolName.includes("ls_tool") && parsed) {
|
|
8936
9941
|
const entries = parsed.entries || parsed.files || [];
|
|
8937
9942
|
if (entries.length === 0) return null;
|
|
8938
|
-
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */
|
|
9943
|
+
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", paddingLeft: 2, children: [
|
|
8939
9944
|
entries.slice(0, 6).map((e, i) => {
|
|
8940
9945
|
const row = e;
|
|
8941
9946
|
const name = row.name ?? e;
|
|
8942
9947
|
const isDir = Boolean(row.isDirectory);
|
|
8943
|
-
return /* @__PURE__ */
|
|
9948
|
+
return /* @__PURE__ */ jsxs12(Text12, { dimColor: true, color: isDir ? BLUMA_TERMINAL.brandBlue : BLUMA_TERMINAL.muted, children: [
|
|
8944
9949
|
isDir ? "d " : "f ",
|
|
8945
9950
|
String(name)
|
|
8946
9951
|
] }, i);
|
|
8947
9952
|
}),
|
|
8948
|
-
entries.length > 6 ? /* @__PURE__ */
|
|
9953
|
+
entries.length > 6 ? /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
8949
9954
|
"\u2026 +",
|
|
8950
9955
|
entries.length - 6
|
|
8951
9956
|
] }) : null
|
|
@@ -8953,15 +9958,15 @@ var ToolResultDisplayComponent = ({ toolName, result }) => {
|
|
|
8953
9958
|
}
|
|
8954
9959
|
if (toolName.includes("load_skill") && parsed) {
|
|
8955
9960
|
if (!parsed.success) {
|
|
8956
|
-
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsx12(Box12, { paddingLeft: 2, children: /* @__PURE__ */
|
|
9961
|
+
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsx12(Box12, { paddingLeft: 2, children: /* @__PURE__ */ jsxs12(Text12, { dimColor: true, color: BLUMA_TERMINAL.err, children: [
|
|
8957
9962
|
"Not found: ",
|
|
8958
9963
|
String(parsed.message || "")
|
|
8959
9964
|
] }) }) });
|
|
8960
9965
|
}
|
|
8961
9966
|
const desc = parsed.description ? String(parsed.description) : "";
|
|
8962
|
-
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */
|
|
8963
|
-
/* @__PURE__ */ jsx12(
|
|
8964
|
-
/* @__PURE__ */
|
|
9967
|
+
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs12(Box12, { paddingLeft: 2, flexDirection: "row", flexWrap: "wrap", children: [
|
|
9968
|
+
/* @__PURE__ */ jsx12(Text12, { color: BLUMA_TERMINAL.brandMagenta, bold: true, children: String(parsed.skill_name || "") }),
|
|
9969
|
+
/* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
8965
9970
|
" ",
|
|
8966
9971
|
"\u2014 ",
|
|
8967
9972
|
desc.slice(0, 80),
|
|
@@ -8969,14 +9974,27 @@ var ToolResultDisplayComponent = ({ toolName, result }) => {
|
|
|
8969
9974
|
] })
|
|
8970
9975
|
] }) });
|
|
8971
9976
|
}
|
|
9977
|
+
if (toolName.includes("web_fetch") && parsed) {
|
|
9978
|
+
const content = typeof parsed.content === "string" ? parsed.content : "";
|
|
9979
|
+
const { lines, truncated } = truncateLines(content, TOOL_PREVIEW_MAX_LINES);
|
|
9980
|
+
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", paddingLeft: 2, children: [
|
|
9981
|
+
/* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
9982
|
+
String(parsed.status_code ?? ""),
|
|
9983
|
+
" \xB7 ",
|
|
9984
|
+
String(parsed.content_type ?? "")
|
|
9985
|
+
] }),
|
|
9986
|
+
lines.map((line, i) => /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: line.slice(0, 120) }, i)),
|
|
9987
|
+
truncated > 0 || parsed.truncated ? /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "\u2026 Ctrl+O expand" }) : null
|
|
9988
|
+
] }) });
|
|
9989
|
+
}
|
|
8972
9990
|
if (toolName.includes("todo")) {
|
|
8973
9991
|
if (parsed && Array.isArray(parsed.tasks)) {
|
|
8974
9992
|
const tasks = parsed.tasks;
|
|
8975
9993
|
const stats = parsed.stats;
|
|
8976
9994
|
const msg = typeof parsed.message === "string" ? parsed.message : "";
|
|
8977
|
-
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */
|
|
8978
|
-
msg ? /* @__PURE__ */ jsx12(Box12, { marginBottom: 1, children: /* @__PURE__ */ jsx12(
|
|
8979
|
-
stats && typeof stats.progress === "number" ? /* @__PURE__ */
|
|
9995
|
+
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", paddingLeft: 2, children: [
|
|
9996
|
+
msg ? /* @__PURE__ */ jsx12(Box12, { marginBottom: 1, children: /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: msg }) }) : null,
|
|
9997
|
+
stats && typeof stats.progress === "number" ? /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
8980
9998
|
stats.completed ?? 0,
|
|
8981
9999
|
"/",
|
|
8982
10000
|
stats.total ?? tasks.length,
|
|
@@ -8984,13 +10002,18 @@ var ToolResultDisplayComponent = ({ toolName, result }) => {
|
|
|
8984
10002
|
stats.progress,
|
|
8985
10003
|
"%"
|
|
8986
10004
|
] }) : null,
|
|
8987
|
-
/* @__PURE__ */
|
|
10005
|
+
/* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", marginTop: 1, children: [
|
|
10006
|
+
parsed.activeTask ? /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
10007
|
+
String(parsed.activeTask.mode || "EXECUTION"),
|
|
10008
|
+
" \xB7 ",
|
|
10009
|
+
String(parsed.activeTask.taskName || "")
|
|
10010
|
+
] }) : null,
|
|
8988
10011
|
tasks.slice(0, 12).map((t, i) => {
|
|
8989
10012
|
const done = t.status === "completed" || t.isComplete === true;
|
|
8990
10013
|
const line = `#${t.id ?? i + 1} ${t.description ?? ""}`;
|
|
8991
10014
|
return /* @__PURE__ */ jsx12(TodoTaskLine, { done, label: line }, i);
|
|
8992
10015
|
}),
|
|
8993
|
-
tasks.length > 12 ? /* @__PURE__ */
|
|
10016
|
+
tasks.length > 12 ? /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
8994
10017
|
"\u2026 +",
|
|
8995
10018
|
tasks.length - 12,
|
|
8996
10019
|
" tasks"
|
|
@@ -9000,21 +10023,21 @@ var ToolResultDisplayComponent = ({ toolName, result }) => {
|
|
|
9000
10023
|
}
|
|
9001
10024
|
const lines = result.split("\n").filter(Boolean);
|
|
9002
10025
|
if (lines.length === 0) return null;
|
|
9003
|
-
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsx12(Box12, { flexDirection: "column", paddingLeft: 2, children: lines.slice(0, 14).map((line, i) => /* @__PURE__ */ jsx12(
|
|
10026
|
+
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsx12(Box12, { flexDirection: "column", paddingLeft: 2, children: lines.slice(0, 14).map((line, i) => /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: line.slice(0, 100) }, i)) }) });
|
|
9004
10027
|
}
|
|
9005
10028
|
if (toolName.includes("view_file_outline") && parsed) {
|
|
9006
10029
|
const symbols = parsed.symbols || parsed.outline || [];
|
|
9007
10030
|
if (symbols.length === 0) return null;
|
|
9008
|
-
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */
|
|
10031
|
+
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", paddingLeft: 2, children: [
|
|
9009
10032
|
symbols.slice(0, 5).map((s, i) => {
|
|
9010
10033
|
const row = s;
|
|
9011
|
-
return /* @__PURE__ */
|
|
10034
|
+
return /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
9012
10035
|
String(row.kind || "sym"),
|
|
9013
10036
|
" ",
|
|
9014
10037
|
String(row.name || "")
|
|
9015
10038
|
] }, i);
|
|
9016
10039
|
}),
|
|
9017
|
-
symbols.length > 5 ? /* @__PURE__ */
|
|
10040
|
+
symbols.length > 5 ? /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
9018
10041
|
"\u2026 +",
|
|
9019
10042
|
symbols.length - 5
|
|
9020
10043
|
] }) : null
|
|
@@ -9025,35 +10048,35 @@ var ToolResultDisplayComponent = ({ toolName, result }) => {
|
|
|
9025
10048
|
var ToolResultDisplay = memo8(ToolResultDisplayComponent);
|
|
9026
10049
|
|
|
9027
10050
|
// src/app/ui/SessionInfoConnectingMCP.tsx
|
|
9028
|
-
import { Box as Box13, Text as
|
|
10051
|
+
import { Box as Box13, Text as Text13 } from "ink";
|
|
9029
10052
|
import Spinner from "ink-spinner";
|
|
9030
|
-
import { jsx as jsx13, jsxs as
|
|
10053
|
+
import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
9031
10054
|
var SessionInfoConnectingMCP = ({
|
|
9032
10055
|
workdir,
|
|
9033
10056
|
statusMessage
|
|
9034
|
-
}) => /* @__PURE__ */ jsx13(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */
|
|
9035
|
-
/* @__PURE__ */
|
|
9036
|
-
/* @__PURE__ */ jsx13(
|
|
10057
|
+
}) => /* @__PURE__ */ jsx13(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", paddingLeft: 1, children: [
|
|
10058
|
+
/* @__PURE__ */ jsxs13(Text13, { dimColor: true, children: [
|
|
10059
|
+
/* @__PURE__ */ jsx13(Text13, { color: BLUMA_TERMINAL.brandMagenta, children: "\u2514 " }),
|
|
9037
10060
|
workdir
|
|
9038
10061
|
] }),
|
|
9039
|
-
/* @__PURE__ */
|
|
9040
|
-
/* @__PURE__ */
|
|
10062
|
+
/* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "row", flexWrap: "wrap", children: [
|
|
10063
|
+
/* @__PURE__ */ jsxs13(Text13, { color: BLUMA_TERMINAL.warn, children: [
|
|
9041
10064
|
/* @__PURE__ */ jsx13(Spinner, { type: "dots" }),
|
|
9042
10065
|
" "
|
|
9043
10066
|
] }),
|
|
9044
|
-
/* @__PURE__ */ jsx13(
|
|
10067
|
+
/* @__PURE__ */ jsx13(Text13, { dimColor: true, children: statusMessage || "Establishing MCP\u2026" })
|
|
9045
10068
|
] })
|
|
9046
10069
|
] }) });
|
|
9047
10070
|
var SessionInfoConnectingMCP_default = SessionInfoConnectingMCP;
|
|
9048
10071
|
|
|
9049
10072
|
// src/app/ui/components/SlashCommands.tsx
|
|
9050
|
-
import { Box as Box14, Text as
|
|
10073
|
+
import { Box as Box14, Text as Text14 } from "ink";
|
|
9051
10074
|
|
|
9052
10075
|
// src/app/ui/constants/historyLayout.ts
|
|
9053
10076
|
var HEADER_PANEL_HISTORY_ID = 0;
|
|
9054
10077
|
|
|
9055
10078
|
// src/app/ui/components/SlashCommands.tsx
|
|
9056
|
-
import { Fragment as Fragment2, jsx as jsx14, jsxs as
|
|
10079
|
+
import { Fragment as Fragment2, jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
9057
10080
|
var SlashCommands = ({
|
|
9058
10081
|
input,
|
|
9059
10082
|
setHistory,
|
|
@@ -9069,13 +10092,13 @@ var SlashCommands = ({
|
|
|
9069
10092
|
if (cmd === "help") {
|
|
9070
10093
|
const lines = formatSlashHelpLines();
|
|
9071
10094
|
return outBox(
|
|
9072
|
-
/* @__PURE__ */
|
|
9073
|
-
/* @__PURE__ */
|
|
9074
|
-
/* @__PURE__ */ jsx14(
|
|
9075
|
-
/* @__PURE__ */ jsx14(
|
|
9076
|
-
/* @__PURE__ */ jsx14(
|
|
10095
|
+
/* @__PURE__ */ jsxs14(Fragment2, { children: [
|
|
10096
|
+
/* @__PURE__ */ jsxs14(Box14, { marginBottom: 1, children: [
|
|
10097
|
+
/* @__PURE__ */ jsx14(Text14, { bold: true, color: BLUMA_TERMINAL.brandMagenta, children: "Slash commands" }),
|
|
10098
|
+
/* @__PURE__ */ jsx14(Text14, { dimColor: true, children: " \xB7 " }),
|
|
10099
|
+
/* @__PURE__ */ jsx14(Text14, { dimColor: true, children: "put .png/.jpg/.webp paths in a normal message to attach images (project dir or ~)" })
|
|
9077
10100
|
] }),
|
|
9078
|
-
/* @__PURE__ */ jsx14(Box14, { flexDirection: "column", children: lines.map((line, i) => /* @__PURE__ */ jsx14(
|
|
10101
|
+
/* @__PURE__ */ jsx14(Box14, { flexDirection: "column", children: lines.map((line, i) => /* @__PURE__ */ jsx14(Text14, { dimColor: line.trim().length > 0, children: line || " " }, i)) })
|
|
9079
10102
|
] })
|
|
9080
10103
|
);
|
|
9081
10104
|
}
|
|
@@ -9083,32 +10106,32 @@ var SlashCommands = ({
|
|
|
9083
10106
|
const list = agentRef.current?.listAvailableSkills?.() || [];
|
|
9084
10107
|
const dirs = agentRef.current?.getSkillsDirs?.();
|
|
9085
10108
|
return outBox(
|
|
9086
|
-
/* @__PURE__ */
|
|
9087
|
-
/* @__PURE__ */
|
|
9088
|
-
/* @__PURE__ */ jsx14(
|
|
9089
|
-
/* @__PURE__ */
|
|
10109
|
+
/* @__PURE__ */ jsxs14(Fragment2, { children: [
|
|
10110
|
+
/* @__PURE__ */ jsxs14(Box14, { marginBottom: 1, children: [
|
|
10111
|
+
/* @__PURE__ */ jsx14(Text14, { bold: true, color: BLUMA_TERMINAL.brandMagenta, children: "Skills (load_skill)" }),
|
|
10112
|
+
/* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
|
|
9090
10113
|
" \xB7 ",
|
|
9091
10114
|
list.length,
|
|
9092
10115
|
" available"
|
|
9093
10116
|
] })
|
|
9094
10117
|
] }),
|
|
9095
|
-
dirs ? /* @__PURE__ */
|
|
9096
|
-
/* @__PURE__ */
|
|
10118
|
+
dirs ? /* @__PURE__ */ jsxs14(Box14, { marginBottom: 1, flexDirection: "column", children: [
|
|
10119
|
+
/* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
|
|
9097
10120
|
"bundled: ",
|
|
9098
10121
|
String(dirs.bundled || "")
|
|
9099
10122
|
] }),
|
|
9100
|
-
/* @__PURE__ */
|
|
10123
|
+
/* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
|
|
9101
10124
|
"project: ",
|
|
9102
10125
|
String(dirs.project || "")
|
|
9103
10126
|
] }),
|
|
9104
|
-
/* @__PURE__ */
|
|
10127
|
+
/* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
|
|
9105
10128
|
"global: ",
|
|
9106
10129
|
String(dirs.global || "")
|
|
9107
10130
|
] })
|
|
9108
10131
|
] }) : null,
|
|
9109
|
-
list.length === 0 ? /* @__PURE__ */ jsx14(
|
|
9110
|
-
/* @__PURE__ */ jsx14(
|
|
9111
|
-
/* @__PURE__ */
|
|
10132
|
+
list.length === 0 ? /* @__PURE__ */ jsx14(Text14, { color: "yellow", children: "No skills found (check bundled dist/config/skills)." }) : /* @__PURE__ */ jsx14(Box14, { flexDirection: "column", children: list.map((s, i) => /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", marginBottom: 1, children: [
|
|
10133
|
+
/* @__PURE__ */ jsx14(Text14, { color: BLUMA_TERMINAL.brandBlue, bold: true, children: s.name }),
|
|
10134
|
+
/* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
|
|
9112
10135
|
s.source,
|
|
9113
10136
|
" \u2014 ",
|
|
9114
10137
|
s.description || "\u2014"
|
|
@@ -9121,9 +10144,9 @@ var SlashCommands = ({
|
|
|
9121
10144
|
onClearRecent?.();
|
|
9122
10145
|
setHistory((prev) => prev.filter((item) => item.id === HEADER_PANEL_HISTORY_ID));
|
|
9123
10146
|
return outBox(
|
|
9124
|
-
/* @__PURE__ */
|
|
9125
|
-
/* @__PURE__ */ jsx14(
|
|
9126
|
-
/* @__PURE__ */ jsx14(
|
|
10147
|
+
/* @__PURE__ */ jsxs14(Box14, { children: [
|
|
10148
|
+
/* @__PURE__ */ jsx14(Text14, { color: "green", children: "[ok]" }),
|
|
10149
|
+
/* @__PURE__ */ jsx14(Text14, { dimColor: true, children: " History cleared" })
|
|
9127
10150
|
] })
|
|
9128
10151
|
);
|
|
9129
10152
|
}
|
|
@@ -9135,7 +10158,7 @@ var SlashCommands = ({
|
|
|
9135
10158
|
setHistory((prev) => prev.concat({
|
|
9136
10159
|
id: Date.now(),
|
|
9137
10160
|
component: outBox(
|
|
9138
|
-
/* @__PURE__ */ jsx14(Box14, { children: /* @__PURE__ */
|
|
10161
|
+
/* @__PURE__ */ jsx14(Box14, { children: /* @__PURE__ */ jsxs14(Text14, { color: "red", children: [
|
|
9139
10162
|
"Failed to execute /init: ",
|
|
9140
10163
|
e?.message || String(e)
|
|
9141
10164
|
] }) })
|
|
@@ -9156,41 +10179,41 @@ var SlashCommands = ({
|
|
|
9156
10179
|
const colType = 10;
|
|
9157
10180
|
const colSource = 18;
|
|
9158
10181
|
return outBox(
|
|
9159
|
-
/* @__PURE__ */
|
|
9160
|
-
/* @__PURE__ */
|
|
9161
|
-
/* @__PURE__ */ jsx14(
|
|
9162
|
-
/* @__PURE__ */ jsx14(
|
|
9163
|
-
/* @__PURE__ */
|
|
10182
|
+
/* @__PURE__ */ jsxs14(Fragment2, { children: [
|
|
10183
|
+
/* @__PURE__ */ jsxs14(Box14, { marginBottom: 1, children: [
|
|
10184
|
+
/* @__PURE__ */ jsx14(Text14, { bold: true, color: BLUMA_TERMINAL.brandMagenta, children: "MCP Tools" }),
|
|
10185
|
+
/* @__PURE__ */ jsx14(Text14, { dimColor: true, children: " \u2022 " }),
|
|
10186
|
+
/* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
|
|
9164
10187
|
tools.length,
|
|
9165
10188
|
" total"
|
|
9166
10189
|
] }),
|
|
9167
|
-
term && /* @__PURE__ */
|
|
9168
|
-
/* @__PURE__ */ jsx14(
|
|
9169
|
-
/* @__PURE__ */
|
|
10190
|
+
term && /* @__PURE__ */ jsxs14(Fragment2, { children: [
|
|
10191
|
+
/* @__PURE__ */ jsx14(Text14, { dimColor: true, children: " \u2022 filter: " }),
|
|
10192
|
+
/* @__PURE__ */ jsxs14(Text14, { color: BLUMA_TERMINAL.brandBlue, children: [
|
|
9170
10193
|
'"',
|
|
9171
10194
|
term,
|
|
9172
10195
|
'"'
|
|
9173
10196
|
] }),
|
|
9174
|
-
/* @__PURE__ */
|
|
10197
|
+
/* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
|
|
9175
10198
|
" \u2022 showing: ",
|
|
9176
10199
|
filtered.length
|
|
9177
10200
|
] })
|
|
9178
10201
|
] })
|
|
9179
10202
|
] }),
|
|
9180
|
-
filtered.length === 0 ? /* @__PURE__ */ jsx14(
|
|
9181
|
-
/* @__PURE__ */ jsx14(Box14, { children: /* @__PURE__ */
|
|
10203
|
+
filtered.length === 0 ? /* @__PURE__ */ jsx14(Text14, { color: "yellow", children: "No MCP tools found" }) : /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
|
|
10204
|
+
/* @__PURE__ */ jsx14(Box14, { children: /* @__PURE__ */ jsxs14(Text14, { color: "gray", children: [
|
|
9182
10205
|
pad("Name", colName),
|
|
9183
10206
|
" \u2502 ",
|
|
9184
10207
|
pad("Type", colType),
|
|
9185
10208
|
" \u2502 ",
|
|
9186
10209
|
pad("Source", colSource)
|
|
9187
10210
|
] }) }),
|
|
9188
|
-
/* @__PURE__ */ jsx14(
|
|
10211
|
+
/* @__PURE__ */ jsx14(Text14, { color: "gray", children: "\u2500".repeat(colName + colType + colSource + 6) }),
|
|
9189
10212
|
filtered.map((t, i) => {
|
|
9190
10213
|
const name = t.function?.name || t.name || "tool";
|
|
9191
10214
|
const type = t.function?.name ? "fn" : t.type || "tool";
|
|
9192
10215
|
const source = t.source || t.provider || "mcp";
|
|
9193
|
-
return /* @__PURE__ */
|
|
10216
|
+
return /* @__PURE__ */ jsxs14(Text14, { color: "white", children: [
|
|
9194
10217
|
pad(name, colName),
|
|
9195
10218
|
" \u2502 ",
|
|
9196
10219
|
pad(String(type), colType),
|
|
@@ -9213,22 +10236,22 @@ var SlashCommands = ({
|
|
|
9213
10236
|
const colType = 10;
|
|
9214
10237
|
const colSource = 18;
|
|
9215
10238
|
return outBox(
|
|
9216
|
-
/* @__PURE__ */
|
|
9217
|
-
/* @__PURE__ */ jsx14(
|
|
9218
|
-
/* @__PURE__ */
|
|
10239
|
+
/* @__PURE__ */ jsxs14(Fragment2, { children: [
|
|
10240
|
+
/* @__PURE__ */ jsx14(Text14, { color: BLUMA_TERMINAL.brandMagenta, bold: true, children: "Native Tools" }),
|
|
10241
|
+
/* @__PURE__ */ jsxs14(Text14, { color: "gray", children: [
|
|
9219
10242
|
"Total Native: ",
|
|
9220
10243
|
tools.length,
|
|
9221
10244
|
term ? ` | Filter: "${term}" | Showing: ${filtered.length}` : ""
|
|
9222
10245
|
] }),
|
|
9223
|
-
filtered.length === 0 ? /* @__PURE__ */ jsx14(
|
|
9224
|
-
/* @__PURE__ */
|
|
10246
|
+
filtered.length === 0 ? /* @__PURE__ */ jsx14(Text14, { color: "yellow", children: "No native tools to display." }) : /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
|
|
10247
|
+
/* @__PURE__ */ jsxs14(Text14, { color: "gray", children: [
|
|
9225
10248
|
pad("Name", colName),
|
|
9226
10249
|
" | ",
|
|
9227
10250
|
pad("Type", colType),
|
|
9228
10251
|
" | ",
|
|
9229
10252
|
pad("Source", colSource)
|
|
9230
10253
|
] }),
|
|
9231
|
-
/* @__PURE__ */
|
|
10254
|
+
/* @__PURE__ */ jsxs14(Text14, { color: "gray", children: [
|
|
9232
10255
|
"".padEnd(colName, "-"),
|
|
9233
10256
|
"---",
|
|
9234
10257
|
"".padEnd(colType, "-"),
|
|
@@ -9239,7 +10262,7 @@ var SlashCommands = ({
|
|
|
9239
10262
|
const name = t.function?.name || t.name || "tool";
|
|
9240
10263
|
const type = t.function?.name ? "fn" : t.type || "tool";
|
|
9241
10264
|
const source = t.source || "native";
|
|
9242
|
-
return /* @__PURE__ */
|
|
10265
|
+
return /* @__PURE__ */ jsxs14(Text14, { color: "white", children: [
|
|
9243
10266
|
pad(name, colName),
|
|
9244
10267
|
" | ",
|
|
9245
10268
|
pad(String(type), colType),
|
|
@@ -9251,7 +10274,7 @@ var SlashCommands = ({
|
|
|
9251
10274
|
] })
|
|
9252
10275
|
);
|
|
9253
10276
|
}
|
|
9254
|
-
return outBox(/* @__PURE__ */
|
|
10277
|
+
return outBox(/* @__PURE__ */ jsxs14(Text14, { color: "red", children: [
|
|
9255
10278
|
"Command not recognized: /",
|
|
9256
10279
|
cmd
|
|
9257
10280
|
] }));
|
|
@@ -9265,16 +10288,16 @@ import latestVersion from "latest-version";
|
|
|
9265
10288
|
import semverGt from "semver/functions/gt.js";
|
|
9266
10289
|
import semverValid from "semver/functions/valid.js";
|
|
9267
10290
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
9268
|
-
import
|
|
9269
|
-
import
|
|
10291
|
+
import path25 from "path";
|
|
10292
|
+
import fs20 from "fs";
|
|
9270
10293
|
var BLUMA_PACKAGE_NAME = "@nomad-e/bluma-cli";
|
|
9271
10294
|
function findBlumaPackageJson(startDir) {
|
|
9272
10295
|
let dir = startDir;
|
|
9273
10296
|
for (let i = 0; i < 12; i++) {
|
|
9274
|
-
const candidate =
|
|
9275
|
-
if (
|
|
10297
|
+
const candidate = path25.join(dir, "package.json");
|
|
10298
|
+
if (fs20.existsSync(candidate)) {
|
|
9276
10299
|
try {
|
|
9277
|
-
const raw =
|
|
10300
|
+
const raw = fs20.readFileSync(candidate, "utf8");
|
|
9278
10301
|
const parsed = JSON.parse(raw);
|
|
9279
10302
|
if (parsed?.name === BLUMA_PACKAGE_NAME && parsed?.version) {
|
|
9280
10303
|
return { name: parsed.name, version: String(parsed.version) };
|
|
@@ -9282,7 +10305,7 @@ function findBlumaPackageJson(startDir) {
|
|
|
9282
10305
|
} catch {
|
|
9283
10306
|
}
|
|
9284
10307
|
}
|
|
9285
|
-
const parent =
|
|
10308
|
+
const parent = path25.dirname(dir);
|
|
9286
10309
|
if (parent === dir) break;
|
|
9287
10310
|
dir = parent;
|
|
9288
10311
|
}
|
|
@@ -9291,13 +10314,13 @@ function findBlumaPackageJson(startDir) {
|
|
|
9291
10314
|
function resolveInstalledBlumaPackage() {
|
|
9292
10315
|
const tried = /* @__PURE__ */ new Set();
|
|
9293
10316
|
const tryFrom = (dir) => {
|
|
9294
|
-
const abs =
|
|
10317
|
+
const abs = path25.resolve(dir);
|
|
9295
10318
|
if (tried.has(abs)) return null;
|
|
9296
10319
|
tried.add(abs);
|
|
9297
10320
|
return findBlumaPackageJson(abs);
|
|
9298
10321
|
};
|
|
9299
10322
|
try {
|
|
9300
|
-
const fromBundle = tryFrom(
|
|
10323
|
+
const fromBundle = tryFrom(path25.dirname(fileURLToPath4(import.meta.url)));
|
|
9301
10324
|
if (fromBundle) return fromBundle;
|
|
9302
10325
|
} catch {
|
|
9303
10326
|
}
|
|
@@ -9305,12 +10328,12 @@ function resolveInstalledBlumaPackage() {
|
|
|
9305
10328
|
if (argv1 && !argv1.startsWith("-")) {
|
|
9306
10329
|
try {
|
|
9307
10330
|
let resolved = argv1;
|
|
9308
|
-
if (
|
|
9309
|
-
resolved =
|
|
10331
|
+
if (path25.isAbsolute(argv1) && fs20.existsSync(argv1)) {
|
|
10332
|
+
resolved = fs20.realpathSync(argv1);
|
|
9310
10333
|
} else {
|
|
9311
|
-
resolved =
|
|
10334
|
+
resolved = path25.resolve(process.cwd(), argv1);
|
|
9312
10335
|
}
|
|
9313
|
-
const fromArgv = tryFrom(
|
|
10336
|
+
const fromArgv = tryFrom(path25.dirname(resolved));
|
|
9314
10337
|
if (fromArgv) return fromArgv;
|
|
9315
10338
|
} catch {
|
|
9316
10339
|
}
|
|
@@ -9354,8 +10377,8 @@ Run: npm i -g ${BLUMA_PACKAGE_NAME} to update.`;
|
|
|
9354
10377
|
}
|
|
9355
10378
|
|
|
9356
10379
|
// src/app/ui/components/UpdateNotice.tsx
|
|
9357
|
-
import { Box as Box15, Text as
|
|
9358
|
-
import { jsx as jsx15, jsxs as
|
|
10380
|
+
import { Box as Box15, Text as Text15 } from "ink";
|
|
10381
|
+
import { jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
9359
10382
|
function parseUpdateMessage(msg) {
|
|
9360
10383
|
const lines = msg.split(/\r?\n/).map((l) => l.trim());
|
|
9361
10384
|
const first = lines[0] || "";
|
|
@@ -9371,25 +10394,25 @@ function parseUpdateMessage(msg) {
|
|
|
9371
10394
|
}
|
|
9372
10395
|
var UpdateNotice = ({ message: message2 }) => {
|
|
9373
10396
|
const { name, current, latest: latest2, hint } = parseUpdateMessage(message2);
|
|
9374
|
-
return /* @__PURE__ */ jsx15(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */
|
|
9375
|
-
name && current && latest2 ? /* @__PURE__ */ jsx15(
|
|
9376
|
-
name && current && latest2 ? /* @__PURE__ */
|
|
10397
|
+
return /* @__PURE__ */ jsx15(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", paddingLeft: 2, children: [
|
|
10398
|
+
name && current && latest2 ? /* @__PURE__ */ jsx15(Text15, { color: BLUMA_TERMINAL.brandMagenta, bold: true, children: name }) : null,
|
|
10399
|
+
name && current && latest2 ? /* @__PURE__ */ jsxs15(Text15, { dimColor: true, children: [
|
|
9377
10400
|
current,
|
|
9378
10401
|
" \u2192 ",
|
|
9379
10402
|
latest2
|
|
9380
|
-
] }) : /* @__PURE__ */ jsx15(
|
|
9381
|
-
hint ? /* @__PURE__ */ jsx15(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx15(
|
|
10403
|
+
] }) : /* @__PURE__ */ jsx15(Text15, { dimColor: true, children: message2 }),
|
|
10404
|
+
hint ? /* @__PURE__ */ jsx15(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx15(Text15, { dimColor: true, children: hint }) }) : null
|
|
9382
10405
|
] }) });
|
|
9383
10406
|
};
|
|
9384
10407
|
var UpdateNotice_default = UpdateNotice;
|
|
9385
10408
|
|
|
9386
10409
|
// src/app/ui/components/ErrorMessage.tsx
|
|
9387
|
-
import { Box as Box16, Text as
|
|
9388
|
-
import { jsx as jsx16, jsxs as
|
|
9389
|
-
var ErrorMessage = ({ message: message2, details, hint }) => /* @__PURE__ */ jsx16(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */
|
|
9390
|
-
/* @__PURE__ */ jsx16(
|
|
9391
|
-
details ? /* @__PURE__ */ jsx16(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx16(
|
|
9392
|
-
hint ? /* @__PURE__ */ jsx16(Box16, { marginTop: 1, children: /* @__PURE__ */
|
|
10410
|
+
import { Box as Box16, Text as Text16 } from "ink";
|
|
10411
|
+
import { jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
10412
|
+
var ErrorMessage = ({ message: message2, details, hint }) => /* @__PURE__ */ jsx16(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", paddingLeft: 2, children: [
|
|
10413
|
+
/* @__PURE__ */ jsx16(Text16, { color: BLUMA_TERMINAL.err, children: message2 }),
|
|
10414
|
+
details ? /* @__PURE__ */ jsx16(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: details }) }) : null,
|
|
10415
|
+
hint ? /* @__PURE__ */ jsx16(Box16, { marginTop: 1, children: /* @__PURE__ */ jsxs16(Text16, { dimColor: true, children: [
|
|
9393
10416
|
"hint: ",
|
|
9394
10417
|
hint
|
|
9395
10418
|
] }) }) : null
|
|
@@ -9398,8 +10421,8 @@ var ErrorMessage_default = ErrorMessage;
|
|
|
9398
10421
|
|
|
9399
10422
|
// src/app/ui/components/ReasoningDisplay.tsx
|
|
9400
10423
|
import { memo as memo9 } from "react";
|
|
9401
|
-
import { Box as Box17, Text as
|
|
9402
|
-
import { jsx as jsx17, jsxs as
|
|
10424
|
+
import { Box as Box17, Text as Text17 } from "ink";
|
|
10425
|
+
import { jsx as jsx17, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
9403
10426
|
var ReasoningDisplayComponent = ({
|
|
9404
10427
|
reasoning,
|
|
9405
10428
|
collapsed = false
|
|
@@ -9411,9 +10434,9 @@ var ReasoningDisplayComponent = ({
|
|
|
9411
10434
|
const lines = reasoning.split("\n");
|
|
9412
10435
|
const displayLines = lines.slice(0, maxLines);
|
|
9413
10436
|
const truncated = lines.length > maxLines;
|
|
9414
|
-
return /* @__PURE__ */ jsx17(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */
|
|
9415
|
-
displayLines.map((line, i) => /* @__PURE__ */ jsx17(
|
|
9416
|
-
truncated ? /* @__PURE__ */
|
|
10437
|
+
return /* @__PURE__ */ jsx17(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", paddingLeft: 2, children: [
|
|
10438
|
+
displayLines.map((line, i) => /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: line }, i)),
|
|
10439
|
+
truncated ? /* @__PURE__ */ jsxs17(Text17, { dimColor: true, children: [
|
|
9417
10440
|
"\u2026 +",
|
|
9418
10441
|
lines.length - maxLines,
|
|
9419
10442
|
" lines"
|
|
@@ -9424,8 +10447,8 @@ var ReasoningDisplay = memo9(ReasoningDisplayComponent);
|
|
|
9424
10447
|
|
|
9425
10448
|
// src/app/ui/components/StreamingText.tsx
|
|
9426
10449
|
import { useState as useState5, useEffect as useEffect6, useRef as useRef4, memo as memo10 } from "react";
|
|
9427
|
-
import { Box as Box18, Text as
|
|
9428
|
-
import { jsx as jsx18, jsxs as
|
|
10450
|
+
import { Box as Box18, Text as Text18 } from "ink";
|
|
10451
|
+
import { jsx as jsx18, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
9429
10452
|
var StreamingTextComponent = ({
|
|
9430
10453
|
eventBus,
|
|
9431
10454
|
onReasoningComplete
|
|
@@ -9491,21 +10514,21 @@ var StreamingTextComponent = ({
|
|
|
9491
10514
|
truncatedCount = lines.length - MAX_VISIBLE_LINES;
|
|
9492
10515
|
displayLines = lines.slice(-MAX_VISIBLE_LINES);
|
|
9493
10516
|
}
|
|
9494
|
-
return /* @__PURE__ */ jsx18(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */
|
|
9495
|
-
truncatedCount > 0 ? /* @__PURE__ */
|
|
10517
|
+
return /* @__PURE__ */ jsx18(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", paddingLeft: 2, children: [
|
|
10518
|
+
truncatedCount > 0 ? /* @__PURE__ */ jsxs18(Text18, { dimColor: true, children: [
|
|
9496
10519
|
"\u2026 ",
|
|
9497
10520
|
truncatedCount,
|
|
9498
10521
|
" lines above hidden"
|
|
9499
10522
|
] }) : null,
|
|
9500
|
-
displayLines.map((line, i) => /* @__PURE__ */ jsx18(
|
|
10523
|
+
displayLines.map((line, i) => /* @__PURE__ */ jsx18(Text18, { dimColor: true, children: line }, i))
|
|
9501
10524
|
] }) });
|
|
9502
10525
|
};
|
|
9503
10526
|
var StreamingText = memo10(StreamingTextComponent);
|
|
9504
10527
|
|
|
9505
10528
|
// src/app/ui/components/ExpandedPreviewBlock.tsx
|
|
9506
10529
|
import { memo as memo11 } from "react";
|
|
9507
|
-
import { Box as Box19, Text as
|
|
9508
|
-
import { jsx as jsx19, jsxs as
|
|
10530
|
+
import { Box as Box19, Text as Text19 } from "ink";
|
|
10531
|
+
import { jsx as jsx19, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
9509
10532
|
function ExpandedPreviewBlockComponent({ data }) {
|
|
9510
10533
|
const cols = typeof process.stdout?.columns === "number" ? process.stdout.columns : 80;
|
|
9511
10534
|
const rule = TERMINAL_RULE_CHAR.repeat(Math.max(8, cols));
|
|
@@ -9513,50 +10536,35 @@ function ExpandedPreviewBlockComponent({ data }) {
|
|
|
9513
10536
|
const cap = EXPAND_OVERLAY_MAX_LINES;
|
|
9514
10537
|
const shown = lines.slice(0, cap);
|
|
9515
10538
|
const rest = lines.length - cap;
|
|
9516
|
-
return /* @__PURE__ */
|
|
9517
|
-
/* @__PURE__ */ jsx19(
|
|
9518
|
-
/* @__PURE__ */
|
|
9519
|
-
/* @__PURE__ */ jsx19(
|
|
9520
|
-
/* @__PURE__ */ jsx19(
|
|
9521
|
-
/* @__PURE__ */
|
|
10539
|
+
return /* @__PURE__ */ jsxs19(ChatBlock, { marginBottom: 1, children: [
|
|
10540
|
+
/* @__PURE__ */ jsx19(Text19, { color: "white", children: rule }),
|
|
10541
|
+
/* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", paddingLeft: 1, children: [
|
|
10542
|
+
/* @__PURE__ */ jsx19(Text19, { color: BLUMA_TERMINAL.brandMagenta, bold: true, children: "expand (Ctrl+O)" }),
|
|
10543
|
+
/* @__PURE__ */ jsx19(Text19, { dimColor: true, children: data.title }),
|
|
10544
|
+
/* @__PURE__ */ jsxs19(Text19, { dimColor: true, children: [
|
|
9522
10545
|
"+",
|
|
9523
10546
|
data.linesHidden,
|
|
9524
10547
|
" lines were clipped in chat \xB7 below: up to ",
|
|
9525
10548
|
cap,
|
|
9526
10549
|
" lines \xB7 use read_file_lines before edit_tool"
|
|
9527
10550
|
] }),
|
|
9528
|
-
/* @__PURE__ */
|
|
9529
|
-
shown.map((line, i) => /* @__PURE__ */ jsx19(
|
|
9530
|
-
rest > 0 ? /* @__PURE__ */
|
|
10551
|
+
/* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", marginTop: 1, children: [
|
|
10552
|
+
shown.map((line, i) => /* @__PURE__ */ jsx19(Text19, { dimColor: true, children: line.slice(0, 200) }, i)),
|
|
10553
|
+
rest > 0 ? /* @__PURE__ */ jsxs19(Text19, { dimColor: true, children: [
|
|
9531
10554
|
"\u2026 +",
|
|
9532
10555
|
rest,
|
|
9533
10556
|
" more lines in this chunk"
|
|
9534
10557
|
] }) : null
|
|
9535
10558
|
] })
|
|
9536
10559
|
] }),
|
|
9537
|
-
/* @__PURE__ */ jsx19(
|
|
10560
|
+
/* @__PURE__ */ jsx19(Text19, { color: "white", children: rule })
|
|
9538
10561
|
] });
|
|
9539
10562
|
}
|
|
9540
10563
|
var ExpandedPreviewBlock = memo11(ExpandedPreviewBlockComponent);
|
|
9541
10564
|
|
|
9542
10565
|
// src/app/ui/App.tsx
|
|
9543
|
-
import { jsx as jsx20, jsxs as
|
|
10566
|
+
import { jsx as jsx20, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
9544
10567
|
var blumaUpdateRegistryCheckStarted = false;
|
|
9545
|
-
var SAFE_AUTO_APPROVE_TOOLS = [
|
|
9546
|
-
// Comunicação/UI
|
|
9547
|
-
"message",
|
|
9548
|
-
"todo",
|
|
9549
|
-
"task_boundary",
|
|
9550
|
-
// Leitura de ficheiros (read-only)
|
|
9551
|
-
"ls_tool",
|
|
9552
|
-
"read_file_lines",
|
|
9553
|
-
"count_file_lines",
|
|
9554
|
-
"view_file_outline",
|
|
9555
|
-
"find_by_name",
|
|
9556
|
-
"grep_search",
|
|
9557
|
-
// Status de comandos (read-only)
|
|
9558
|
-
"command_status"
|
|
9559
|
-
];
|
|
9560
10568
|
function trimRecentActivity(s, max = 72) {
|
|
9561
10569
|
const t = String(s ?? "").replace(/\s+/g, " ").trim();
|
|
9562
10570
|
if (!t) return "";
|
|
@@ -9579,7 +10587,7 @@ function UserMessageWithOptionalImages({
|
|
|
9579
10587
|
caption: cap.length > 0 ? capDisp : null,
|
|
9580
10588
|
captionDim: true
|
|
9581
10589
|
}
|
|
9582
|
-
) : /* @__PURE__ */ jsx20(
|
|
10590
|
+
) : /* @__PURE__ */ jsx20(Text20, { dimColor: true, wrap: "wrap", children: fallbackDisp }) });
|
|
9583
10591
|
}
|
|
9584
10592
|
const displayRaw = raw.length > 1e4 ? `${raw.substring(0, 1e4)}...` : raw;
|
|
9585
10593
|
const paths = collectImagePathStrings(displayRaw);
|
|
@@ -9590,7 +10598,7 @@ function UserMessageWithOptionalImages({
|
|
|
9590
10598
|
imageCount: paths.length,
|
|
9591
10599
|
caption: stripped.trim().length > 0 ? stripped : null
|
|
9592
10600
|
}
|
|
9593
|
-
) : /* @__PURE__ */ jsx20(
|
|
10601
|
+
) : /* @__PURE__ */ jsx20(Text20, { wrap: "wrap", children: displayRaw }) });
|
|
9594
10602
|
}
|
|
9595
10603
|
var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
|
|
9596
10604
|
const agentInstance = useRef5(null);
|
|
@@ -9611,6 +10619,10 @@ var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
|
|
|
9611
10619
|
);
|
|
9612
10620
|
const [isInitAgentActive, setIsInitAgentActive] = useState6(false);
|
|
9613
10621
|
const [recentActivityLine, setRecentActivityLine] = useState6(null);
|
|
10622
|
+
const [taskSummary, setTaskSummary] = useState6({
|
|
10623
|
+
activeTaskSummary: null,
|
|
10624
|
+
taskProgressSummary: null
|
|
10625
|
+
});
|
|
9614
10626
|
const alwaysAcceptList = useRef5([]);
|
|
9615
10627
|
const workdir = process.cwd();
|
|
9616
10628
|
const turnStartedAtRef = useRef5(null);
|
|
@@ -9648,11 +10660,11 @@ var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
|
|
|
9648
10660
|
void checkForUpdates().then((msg) => {
|
|
9649
10661
|
if (!msg) return;
|
|
9650
10662
|
setHistory((prev) => {
|
|
9651
|
-
const
|
|
10663
|
+
const nextId2 = prev.length === 0 ? 1 : Math.max(...prev.map((h) => h.id), HEADER_PANEL_HISTORY_ID) + 1;
|
|
9652
10664
|
return [
|
|
9653
10665
|
...prev,
|
|
9654
10666
|
{
|
|
9655
|
-
id:
|
|
10667
|
+
id: nextId2,
|
|
9656
10668
|
component: /* @__PURE__ */ jsx20(UpdateNotice_default, { message: msg })
|
|
9657
10669
|
}
|
|
9658
10670
|
];
|
|
@@ -9671,14 +10683,16 @@ var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
|
|
|
9671
10683
|
sessionId,
|
|
9672
10684
|
workdir,
|
|
9673
10685
|
cliVersion,
|
|
9674
|
-
recentActivitySummary: recentActivityLine
|
|
10686
|
+
recentActivitySummary: recentActivityLine,
|
|
10687
|
+
activeTaskSummary: taskSummary.activeTaskSummary,
|
|
10688
|
+
taskProgressSummary: taskSummary.taskProgressSummary
|
|
9675
10689
|
}
|
|
9676
10690
|
)
|
|
9677
10691
|
},
|
|
9678
10692
|
...tail
|
|
9679
10693
|
];
|
|
9680
10694
|
});
|
|
9681
|
-
}, [sessionId, workdir, cliVersion, recentActivityLine]);
|
|
10695
|
+
}, [sessionId, workdir, cliVersion, recentActivityLine, taskSummary]);
|
|
9682
10696
|
const handleInterrupt = useCallback3(() => {
|
|
9683
10697
|
if (!isProcessing) return;
|
|
9684
10698
|
eventBus.emit("user_interrupt");
|
|
@@ -9739,7 +10753,7 @@ var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
|
|
|
9739
10753
|
...prev,
|
|
9740
10754
|
{
|
|
9741
10755
|
id: prev.length,
|
|
9742
|
-
component: /* @__PURE__ */ jsx20(ChatUserMessage, { children: /* @__PURE__ */ jsx20(
|
|
10756
|
+
component: /* @__PURE__ */ jsx20(ChatUserMessage, { children: /* @__PURE__ */ jsx20(Text20, { dimColor: true, children: text }) })
|
|
9743
10757
|
},
|
|
9744
10758
|
{
|
|
9745
10759
|
id: prev.length + 1,
|
|
@@ -9768,7 +10782,7 @@ var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
|
|
|
9768
10782
|
...prev,
|
|
9769
10783
|
{
|
|
9770
10784
|
id: prev.length,
|
|
9771
|
-
component: /* @__PURE__ */ jsx20(ChatUserMessage, { children: /* @__PURE__ */
|
|
10785
|
+
component: /* @__PURE__ */ jsx20(ChatUserMessage, { children: /* @__PURE__ */ jsxs20(Text20, { bold: true, color: "white", children: [
|
|
9772
10786
|
"$ !",
|
|
9773
10787
|
command
|
|
9774
10788
|
] }) })
|
|
@@ -9791,7 +10805,7 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
9791
10805
|
...prev,
|
|
9792
10806
|
{
|
|
9793
10807
|
id: prev.length,
|
|
9794
|
-
component: /* @__PURE__ */
|
|
10808
|
+
component: /* @__PURE__ */ jsxs20(Text20, { color: "red", children: [
|
|
9795
10809
|
"Failed to execute: ",
|
|
9796
10810
|
result.error || result.message
|
|
9797
10811
|
] })
|
|
@@ -9805,7 +10819,7 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
9805
10819
|
...prev,
|
|
9806
10820
|
{
|
|
9807
10821
|
id: prev.length,
|
|
9808
|
-
component: /* @__PURE__ */
|
|
10822
|
+
component: /* @__PURE__ */ jsxs20(Text20, { color: "red", children: [
|
|
9809
10823
|
"Error: ",
|
|
9810
10824
|
err.message
|
|
9811
10825
|
] })
|
|
@@ -9871,6 +10885,16 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
9871
10885
|
};
|
|
9872
10886
|
const handleBackendMessage = (parsed) => {
|
|
9873
10887
|
try {
|
|
10888
|
+
const updateTaskSummaryFromResult = () => {
|
|
10889
|
+
const activeTask = parsed?.activeTask;
|
|
10890
|
+
const stats = parsed?.stats;
|
|
10891
|
+
if (activeTask || stats) {
|
|
10892
|
+
setTaskSummary({
|
|
10893
|
+
activeTaskSummary: activeTask ? `${String(activeTask.mode || "EXECUTION")} \xB7 ${String(activeTask.taskName || "")}${activeTask.status ? ` \xB7 ${String(activeTask.status)}` : ""}` : null,
|
|
10894
|
+
taskProgressSummary: stats && typeof stats.total === "number" ? `${stats.completed ?? 0}/${stats.total ?? 0} done \xB7 ${stats.pending ?? 0} pending \xB7 ${stats.inProgress ?? 0} in progress \xB7 ${stats.progress ?? 0}%` : null
|
|
10895
|
+
});
|
|
10896
|
+
}
|
|
10897
|
+
};
|
|
9874
10898
|
const appendTurnDurationIfAny = () => {
|
|
9875
10899
|
const t = turnStartedAtRef.current;
|
|
9876
10900
|
if (t == null) return;
|
|
@@ -9893,7 +10917,8 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
9893
10917
|
}
|
|
9894
10918
|
if (parsed.type === "confirmation_request") {
|
|
9895
10919
|
const toolToConfirm = parsed.tool_calls[0].function.name;
|
|
9896
|
-
|
|
10920
|
+
const policyAutoApprove = parsed.tool_policy?.autoApprove === true;
|
|
10921
|
+
if (policyAutoApprove) {
|
|
9897
10922
|
handleConfirmation("accept", parsed.tool_calls);
|
|
9898
10923
|
return;
|
|
9899
10924
|
}
|
|
@@ -9929,9 +10954,9 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
9929
10954
|
if (parsed.type === "debug") {
|
|
9930
10955
|
newComponent = /* @__PURE__ */ jsx20(ChatMeta, { children: parsed.message });
|
|
9931
10956
|
} else if (parsed.type === "protocol_violation") {
|
|
9932
|
-
newComponent = /* @__PURE__ */ jsx20(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */
|
|
9933
|
-
/* @__PURE__ */ jsx20(
|
|
9934
|
-
/* @__PURE__ */ jsx20(
|
|
10957
|
+
newComponent = /* @__PURE__ */ jsx20(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", paddingLeft: 2, children: [
|
|
10958
|
+
/* @__PURE__ */ jsx20(Text20, { dimColor: true, children: parsed.content }),
|
|
10959
|
+
/* @__PURE__ */ jsx20(Text20, { dimColor: true, children: parsed.message })
|
|
9935
10960
|
] }) });
|
|
9936
10961
|
} else if (parsed.type === "error") {
|
|
9937
10962
|
newComponent = /* @__PURE__ */ jsx20(
|
|
@@ -9951,10 +10976,12 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
9951
10976
|
{
|
|
9952
10977
|
toolName: parsed.tool_name,
|
|
9953
10978
|
args: parsed.arguments,
|
|
9954
|
-
preview: parsed.preview
|
|
10979
|
+
preview: parsed.preview,
|
|
10980
|
+
toolPolicy: parsed.tool_policy
|
|
9955
10981
|
}
|
|
9956
10982
|
);
|
|
9957
10983
|
} else if (parsed.type === "tool_result") {
|
|
10984
|
+
updateTaskSummaryFromResult();
|
|
9958
10985
|
newComponent = /* @__PURE__ */ jsx20(
|
|
9959
10986
|
ToolResultDisplay,
|
|
9960
10987
|
{
|
|
@@ -9968,11 +10995,11 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
9968
10995
|
`Context: ${trimRecentActivity(String(parsed.payload))}`
|
|
9969
10996
|
);
|
|
9970
10997
|
}
|
|
9971
|
-
newComponent = /* @__PURE__ */ jsx20(ChatUserMessage, { children: /* @__PURE__ */ jsx20(
|
|
10998
|
+
newComponent = /* @__PURE__ */ jsx20(ChatUserMessage, { children: /* @__PURE__ */ jsx20(Text20, { dimColor: true, children: parsed.payload }) });
|
|
9972
10999
|
} else if (parsed.type === "reasoning") {
|
|
9973
11000
|
newComponent = /* @__PURE__ */ jsx20(ReasoningDisplay, { reasoning: parsed.content });
|
|
9974
11001
|
} else if (parsed.type === "log") {
|
|
9975
|
-
newComponent = /* @__PURE__ */
|
|
11002
|
+
newComponent = /* @__PURE__ */ jsxs20(ChatMeta, { children: [
|
|
9976
11003
|
parsed.message,
|
|
9977
11004
|
parsed.payload ? `: ${parsed.payload}` : ""
|
|
9978
11005
|
] });
|
|
@@ -10036,7 +11063,7 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
10036
11063
|
}
|
|
10037
11064
|
);
|
|
10038
11065
|
}
|
|
10039
|
-
return /* @__PURE__ */
|
|
11066
|
+
return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", children: [
|
|
10040
11067
|
isProcessing && !pendingConfirmation && /* @__PURE__ */ jsx20(WorkingTimer, { eventBus }),
|
|
10041
11068
|
/* @__PURE__ */ jsx20(
|
|
10042
11069
|
InputPrompt,
|
|
@@ -10049,7 +11076,7 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
10049
11076
|
)
|
|
10050
11077
|
] });
|
|
10051
11078
|
};
|
|
10052
|
-
return /* @__PURE__ */
|
|
11079
|
+
return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", children: [
|
|
10053
11080
|
/* @__PURE__ */ jsx20(Static, { items: history, children: (item) => /* @__PURE__ */ jsx20(Box20, { children: item.component }, item.id) }),
|
|
10054
11081
|
/* @__PURE__ */ jsx20(
|
|
10055
11082
|
StreamingText,
|
|
@@ -10148,20 +11175,90 @@ function writeJsonl(event) {
|
|
|
10148
11175
|
} catch {
|
|
10149
11176
|
}
|
|
10150
11177
|
}
|
|
11178
|
+
function writeAgentEvent(sessionId, event) {
|
|
11179
|
+
writeJsonl(event);
|
|
11180
|
+
if (sessionId) {
|
|
11181
|
+
appendSessionLog(sessionId, event);
|
|
11182
|
+
}
|
|
11183
|
+
}
|
|
11184
|
+
function finalizeSession(sessionId, status, metadata) {
|
|
11185
|
+
updateSession(sessionId, {
|
|
11186
|
+
status,
|
|
11187
|
+
pid: process.pid,
|
|
11188
|
+
metadata: metadata ? { ...getSession(sessionId)?.metadata, ...metadata } : getSession(sessionId)?.metadata
|
|
11189
|
+
});
|
|
11190
|
+
}
|
|
11191
|
+
function installSessionLifecycle(sessionId) {
|
|
11192
|
+
let finalized = false;
|
|
11193
|
+
const safeFinalize = (status, metadata) => {
|
|
11194
|
+
if (finalized) return;
|
|
11195
|
+
finalized = true;
|
|
11196
|
+
finalizeSession(sessionId, status, metadata);
|
|
11197
|
+
};
|
|
11198
|
+
process.once("exit", (code) => {
|
|
11199
|
+
safeFinalize(code === 0 ? "completed" : "error", { exitCode: code ?? 0 });
|
|
11200
|
+
});
|
|
11201
|
+
process.once("SIGINT", () => {
|
|
11202
|
+
safeFinalize("cancelled", { signal: "SIGINT" });
|
|
11203
|
+
process.exit(130);
|
|
11204
|
+
});
|
|
11205
|
+
process.once("SIGTERM", () => {
|
|
11206
|
+
safeFinalize("cancelled", { signal: "SIGTERM" });
|
|
11207
|
+
process.exit(143);
|
|
11208
|
+
});
|
|
11209
|
+
process.once("uncaughtException", (error) => {
|
|
11210
|
+
safeFinalize("error", { uncaughtException: error instanceof Error ? error.message : String(error) });
|
|
11211
|
+
throw error;
|
|
11212
|
+
});
|
|
11213
|
+
}
|
|
11214
|
+
function formatSessionLine(session) {
|
|
11215
|
+
return `${session.sessionId} ${session.kind} ${session.status} ${session.updatedAt} ${session.title}`;
|
|
11216
|
+
}
|
|
11217
|
+
function formatLogLine(line) {
|
|
11218
|
+
try {
|
|
11219
|
+
const parsed = JSON.parse(line);
|
|
11220
|
+
const ts = parsed.timestamp || (/* @__PURE__ */ new Date()).toISOString();
|
|
11221
|
+
if (parsed.event_type === "log") {
|
|
11222
|
+
return `[${ts}] ${parsed.level.toUpperCase()} ${parsed.message}`;
|
|
11223
|
+
}
|
|
11224
|
+
if (parsed.event_type === "backend_message") {
|
|
11225
|
+
return `[${ts}] EVENT ${parsed.backend_type}`;
|
|
11226
|
+
}
|
|
11227
|
+
if (parsed.event_type === "action_status") {
|
|
11228
|
+
return `[${ts}] STATUS ${JSON.stringify(parsed.payload)}`;
|
|
11229
|
+
}
|
|
11230
|
+
if (parsed.event_type === "result") {
|
|
11231
|
+
return `[${ts}] RESULT ${parsed.status}`;
|
|
11232
|
+
}
|
|
11233
|
+
} catch {
|
|
11234
|
+
}
|
|
11235
|
+
return line;
|
|
11236
|
+
}
|
|
11237
|
+
function isProcessAlive(pid) {
|
|
11238
|
+
if (!pid || pid <= 0) return false;
|
|
11239
|
+
try {
|
|
11240
|
+
process.kill(pid, 0);
|
|
11241
|
+
return true;
|
|
11242
|
+
} catch {
|
|
11243
|
+
return false;
|
|
11244
|
+
}
|
|
11245
|
+
}
|
|
10151
11246
|
async function runAgentMode() {
|
|
10152
11247
|
const args = process.argv.slice(2);
|
|
10153
11248
|
const inputFileIndex = args.indexOf("--input-file");
|
|
10154
|
-
const
|
|
11249
|
+
const backgroundWorker = args.includes("--background-worker");
|
|
11250
|
+
const registrySessionIndex = args.indexOf("--registry-session");
|
|
11251
|
+
const registrySessionId = registrySessionIndex !== -1 && args[registrySessionIndex + 1] ? args[registrySessionIndex + 1] : null;
|
|
10155
11252
|
let rawPayload = "";
|
|
10156
11253
|
try {
|
|
10157
11254
|
if (inputFileIndex !== -1 && args[inputFileIndex + 1]) {
|
|
10158
11255
|
const filePath = args[inputFileIndex + 1];
|
|
10159
|
-
rawPayload =
|
|
11256
|
+
rawPayload = fs21.readFileSync(filePath, "utf-8");
|
|
10160
11257
|
} else {
|
|
10161
|
-
rawPayload =
|
|
11258
|
+
rawPayload = fs21.readFileSync(0, "utf-8");
|
|
10162
11259
|
}
|
|
10163
11260
|
} catch (err) {
|
|
10164
|
-
|
|
11261
|
+
writeAgentEvent(registrySessionId, {
|
|
10165
11262
|
event_type: "result",
|
|
10166
11263
|
status: "error",
|
|
10167
11264
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -10177,7 +11274,7 @@ async function runAgentMode() {
|
|
|
10177
11274
|
try {
|
|
10178
11275
|
envelope = JSON.parse(rawPayload);
|
|
10179
11276
|
} catch (err) {
|
|
10180
|
-
|
|
11277
|
+
writeAgentEvent(registrySessionId, {
|
|
10181
11278
|
event_type: "result",
|
|
10182
11279
|
status: "error",
|
|
10183
11280
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -10196,7 +11293,9 @@ async function runAgentMode() {
|
|
|
10196
11293
|
}
|
|
10197
11294
|
}
|
|
10198
11295
|
const eventBus = new EventEmitter3();
|
|
10199
|
-
const sessionId = envelope.session_id || envelope.message_id ||
|
|
11296
|
+
const sessionId = registrySessionId || envelope.session_id || envelope.message_id || uuidv47();
|
|
11297
|
+
process.env.BLUMA_SESSION_ID = sessionId;
|
|
11298
|
+
installSessionLifecycle(sessionId);
|
|
10200
11299
|
const uc = envelope.user_context;
|
|
10201
11300
|
const userContextInput = {
|
|
10202
11301
|
sessionId,
|
|
@@ -10208,13 +11307,27 @@ async function runAgentMode() {
|
|
|
10208
11307
|
companyId: uc?.companyId ?? null,
|
|
10209
11308
|
companyName: uc?.companyName ?? null
|
|
10210
11309
|
};
|
|
11310
|
+
registerSession({
|
|
11311
|
+
sessionId,
|
|
11312
|
+
kind: "agent",
|
|
11313
|
+
status: "running",
|
|
11314
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11315
|
+
workdir: process.cwd(),
|
|
11316
|
+
title: backgroundWorker ? `background:${envelope.action || "unknown"}` : `agent:${envelope.action || "unknown"}`,
|
|
11317
|
+
pid: process.pid,
|
|
11318
|
+
metadata: {
|
|
11319
|
+
message_id: envelope.message_id || null,
|
|
11320
|
+
action: envelope.action || null,
|
|
11321
|
+
background: backgroundWorker
|
|
11322
|
+
}
|
|
11323
|
+
});
|
|
10211
11324
|
let lastAssistantMessage = null;
|
|
10212
11325
|
let reasoningBuffer = null;
|
|
10213
11326
|
let lastAttachments = null;
|
|
10214
11327
|
let resultEmitted = false;
|
|
10215
11328
|
eventBus.on("backend_message", (payload) => {
|
|
10216
11329
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
10217
|
-
|
|
11330
|
+
writeAgentEvent(sessionId, {
|
|
10218
11331
|
event_type: "backend_message",
|
|
10219
11332
|
backend_type: String(payload?.type || "unknown"),
|
|
10220
11333
|
timestamp,
|
|
@@ -10245,7 +11358,8 @@ async function runAgentMode() {
|
|
|
10245
11358
|
}
|
|
10246
11359
|
if (!resultEmitted && payload?.type === "done") {
|
|
10247
11360
|
resultEmitted = true;
|
|
10248
|
-
|
|
11361
|
+
finalizeSession(sessionId, "completed", { finishedBy: "done-event" });
|
|
11362
|
+
writeAgentEvent(sessionId, {
|
|
10249
11363
|
event_type: "result",
|
|
10250
11364
|
status: "success",
|
|
10251
11365
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -10261,7 +11375,7 @@ async function runAgentMode() {
|
|
|
10261
11375
|
}
|
|
10262
11376
|
});
|
|
10263
11377
|
eventBus.on("action_status", (payload) => {
|
|
10264
|
-
|
|
11378
|
+
writeAgentEvent(sessionId, {
|
|
10265
11379
|
event_type: "action_status",
|
|
10266
11380
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
10267
11381
|
payload
|
|
@@ -10270,7 +11384,7 @@ async function runAgentMode() {
|
|
|
10270
11384
|
eventBus.on("stream_reasoning_chunk", (payload) => {
|
|
10271
11385
|
reasoningBuffer = (reasoningBuffer || "") + (payload?.delta || "");
|
|
10272
11386
|
});
|
|
10273
|
-
|
|
11387
|
+
writeAgentEvent(sessionId, {
|
|
10274
11388
|
event_type: "log",
|
|
10275
11389
|
level: "info",
|
|
10276
11390
|
message: "Starting agent mode execution",
|
|
@@ -10295,7 +11409,8 @@ async function runAgentMode() {
|
|
|
10295
11409
|
await agent.processTurn({ content: userContent }, userContextInput);
|
|
10296
11410
|
if (!resultEmitted) {
|
|
10297
11411
|
resultEmitted = true;
|
|
10298
|
-
|
|
11412
|
+
finalizeSession(sessionId, "completed", { finishedBy: "post-turn-fallback" });
|
|
11413
|
+
writeAgentEvent(sessionId, {
|
|
10299
11414
|
event_type: "result",
|
|
10300
11415
|
status: "success",
|
|
10301
11416
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -10311,7 +11426,8 @@ async function runAgentMode() {
|
|
|
10311
11426
|
}
|
|
10312
11427
|
} catch (err) {
|
|
10313
11428
|
if (!resultEmitted) {
|
|
10314
|
-
|
|
11429
|
+
finalizeSession(sessionId, "error", { finishedBy: "exception" });
|
|
11430
|
+
writeAgentEvent(sessionId, {
|
|
10315
11431
|
event_type: "result",
|
|
10316
11432
|
status: "error",
|
|
10317
11433
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -10326,29 +11442,177 @@ async function runAgentMode() {
|
|
|
10326
11442
|
}
|
|
10327
11443
|
function readCliPackageVersion() {
|
|
10328
11444
|
try {
|
|
10329
|
-
const base =
|
|
10330
|
-
const pkgPath =
|
|
10331
|
-
const j = JSON.parse(
|
|
11445
|
+
const base = path26.dirname(fileURLToPath5(import.meta.url));
|
|
11446
|
+
const pkgPath = path26.join(base, "..", "package.json");
|
|
11447
|
+
const j = JSON.parse(fs21.readFileSync(pkgPath, "utf8"));
|
|
10332
11448
|
return String(j.version || "0.0.0");
|
|
10333
11449
|
} catch {
|
|
10334
11450
|
return "0.0.0";
|
|
10335
11451
|
}
|
|
10336
11452
|
}
|
|
10337
|
-
function runCliMode() {
|
|
11453
|
+
function runCliMode(sessionId) {
|
|
10338
11454
|
const BLUMA_TITLE = process.env.BLUMA_TITLE || "BluMa - NomadEngenuity";
|
|
10339
11455
|
startTitleKeeper(BLUMA_TITLE);
|
|
10340
11456
|
const eventBus = new EventEmitter3();
|
|
10341
|
-
const
|
|
11457
|
+
const resolvedSessionId = sessionId || uuidv47();
|
|
11458
|
+
process.env.BLUMA_SESSION_ID = resolvedSessionId;
|
|
11459
|
+
registerSession({
|
|
11460
|
+
sessionId: resolvedSessionId,
|
|
11461
|
+
kind: "interactive",
|
|
11462
|
+
status: "running",
|
|
11463
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11464
|
+
workdir: process.cwd(),
|
|
11465
|
+
title: "interactive-cli",
|
|
11466
|
+
pid: process.pid,
|
|
11467
|
+
metadata: {}
|
|
11468
|
+
});
|
|
11469
|
+
installSessionLifecycle(resolvedSessionId);
|
|
10342
11470
|
const props = {
|
|
10343
11471
|
eventBus,
|
|
10344
|
-
sessionId,
|
|
11472
|
+
sessionId: resolvedSessionId,
|
|
10345
11473
|
cliVersion: readCliPackageVersion()
|
|
10346
11474
|
};
|
|
10347
|
-
render(React12.createElement(App_default, props));
|
|
11475
|
+
const instance = render(React12.createElement(App_default, props));
|
|
11476
|
+
void instance.waitUntilExit().then(() => {
|
|
11477
|
+
finalizeSession(resolvedSessionId, "completed", { finishedBy: "interactive-exit" });
|
|
11478
|
+
});
|
|
11479
|
+
}
|
|
11480
|
+
function printSessions() {
|
|
11481
|
+
const sessions = listSessions();
|
|
11482
|
+
if (sessions.length === 0) {
|
|
11483
|
+
console.log("No sessions registered.");
|
|
11484
|
+
return;
|
|
11485
|
+
}
|
|
11486
|
+
for (const session of sessions) {
|
|
11487
|
+
console.log(formatSessionLine(session));
|
|
11488
|
+
}
|
|
11489
|
+
}
|
|
11490
|
+
function printSessionStatus(sessionId) {
|
|
11491
|
+
const session = getSession(sessionId);
|
|
11492
|
+
if (!session) {
|
|
11493
|
+
console.error(`Unknown session: ${sessionId}`);
|
|
11494
|
+
process.exit(1);
|
|
11495
|
+
return;
|
|
11496
|
+
}
|
|
11497
|
+
const alive = session.status === "running" ? isProcessAlive(session.pid) : false;
|
|
11498
|
+
console.log(JSON.stringify({
|
|
11499
|
+
...session,
|
|
11500
|
+
alive
|
|
11501
|
+
}, null, 2));
|
|
11502
|
+
}
|
|
11503
|
+
function printLogs(sessionId) {
|
|
11504
|
+
const session = getSession(sessionId);
|
|
11505
|
+
if (!session) {
|
|
11506
|
+
console.error(`Unknown session: ${sessionId}`);
|
|
11507
|
+
process.exit(1);
|
|
11508
|
+
}
|
|
11509
|
+
const lines = readSessionLog(sessionId);
|
|
11510
|
+
for (const line of lines) {
|
|
11511
|
+
console.log(formatLogLine(line));
|
|
11512
|
+
}
|
|
11513
|
+
}
|
|
11514
|
+
async function attachToSession(sessionId) {
|
|
11515
|
+
const session = getSession(sessionId);
|
|
11516
|
+
if (!session) {
|
|
11517
|
+
console.error(`Unknown session: ${sessionId}`);
|
|
11518
|
+
process.exit(1);
|
|
11519
|
+
return;
|
|
11520
|
+
}
|
|
11521
|
+
let cursor = 0;
|
|
11522
|
+
while (true) {
|
|
11523
|
+
const lines = readSessionLog(sessionId);
|
|
11524
|
+
const next = lines.slice(cursor);
|
|
11525
|
+
cursor = lines.length;
|
|
11526
|
+
for (const line of next) {
|
|
11527
|
+
console.log(formatLogLine(line));
|
|
11528
|
+
}
|
|
11529
|
+
const latest2 = getSession(sessionId);
|
|
11530
|
+
if (!latest2 || latest2.status !== "running") {
|
|
11531
|
+
return;
|
|
11532
|
+
}
|
|
11533
|
+
await new Promise((resolve2) => setTimeout(resolve2, 1e3));
|
|
11534
|
+
}
|
|
11535
|
+
}
|
|
11536
|
+
function killSession(sessionId) {
|
|
11537
|
+
const session = getSession(sessionId);
|
|
11538
|
+
if (!session) {
|
|
11539
|
+
console.error(`Unknown session: ${sessionId}`);
|
|
11540
|
+
process.exit(1);
|
|
11541
|
+
return;
|
|
11542
|
+
}
|
|
11543
|
+
if (session.status !== "running") {
|
|
11544
|
+
console.log(`Session ${sessionId} is already ${session.status}.`);
|
|
11545
|
+
return;
|
|
11546
|
+
}
|
|
11547
|
+
if (!session.pid || !isProcessAlive(session.pid)) {
|
|
11548
|
+
updateSession(sessionId, {
|
|
11549
|
+
status: "cancelled",
|
|
11550
|
+
metadata: { ...session.metadata, signal: "stale-process" }
|
|
11551
|
+
});
|
|
11552
|
+
console.log(`Session ${sessionId} was marked as cancelled because its process is not running.`);
|
|
11553
|
+
return;
|
|
11554
|
+
}
|
|
11555
|
+
process.kill(session.pid, "SIGTERM");
|
|
11556
|
+
updateSession(sessionId, {
|
|
11557
|
+
status: "cancelled",
|
|
11558
|
+
metadata: { ...session.metadata, signal: "SIGTERM" }
|
|
11559
|
+
});
|
|
11560
|
+
console.log(`Sent SIGTERM to session ${sessionId} (${session.pid}).`);
|
|
11561
|
+
}
|
|
11562
|
+
function startBackgroundAgent() {
|
|
11563
|
+
const args = process.argv.slice(2);
|
|
11564
|
+
const inputFileIndex = args.indexOf("--input-file");
|
|
11565
|
+
if (inputFileIndex === -1 || !args[inputFileIndex + 1]) {
|
|
11566
|
+
console.error("Background agent mode requires --input-file <path>.");
|
|
11567
|
+
process.exit(1);
|
|
11568
|
+
}
|
|
11569
|
+
const filePath = args[inputFileIndex + 1];
|
|
11570
|
+
const rawPayload = fs21.readFileSync(filePath, "utf-8");
|
|
11571
|
+
const envelope = JSON.parse(rawPayload);
|
|
11572
|
+
const sessionId = envelope.session_id || envelope.message_id || uuidv47();
|
|
11573
|
+
registerSession({
|
|
11574
|
+
sessionId,
|
|
11575
|
+
kind: "agent",
|
|
11576
|
+
status: "running",
|
|
11577
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11578
|
+
workdir: process.cwd(),
|
|
11579
|
+
title: `background:${envelope.action || "unknown"}`,
|
|
11580
|
+
metadata: {
|
|
11581
|
+
action: envelope.action || null,
|
|
11582
|
+
message_id: envelope.message_id || null,
|
|
11583
|
+
background: true
|
|
11584
|
+
}
|
|
11585
|
+
});
|
|
11586
|
+
const childArgs = [process.argv[1], "agent", "--input-file", filePath, "--background-worker", "--registry-session", sessionId];
|
|
11587
|
+
const child = spawn4(process.execPath, childArgs, {
|
|
11588
|
+
detached: true,
|
|
11589
|
+
stdio: "ignore",
|
|
11590
|
+
cwd: process.cwd(),
|
|
11591
|
+
env: process.env
|
|
11592
|
+
});
|
|
11593
|
+
child.unref();
|
|
11594
|
+
updateSession(sessionId, { pid: child.pid });
|
|
11595
|
+
console.log(sessionId);
|
|
10348
11596
|
}
|
|
10349
11597
|
var argv = process.argv.slice(2);
|
|
10350
|
-
if (argv[0] === "agent") {
|
|
11598
|
+
if (argv[0] === "agent" && argv.includes("--background")) {
|
|
11599
|
+
startBackgroundAgent();
|
|
11600
|
+
} else if (argv[0] === "agent") {
|
|
10351
11601
|
runAgentMode();
|
|
11602
|
+
} else if (argv[0] === "sessions") {
|
|
11603
|
+
printSessions();
|
|
11604
|
+
} else if (argv[0] === "logs" && argv[1]) {
|
|
11605
|
+
printLogs(argv[1]);
|
|
11606
|
+
} else if (argv[0] === "status" && argv[1]) {
|
|
11607
|
+
printSessionStatus(argv[1]);
|
|
11608
|
+
} else if (argv[0] === "attach" && argv[1]) {
|
|
11609
|
+
attachToSession(argv[1]);
|
|
11610
|
+
} else if (argv[0] === "follow" && argv[1]) {
|
|
11611
|
+
attachToSession(argv[1]);
|
|
11612
|
+
} else if (argv[0] === "kill" && argv[1]) {
|
|
11613
|
+
killSession(argv[1]);
|
|
11614
|
+
} else if (argv[0] === "resume" && argv[1]) {
|
|
11615
|
+
runCliMode(argv[1]);
|
|
10352
11616
|
} else {
|
|
10353
11617
|
runCliMode();
|
|
10354
11618
|
}
|