@nomad-e/bluma-cli 0.0.11 → 0.0.13

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.
@@ -10,19 +10,6 @@
10
10
  "@sousaalex1605/bluma-nootebook"
11
11
  ]
12
12
  },
13
- "githubApi": {
14
- "type": "stdio",
15
- "command": "cmd",
16
- "args": [
17
- "/c",
18
- "npx",
19
- "-y",
20
- "@modelcontextprotocol/server-github"
21
- ],
22
- "env": {
23
- "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_PERSONAL_ACCESS_TOKEN}"
24
- }
25
- },
26
13
  "notionApi": {
27
14
  "type": "stdio",
28
15
  "command": "cmd",
package/dist/main.js CHANGED
@@ -7,8 +7,7 @@ import { v4 as uuidv42 } from "uuid";
7
7
 
8
8
  // src/app/ui/App.tsx
9
9
  import { useState as useState4, useEffect as useEffect3, useRef, useCallback, memo as memo4 } from "react";
10
- import { Box as Box11, Text as Text10, Static } from "ink";
11
- import Spinner from "ink-spinner";
10
+ import { Box as Box13, Text as Text12, Static } from "ink";
12
11
 
13
12
  // src/app/ui/layout.tsx
14
13
  import { Box, Text } from "ink";
@@ -21,14 +20,34 @@ var BRAND_COLORS = {
21
20
  greydark: "#444"
22
21
  };
23
22
  var Header = () => {
24
- return /* @__PURE__ */ jsx(Box, { flexDirection: "column", alignItems: "center", justifyContent: "center", height: 8, children: /* @__PURE__ */ jsx(
25
- BigText,
26
- {
27
- text: "BluMa CLI",
28
- font: "block",
29
- colors: [BRAND_COLORS.main, BRAND_COLORS.accent, BRAND_COLORS.shadow]
30
- }
31
- ) });
23
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
24
+ /* @__PURE__ */ jsx(
25
+ Box,
26
+ {
27
+ flexDirection: "column",
28
+ height: 8,
29
+ marginBottom: 1,
30
+ children: /* @__PURE__ */ jsx(
31
+ BigText,
32
+ {
33
+ text: "BluMa CLI",
34
+ font: "block",
35
+ colors: [BRAND_COLORS.main, BRAND_COLORS.accent, BRAND_COLORS.shadow]
36
+ }
37
+ )
38
+ }
39
+ ),
40
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
41
+ /* @__PURE__ */ jsx(Text, { children: "How to get started with BluMa:" }),
42
+ /* @__PURE__ */ jsx(Text, { children: "1. You can ask questions, modify files, or execute commands directly." }),
43
+ /* @__PURE__ */ jsx(Text, { children: "2. Be as clear and specific as possible to get accurate responses." }),
44
+ /* @__PURE__ */ jsxs(Text, { children: [
45
+ "3. Type ",
46
+ /* @__PURE__ */ jsx(Text, { color: "cyan", children: "/help" }),
47
+ " to explore available commands and features."
48
+ ] })
49
+ ] })
50
+ ] });
32
51
  };
33
52
  var SessionInfo = ({
34
53
  sessionId: sessionId2,
@@ -44,7 +63,6 @@ var SessionInfo = ({
44
63
  {
45
64
  borderStyle: "round",
46
65
  borderColor: "gray",
47
- paddingX: 1,
48
66
  flexDirection: "column",
49
67
  marginBottom: 1,
50
68
  children: [
@@ -64,26 +82,18 @@ var SessionInfo = ({
64
82
  ] }),
65
83
  /* @__PURE__ */ jsxs(Text, { children: [
66
84
  /* @__PURE__ */ jsx(Text, { color: "magenta", children: "\u21B3" }),
67
- /* @__PURE__ */ jsx(Text, { color: "gray", children: "agent: BluMa" })
68
- ] }),
69
- /* @__PURE__ */ jsxs(Text, { children: [
70
- /* @__PURE__ */ jsx(Text, { color: "magenta", children: "\u21B3" }),
71
- /* @__PURE__ */ jsx(Text, { color: "gray", children: "MCP: " }),
85
+ " ",
86
+ /* @__PURE__ */ jsx(Text, { color: "gray", children: "mcp: " }),
72
87
  /* @__PURE__ */ jsx(Text, { color: mcpStatus === "connected" ? "green" : "yellow", children: mcpStatus })
73
- ] }),
74
- /* @__PURE__ */ jsxs(Text, { children: [
75
- /* @__PURE__ */ jsx(Text, { color: "magenta", children: "\u21B3" }),
76
- /* @__PURE__ */ jsx(Text, { color: "gray", children: "Tools: " }),
77
- /* @__PURE__ */ jsx(Text, { color: "cyan", children: toolsCount !== null ? toolsCount : "loading..." })
78
88
  ] })
79
89
  ]
80
90
  }
81
91
  );
82
92
 
83
- // src/app/ui/input/InputPrompt.tsx
84
- import { Box as Box2, Text as Text2, useStdout } from "ink";
93
+ // src/app/ui/components/InputPrompt.tsx
94
+ import { Box as Box2, Text as Text2, useStdout, useInput as useInput2 } from "ink";
85
95
 
86
- // src/app/ui/input/utils/useSimpleInputBuffer.ts
96
+ // src/app/ui/utils/useSimpleInputBuffer.ts
87
97
  import { useReducer } from "react";
88
98
  import { useInput } from "ink";
89
99
  function inputReducer(state, action, viewWidth) {
@@ -175,9 +185,24 @@ var useCustomInput = ({ onSubmit, viewWidth, isReadOnly, onInterrupt }) => {
175
185
  };
176
186
  };
177
187
 
178
- // src/app/ui/input/InputPrompt.tsx
179
- import { useEffect, useState } from "react";
188
+ // src/app/ui/components/InputPrompt.tsx
189
+ import { useEffect, useMemo, useState } from "react";
180
190
  import { EventEmitter } from "events";
191
+
192
+ // src/app/ui/utils/slashRegistry.ts
193
+ var getSlashCommands = () => [
194
+ { name: "/help", description: "list commands" },
195
+ { name: "/mcp", description: "list tools connected via MCP" },
196
+ { name: "/tools", description: "list native tools" },
197
+ { name: "/clear", description: "clear history" }
198
+ ];
199
+ var filterSlashCommands = (query) => {
200
+ const list = getSlashCommands();
201
+ const q = query.toLowerCase();
202
+ return list.filter((c) => c.name.toLowerCase().startsWith(q));
203
+ };
204
+
205
+ // src/app/ui/components/InputPrompt.tsx
181
206
  import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
182
207
  var uiEventBus = global.__bluma_ui_eventbus__ || new EventEmitter();
183
208
  global.__bluma_ui_eventbus__ = uiEventBus;
@@ -209,6 +234,8 @@ var InputPrompt = ({ onSubmit, isReadOnly, onInterrupt }) => {
209
234
  isReadOnly,
210
235
  onInterrupt
211
236
  });
237
+ const [slashOpen, setSlashOpen] = useState(false);
238
+ const [slashIndex, setSlashIndex] = useState(0);
212
239
  const visibleText = text.slice(viewStart, viewStart + viewWidth);
213
240
  const visibleCursorPosition = cursorPosition - viewStart;
214
241
  const textBeforeCursor = visibleText.slice(0, visibleCursorPosition);
@@ -221,8 +248,42 @@ var InputPrompt = ({ onSubmit, isReadOnly, onInterrupt }) => {
221
248
  const borderColor = isReadOnly ? "gray" : "gray";
222
249
  const placeholder = isReadOnly ? " press esc to cancel | type a message while agent processes" : "";
223
250
  const showPlaceholder = text.length === 0 && isReadOnly;
251
+ const slashQuery = useMemo(() => text.startsWith("/") ? text : "", [text]);
252
+ const slashSuggestions = useMemo(() => {
253
+ if (!slashQuery) return [];
254
+ return filterSlashCommands(slashQuery);
255
+ }, [slashQuery]);
256
+ useEffect(() => {
257
+ if (isReadOnly) {
258
+ setSlashOpen(false);
259
+ return;
260
+ }
261
+ if (text.startsWith("/")) {
262
+ setSlashOpen(true);
263
+ setSlashIndex(0);
264
+ } else {
265
+ setSlashOpen(false);
266
+ }
267
+ }, [text, isReadOnly]);
268
+ useInput2((input, key) => {
269
+ if (!slashOpen) return;
270
+ if (key.downArrow) {
271
+ setSlashIndex((i) => Math.min(i + 1, Math.max(0, slashSuggestions.length - 1)));
272
+ } else if (key.upArrow) {
273
+ setSlashIndex((i) => Math.max(i - 1, 0));
274
+ } else if (key.return) {
275
+ const choice = slashSuggestions[slashIndex];
276
+ if (choice) {
277
+ const cmd = choice.name;
278
+ setSlashOpen(false);
279
+ permissiveOnSubmit(cmd);
280
+ }
281
+ } else if (key.escape) {
282
+ setSlashOpen(false);
283
+ }
284
+ }, { isActive: slashOpen });
224
285
  return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
225
- /* @__PURE__ */ jsx2(Box2, { borderStyle: "single", borderColor, borderDimColor: !isReadOnly, children: /* @__PURE__ */ jsxs2(Box2, { flexDirection: "row", paddingX: 1, flexWrap: "nowrap", children: [
286
+ /* @__PURE__ */ jsx2(Box2, { borderStyle: "round", borderColor, borderDimColor: !isReadOnly, width: viewWidth - 7, paddingY: 0, children: /* @__PURE__ */ jsxs2(Box2, { flexDirection: "row", paddingX: 1, flexWrap: "nowrap", children: [
226
287
  /* @__PURE__ */ jsxs2(Text2, { color: "white", dimColor: true, children: [
227
288
  ">",
228
289
  " "
@@ -231,8 +292,22 @@ var InputPrompt = ({ onSubmit, isReadOnly, onInterrupt }) => {
231
292
  /* @__PURE__ */ jsx2(Text2, { inverse: true, children: cursorGlyph }),
232
293
  showPlaceholder ? /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: placeholder }) : /* @__PURE__ */ jsx2(Text2, { children: textAfterCursor })
233
294
  ] }) }),
295
+ slashOpen && slashSuggestions.length > 0 && /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", marginTop: 1, children: slashSuggestions.map((s, idx) => {
296
+ const isSelected = idx === slashIndex;
297
+ return /* @__PURE__ */ jsxs2(Box2, { paddingLeft: 1, paddingY: 0, children: [
298
+ /* @__PURE__ */ jsx2(Text2, { color: isSelected ? "blue" : "gray", children: isSelected ? "\u276F " : " " }),
299
+ /* @__PURE__ */ jsxs2(Text2, { color: isSelected ? "blue" : "white", bold: isSelected, dimColor: !isSelected, children: [
300
+ s.name,
301
+ " ",
302
+ /* @__PURE__ */ jsxs2(Text2, { color: "gray", children: [
303
+ "- ",
304
+ s.description
305
+ ] })
306
+ ] })
307
+ ] }, s.name);
308
+ }) }),
234
309
  /* @__PURE__ */ jsx2(Box2, { paddingX: 1, justifyContent: "center", children: /* @__PURE__ */ jsxs2(Text2, { color: "gray", dimColor: true, children: [
235
- "ctrl+c to exit | esc to interrupt | ",
310
+ "ctrl+c to exit | /help to explore commands | esc to interrupt | ",
236
311
  isReadOnly ? "Read-only mode (message passthrough)" : "Editable mode"
237
312
  ] }) })
238
313
  ] });
@@ -243,7 +318,7 @@ import { Box as Box6, Text as Text6 } from "ink";
243
318
 
244
319
  // src/app/ui/InteractiveMenu.tsx
245
320
  import { useState as useState2, memo } from "react";
246
- import { Box as Box3, Text as Text3, useInput as useInput2 } from "ink";
321
+ import { Box as Box3, Text as Text3, useInput as useInput3 } from "ink";
247
322
  import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
248
323
  var InteractiveMenuComponent = ({ onDecision }) => {
249
324
  const options = [
@@ -252,7 +327,7 @@ var InteractiveMenuComponent = ({ onDecision }) => {
252
327
  { label: "3. Always allow this type of command", value: "accept_always" }
253
328
  ];
254
329
  const [selectedOption, setSelectedOption] = useState2(0);
255
- useInput2((input, key) => {
330
+ useInput3((input, key) => {
256
331
  if (key.upArrow) {
257
332
  setSelectedOption((prev) => prev > 0 ? prev - 1 : options.length - 1);
258
333
  }
@@ -1581,7 +1656,7 @@ var MCPClient = class {
1581
1656
  try {
1582
1657
  this.eventBus.emit("backend_message", {
1583
1658
  type: "connection_status",
1584
- message: `Connecting to MCP server: ${serverName}...`
1659
+ message: `${serverName} server is being connected...`
1585
1660
  });
1586
1661
  if (serverConf.type === "stdio") {
1587
1662
  await this.connectToStdioServer(serverName, serverConf);
@@ -1673,6 +1748,19 @@ var MCPClient = class {
1673
1748
  getAvailableTools() {
1674
1749
  return this.globalToolsForLlm;
1675
1750
  }
1751
+ // New: detailed list for UI with origin metadata
1752
+ getAvailableToolsDetailed() {
1753
+ const detailed = [];
1754
+ for (const tool of this.globalToolsForLlm) {
1755
+ const name = tool.function?.name;
1756
+ if (!name) continue;
1757
+ const route = this.toolToServerMap.get(name);
1758
+ if (!route) continue;
1759
+ const source = route.server === "native" ? "native" : "mcp";
1760
+ detailed.push({ ...tool, source, server: route.server, originalName: route.originalName });
1761
+ }
1762
+ return detailed;
1763
+ }
1676
1764
  async close() {
1677
1765
  for (const [name, session] of this.sessions.entries()) {
1678
1766
  try {
@@ -1891,6 +1979,10 @@ var Agent = class {
1891
1979
  getAvailableTools() {
1892
1980
  return this.mcpClient.getAvailableTools();
1893
1981
  }
1982
+ // UI helper: detailed tools with origin metadata
1983
+ getUiToolsDetailed() {
1984
+ return this.mcpClient.getAvailableToolsDetailed();
1985
+ }
1894
1986
  async processTurn(userInput) {
1895
1987
  this.isInterrupted = false;
1896
1988
  this.history.push({ role: "user", content: userInput.content });
@@ -2077,7 +2169,7 @@ var WorkingTimer = () => {
2077
2169
  return () => clearInterval(dotsTimer);
2078
2170
  }, []);
2079
2171
  const dots = ".".repeat(dotIndex).padEnd(3, " ");
2080
- return /* @__PURE__ */ jsx7(Box7, { marginBottom: 1, marginTop: 1, paddingX: 1, children: /* @__PURE__ */ jsxs7(Text7, { color: "magenta", children: [
2172
+ return /* @__PURE__ */ jsx7(Box7, { marginBottom: 0.5, paddingX: 1, children: /* @__PURE__ */ jsxs7(Text7, { color: "magenta", children: [
2081
2173
  `working${dots}`,
2082
2174
  ` ${seconds}s`
2083
2175
  ] }) });
@@ -2306,8 +2398,191 @@ var ToolResultDisplayComponent = ({ toolName, result }) => {
2306
2398
  };
2307
2399
  var ToolResultDisplay = memo3(ToolResultDisplayComponent);
2308
2400
 
2309
- // src/app/ui/App.tsx
2401
+ // src/app/ui/SessionInfoConnectingMCP.tsx
2402
+ import { Box as Box11, Text as Text10 } from "ink";
2403
+ import Spinner from "ink-spinner";
2310
2404
  import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
2405
+ var SessionInfoConnectingMCP = ({ sessionId: sessionId2, workdir, statusMessage }) => {
2406
+ return /* @__PURE__ */ jsxs9(
2407
+ Box11,
2408
+ {
2409
+ borderStyle: "round",
2410
+ borderColor: "gray",
2411
+ flexDirection: "column",
2412
+ marginBottom: 1,
2413
+ children: [
2414
+ /* @__PURE__ */ jsxs9(Text10, { children: [
2415
+ /* @__PURE__ */ jsx11(Text10, { bold: true, color: "white", children: "localhost" }),
2416
+ " ",
2417
+ /* @__PURE__ */ jsx11(Text10, { color: "gray", children: " session:" }),
2418
+ " ",
2419
+ /* @__PURE__ */ jsx11(Text10, { color: "magenta", children: sessionId2 })
2420
+ ] }),
2421
+ /* @__PURE__ */ jsxs9(Text10, { children: [
2422
+ /* @__PURE__ */ jsx11(Text10, { color: "magenta", children: "\u21B3" }),
2423
+ " ",
2424
+ /* @__PURE__ */ jsxs9(Text10, { color: "gray", children: [
2425
+ "workdir: ",
2426
+ workdir
2427
+ ] })
2428
+ ] }),
2429
+ /* @__PURE__ */ jsxs9(Text10, { children: [
2430
+ /* @__PURE__ */ jsx11(Text10, { color: "magenta", children: "\u21B3" }),
2431
+ " ",
2432
+ /* @__PURE__ */ jsx11(Text10, { color: "gray", children: "MCP: " }),
2433
+ /* @__PURE__ */ jsxs9(Text10, { color: "yellow", children: [
2434
+ /* @__PURE__ */ jsx11(Spinner, { type: "dots" }),
2435
+ " connecting"
2436
+ ] })
2437
+ ] }),
2438
+ /* @__PURE__ */ jsxs9(Text10, { children: [
2439
+ /* @__PURE__ */ jsx11(Text10, { color: "magenta", children: "\u21B3" }),
2440
+ " ",
2441
+ /* @__PURE__ */ jsx11(Text10, { color: "gray", children: "status: " }),
2442
+ /* @__PURE__ */ jsx11(Text10, { color: "white", children: statusMessage || "Please wait while we establish connections." })
2443
+ ] })
2444
+ ]
2445
+ }
2446
+ );
2447
+ };
2448
+ var SessionInfoConnectingMCP_default = SessionInfoConnectingMCP;
2449
+
2450
+ // src/app/ui/components/SlashCommands.tsx
2451
+ import { Box as Box12, Text as Text11 } from "ink";
2452
+ import { Fragment, jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
2453
+ var SlashCommands = ({ input, setHistory, agentRef }) => {
2454
+ const [cmd, ...args] = input.slice(1).trim().split(/\s+/);
2455
+ const outBox = (children) => /* @__PURE__ */ jsx12(Box12, { borderStyle: "round", borderColor: "gray", paddingX: 1, marginBottom: 1, flexDirection: "column", children });
2456
+ const render2 = () => {
2457
+ if (!cmd) {
2458
+ return null;
2459
+ }
2460
+ if (cmd === "help") {
2461
+ const cmds = getSlashCommands();
2462
+ return outBox(
2463
+ /* @__PURE__ */ jsxs10(Fragment, { children: [
2464
+ /* @__PURE__ */ jsx12(Text11, { color: "cyan", bold: true, children: "Available commands" }),
2465
+ cmds.map((c, i) => /* @__PURE__ */ jsxs10(Text11, { color: "gray", children: [
2466
+ c.name,
2467
+ " - ",
2468
+ c.description
2469
+ ] }, i))
2470
+ ] })
2471
+ );
2472
+ }
2473
+ if (cmd === "clear") {
2474
+ setHistory((prev) => prev.filter((item) => item.id === 0 || item.id === 1));
2475
+ return outBox(/* @__PURE__ */ jsx12(Text11, { color: "green", children: "History cleared." }));
2476
+ }
2477
+ if (cmd === "mcp") {
2478
+ const all = agentRef.current?.getUiToolsDetailed?.() || agentRef.current?.getAvailableTools?.() || [];
2479
+ const isMcp = (t) => t.source?.toLowerCase?.() === "mcp" || !!t.server && t.server !== "native";
2480
+ const tools = all.filter(isMcp);
2481
+ const term = (args?.[0] || "").toLowerCase();
2482
+ const filtered = term ? tools.filter((t) => (t.function?.name || t.name || "tool").toLowerCase().includes(term)) : tools;
2483
+ const pad = (s, n) => s.length >= n ? s.slice(0, n - 1) + "\u2026" : s.padEnd(n, " ");
2484
+ const colName = 34;
2485
+ const colType = 10;
2486
+ const colSource = 18;
2487
+ return outBox(
2488
+ /* @__PURE__ */ jsxs10(Fragment, { children: [
2489
+ /* @__PURE__ */ jsx12(Text11, { color: "cyan", bold: true, children: "MCP Tools" }),
2490
+ /* @__PURE__ */ jsxs10(Text11, { color: "gray", children: [
2491
+ "Total MCP: ",
2492
+ tools.length,
2493
+ term ? ` | Filter: "${term}" | Showing: ${filtered.length}` : ""
2494
+ ] }),
2495
+ filtered.length === 0 ? /* @__PURE__ */ jsx12(Text11, { color: "yellow", children: "No MCP tools to display." }) : /* @__PURE__ */ jsxs10(Box12, { flexDirection: "column", children: [
2496
+ /* @__PURE__ */ jsxs10(Text11, { color: "gray", children: [
2497
+ pad("Name", colName),
2498
+ " | ",
2499
+ pad("Type", colType),
2500
+ " | ",
2501
+ pad("Source", colSource)
2502
+ ] }),
2503
+ /* @__PURE__ */ jsxs10(Text11, { color: "gray", children: [
2504
+ "".padEnd(colName, "-"),
2505
+ "---",
2506
+ "".padEnd(colType, "-"),
2507
+ "---",
2508
+ "".padEnd(colSource, "-")
2509
+ ] }),
2510
+ filtered.map((t, i) => {
2511
+ const name = t.function?.name || t.name || "tool";
2512
+ const type = t.function?.name ? "fn" : t.type || "tool";
2513
+ const source = t.source || t.provider || "mcp";
2514
+ return /* @__PURE__ */ jsxs10(Text11, { color: "white", children: [
2515
+ pad(name, colName),
2516
+ " | ",
2517
+ pad(String(type), colType),
2518
+ " | ",
2519
+ pad(String(source), colSource)
2520
+ ] }, i);
2521
+ })
2522
+ ] })
2523
+ ] })
2524
+ );
2525
+ }
2526
+ if (cmd === "tools") {
2527
+ const all = agentRef.current?.getUiToolsDetailed?.() || agentRef.current?.getAvailableTools?.() || [];
2528
+ const isMcp = (t) => t.source?.toLowerCase?.() === "mcp" || !!t.server && t.server !== "native";
2529
+ const tools = all.filter((t) => !isMcp(t));
2530
+ const term = (args?.[0] || "").toLowerCase();
2531
+ const filtered = term ? tools.filter((t) => (t.function?.name || t.name || "tool").toLowerCase().includes(term)) : tools;
2532
+ const pad = (s, n) => s.length >= n ? s.slice(0, n - 1) + "\u2026" : s.padEnd(n, " ");
2533
+ const colName = 34;
2534
+ const colType = 10;
2535
+ const colSource = 18;
2536
+ return outBox(
2537
+ /* @__PURE__ */ jsxs10(Fragment, { children: [
2538
+ /* @__PURE__ */ jsx12(Text11, { color: "cyan", bold: true, children: "Native Tools" }),
2539
+ /* @__PURE__ */ jsxs10(Text11, { color: "gray", children: [
2540
+ "Total Native: ",
2541
+ tools.length,
2542
+ term ? ` | Filter: "${term}" | Showing: ${filtered.length}` : ""
2543
+ ] }),
2544
+ filtered.length === 0 ? /* @__PURE__ */ jsx12(Text11, { color: "yellow", children: "No native tools to display." }) : /* @__PURE__ */ jsxs10(Box12, { flexDirection: "column", children: [
2545
+ /* @__PURE__ */ jsxs10(Text11, { color: "gray", children: [
2546
+ pad("Name", colName),
2547
+ " | ",
2548
+ pad("Type", colType),
2549
+ " | ",
2550
+ pad("Source", colSource)
2551
+ ] }),
2552
+ /* @__PURE__ */ jsxs10(Text11, { color: "gray", children: [
2553
+ "".padEnd(colName, "-"),
2554
+ "---",
2555
+ "".padEnd(colType, "-"),
2556
+ "---",
2557
+ "".padEnd(colSource, "-")
2558
+ ] }),
2559
+ filtered.map((t, i) => {
2560
+ const name = t.function?.name || t.name || "tool";
2561
+ const type = t.function?.name ? "fn" : t.type || "tool";
2562
+ const source = t.source || "native";
2563
+ return /* @__PURE__ */ jsxs10(Text11, { color: "white", children: [
2564
+ pad(name, colName),
2565
+ " | ",
2566
+ pad(String(type), colType),
2567
+ " | ",
2568
+ pad(String(source), colSource)
2569
+ ] }, i);
2570
+ })
2571
+ ] })
2572
+ ] })
2573
+ );
2574
+ }
2575
+ return outBox(/* @__PURE__ */ jsxs10(Text11, { color: "red", children: [
2576
+ "Command not recognized: /",
2577
+ cmd
2578
+ ] }));
2579
+ };
2580
+ return /* @__PURE__ */ jsx12(Fragment, { children: render2() });
2581
+ };
2582
+ var SlashCommands_default = SlashCommands;
2583
+
2584
+ // src/app/ui/App.tsx
2585
+ import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
2311
2586
  var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
2312
2587
  const agentInstance = useRef(null);
2313
2588
  const [history, setHistory] = useState4([]);
@@ -2322,7 +2597,9 @@ var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
2322
2597
  const [pendingConfirmation, setPendingConfirmation] = useState4(
2323
2598
  null
2324
2599
  );
2325
- const [confirmationPreview, setConfirmationPreview] = useState4(null);
2600
+ const [confirmationPreview, setConfirmationPreview] = useState4(
2601
+ null
2602
+ );
2326
2603
  const alwaysAcceptList = useRef([]);
2327
2604
  const workdir = process.cwd();
2328
2605
  const handleInterrupt = useCallback(() => {
@@ -2333,13 +2610,33 @@ var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
2333
2610
  ...prev,
2334
2611
  {
2335
2612
  id: prev.length,
2336
- component: /* @__PURE__ */ jsx11(Text10, { color: "yellow", children: "-- Task cancelled by dev. --" })
2613
+ component: /* @__PURE__ */ jsx13(Text12, { color: "yellow", children: "-- Task cancelled by dev. --" })
2337
2614
  }
2338
2615
  ]);
2339
2616
  }, [isProcessing, eventBus2]);
2340
2617
  const handleSubmit = useCallback(
2341
2618
  (text) => {
2342
2619
  if (!text || isProcessing || !agentInstance.current) return;
2620
+ if (text.startsWith("/")) {
2621
+ const [cmd] = text.slice(1).trim().split(/\s+/);
2622
+ if (!cmd) {
2623
+ setIsProcessing(false);
2624
+ return;
2625
+ }
2626
+ setHistory((prev) => [
2627
+ ...prev,
2628
+ {
2629
+ id: prev.length,
2630
+ component: /* @__PURE__ */ jsx13(Box13, { marginBottom: 1, children: /* @__PURE__ */ jsx13(Text12, { color: "white", dimColor: true, children: text }) })
2631
+ },
2632
+ {
2633
+ id: prev.length + 1,
2634
+ component: /* @__PURE__ */ jsx13(SlashCommands_default, { input: text, setHistory, agentRef: agentInstance })
2635
+ }
2636
+ ]);
2637
+ setIsProcessing(false);
2638
+ return;
2639
+ }
2343
2640
  setIsProcessing(true);
2344
2641
  const displayText = text.length > 1e4 ? text.substring(0, 1e4) + "..." : text;
2345
2642
  setHistory((prev) => [
@@ -2348,8 +2645,8 @@ var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
2348
2645
  id: prev.length,
2349
2646
  component: (
2350
2647
  // Uma única Box para o espaçamento
2351
- /* @__PURE__ */ jsx11(Box11, { marginBottom: 1, children: /* @__PURE__ */ jsxs9(Text10, { color: "white", dimColor: true, children: [
2352
- /* @__PURE__ */ jsxs9(Text10, { color: "white", children: [
2648
+ /* @__PURE__ */ jsx13(Box13, { marginBottom: 1, children: /* @__PURE__ */ jsxs11(Text12, { color: "white", dimColor: true, children: [
2649
+ /* @__PURE__ */ jsxs11(Text12, { color: "white", children: [
2353
2650
  ">",
2354
2651
  " "
2355
2652
  ] }),
@@ -2384,7 +2681,7 @@ var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
2384
2681
  []
2385
2682
  );
2386
2683
  useEffect3(() => {
2387
- setHistory([{ id: 0, component: /* @__PURE__ */ jsx11(Header, {}) }]);
2684
+ setHistory([{ id: 0, component: /* @__PURE__ */ jsx13(Header, {}) }]);
2388
2685
  const initializeAgent = async () => {
2389
2686
  try {
2390
2687
  agentInstance.current = new Agent(sessionId2, eventBus2);
@@ -2436,7 +2733,7 @@ var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
2436
2733
  if (prev.length < 2) {
2437
2734
  newHistory.push({
2438
2735
  id: 1,
2439
- component: /* @__PURE__ */ jsx11(
2736
+ component: /* @__PURE__ */ jsx13(
2440
2737
  SessionInfo,
2441
2738
  {
2442
2739
  sessionId: sessionId2,
@@ -2457,10 +2754,10 @@ var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
2457
2754
  }
2458
2755
  let newComponent = null;
2459
2756
  if (parsed.type === "debug") {
2460
- newComponent = /* @__PURE__ */ jsx11(Text10, { color: "gray", children: parsed.message });
2757
+ newComponent = /* @__PURE__ */ jsx13(Text12, { color: "gray", children: parsed.message });
2461
2758
  } else if (parsed.type === "protocol_violation") {
2462
- newComponent = /* @__PURE__ */ jsxs9(
2463
- Box11,
2759
+ newComponent = /* @__PURE__ */ jsxs11(
2760
+ Box13,
2464
2761
  {
2465
2762
  borderStyle: "round",
2466
2763
  borderColor: "yellow",
@@ -2468,19 +2765,19 @@ var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
2468
2765
  marginBottom: 1,
2469
2766
  paddingX: 1,
2470
2767
  children: [
2471
- /* @__PURE__ */ jsx11(Text10, { color: "yellow", bold: true, children: "Protocol Violation" }),
2472
- /* @__PURE__ */ jsx11(Text10, { color: "gray", children: parsed.content }),
2473
- /* @__PURE__ */ jsx11(Text10, { color: "yellow", children: parsed.message })
2768
+ /* @__PURE__ */ jsx13(Text12, { color: "yellow", bold: true, children: "Protocol Violation" }),
2769
+ /* @__PURE__ */ jsx13(Text12, { color: "gray", children: parsed.content }),
2770
+ /* @__PURE__ */ jsx13(Text12, { color: "yellow", children: parsed.message })
2474
2771
  ]
2475
2772
  }
2476
2773
  );
2477
2774
  } else if (parsed.type === "error") {
2478
- newComponent = /* @__PURE__ */ jsxs9(Text10, { color: "red", children: [
2775
+ newComponent = /* @__PURE__ */ jsxs11(Text12, { color: "red", children: [
2479
2776
  "\u274C ",
2480
2777
  parsed.message
2481
2778
  ] });
2482
2779
  } else if (parsed.type === "tool_call") {
2483
- newComponent = /* @__PURE__ */ jsx11(
2780
+ newComponent = /* @__PURE__ */ jsx13(
2484
2781
  ToolCallDisplay,
2485
2782
  {
2486
2783
  toolName: parsed.tool_name,
@@ -2489,7 +2786,7 @@ var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
2489
2786
  }
2490
2787
  );
2491
2788
  } else if (parsed.type === "tool_result") {
2492
- newComponent = /* @__PURE__ */ jsx11(
2789
+ newComponent = /* @__PURE__ */ jsx13(
2493
2790
  ToolResultDisplay,
2494
2791
  {
2495
2792
  toolName: parsed.tool_name,
@@ -2497,9 +2794,15 @@ var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
2497
2794
  }
2498
2795
  );
2499
2796
  } else if (parsed.type === "dev_overlay") {
2500
- newComponent = /* @__PURE__ */ jsx11(Box11, { borderStyle: "classic", borderColor: "blue", paddingX: 1, marginBottom: 1, children: /* @__PURE__ */ jsx11(Text10, { color: "white", children: parsed.payload }) });
2797
+ newComponent = /* @__PURE__ */ jsx13(Box13, { marginBottom: 1, children: /* @__PURE__ */ jsxs11(Text12, { color: "gray", children: [
2798
+ /* @__PURE__ */ jsxs11(Text12, { color: "blue", children: [
2799
+ ">",
2800
+ " "
2801
+ ] }),
2802
+ parsed.payload
2803
+ ] }) });
2501
2804
  } else if (parsed.type === "log") {
2502
- newComponent = /* @__PURE__ */ jsxs9(Text10, { color: "gray", children: [
2805
+ newComponent = /* @__PURE__ */ jsxs11(Text12, { color: "gray", children: [
2503
2806
  "\u2139\uFE0F ",
2504
2807
  parsed.message,
2505
2808
  parsed.payload ? `: ${parsed.payload}` : ""
@@ -2529,14 +2832,24 @@ var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
2529
2832
  }, [eventBus2, sessionId2, handleConfirmation]);
2530
2833
  const renderInteractiveComponent = () => {
2531
2834
  if (mcpStatus !== "connected") {
2532
- return /* @__PURE__ */ jsx11(Box11, { borderStyle: "round", borderColor: "black", children: /* @__PURE__ */ jsxs9(Text10, { color: "yellow", children: [
2533
- /* @__PURE__ */ jsx11(Spinner, { type: "dots" }),
2534
- " ",
2535
- statusMessage || "Connecting..."
2536
- ] }) });
2835
+ return /* @__PURE__ */ jsx13(
2836
+ Box13,
2837
+ {
2838
+ borderStyle: "round",
2839
+ borderColor: "black",
2840
+ children: /* @__PURE__ */ jsx13(
2841
+ SessionInfoConnectingMCP_default,
2842
+ {
2843
+ sessionId: sessionId2,
2844
+ workdir,
2845
+ statusMessage
2846
+ }
2847
+ )
2848
+ }
2849
+ );
2537
2850
  }
2538
2851
  if (pendingConfirmation) {
2539
- return /* @__PURE__ */ jsx11(
2852
+ return /* @__PURE__ */ jsx13(
2540
2853
  ConfirmationPrompt,
2541
2854
  {
2542
2855
  toolCalls: pendingConfirmation,
@@ -2548,9 +2861,9 @@ var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
2548
2861
  }
2549
2862
  );
2550
2863
  }
2551
- return /* @__PURE__ */ jsxs9(Box11, { flexDirection: "column", children: [
2552
- isProcessing && !pendingConfirmation && /* @__PURE__ */ jsx11(WorkingTimer, {}),
2553
- /* @__PURE__ */ jsx11(
2864
+ return /* @__PURE__ */ jsxs11(Box13, { flexDirection: "column", children: [
2865
+ isProcessing && !pendingConfirmation && /* @__PURE__ */ jsx13(WorkingTimer, {}),
2866
+ /* @__PURE__ */ jsx13(
2554
2867
  InputPrompt,
2555
2868
  {
2556
2869
  onSubmit: handleSubmit,
@@ -2560,8 +2873,8 @@ var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
2560
2873
  )
2561
2874
  ] });
2562
2875
  };
2563
- return /* @__PURE__ */ jsxs9(Box11, { flexDirection: "column", children: [
2564
- /* @__PURE__ */ jsx11(Static, { items: history, children: (item) => /* @__PURE__ */ jsx11(Box11, { children: item.component }, item.id) }),
2876
+ return /* @__PURE__ */ jsxs11(Box13, { flexDirection: "column", children: [
2877
+ /* @__PURE__ */ jsx13(Static, { items: history, children: (item) => /* @__PURE__ */ jsx13(Box13, { children: item.component }, item.id) }),
2565
2878
  renderInteractiveComponent()
2566
2879
  ] });
2567
2880
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nomad-e/bluma-cli",
3
- "version": "0.0.11",
3
+ "version": "0.0.13",
4
4
  "description": "BluMa independent agent for automation and advanced software engineering.",
5
5
  "author": "Alex Fonseca",
6
6
  "license": "MIT",