@bike4mind/cli 0.2.7-ja-fix-confluence-table-data-5752.17142 → 0.2.8-cli-bash-tools.17140

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/index.js CHANGED
@@ -4,9 +4,9 @@ import {
4
4
  getEffectiveApiKey,
5
5
  getOpenWeatherKey,
6
6
  getSerperKey
7
- } from "./chunk-GPTQ7T7Y.js";
8
- import "./chunk-6ATNPERY.js";
9
- import "./chunk-OK3T7VKG.js";
7
+ } from "./chunk-6S7HV2GF.js";
8
+ import "./chunk-F2K7OCDJ.js";
9
+ import "./chunk-RJYG7BUV.js";
10
10
  import {
11
11
  BFLImageService,
12
12
  BaseStorage,
@@ -15,7 +15,7 @@ import {
15
15
  OpenAIBackend,
16
16
  OpenAIImageService,
17
17
  XAIImageService
18
- } from "./chunk-KPBWTYME.js";
18
+ } from "./chunk-SE2T5GED.js";
19
19
  import {
20
20
  Logger
21
21
  } from "./chunk-AMDXHL6S.js";
@@ -73,19 +73,19 @@ import {
73
73
  XAI_IMAGE_MODELS,
74
74
  b4mLLMTools,
75
75
  getMcpProviderMetadata
76
- } from "./chunk-F2LBB4TN.js";
76
+ } from "./chunk-HD4QQGS6.js";
77
77
  import {
78
78
  __require
79
79
  } from "./chunk-PDX44BCA.js";
80
80
 
81
81
  // src/index.tsx
82
- import React13, { useState as useState4, useEffect as useEffect3, useCallback, useRef } from "react";
83
- import { render, Box as Box13, Text as Text12, useApp, useInput as useInput3 } from "ink";
82
+ import React14, { useState as useState5, useEffect as useEffect3, useCallback, useRef } from "react";
83
+ import { render, Box as Box14, Text as Text13, useApp, useInput as useInput4 } from "ink";
84
84
  import { v4 as uuidv49 } from "uuid";
85
85
 
86
86
  // src/components/App.tsx
87
87
  import React9 from "react";
88
- import { Box as Box9, Text as Text8, Static } from "ink";
88
+ import { Box as Box9, Text as Text8 } from "ink";
89
89
 
90
90
  // src/components/StatusBar.tsx
91
91
  import React from "react";
@@ -389,6 +389,11 @@ var COMMANDS = [
389
389
  name: "clear",
390
390
  description: "Start a new session",
391
391
  aliases: ["new"]
392
+ },
393
+ {
394
+ name: "rewind",
395
+ description: "Rewind conversation to a previous point",
396
+ aliases: ["undo"]
392
397
  }
393
398
  ];
394
399
 
@@ -625,12 +630,26 @@ function findAtTrigger(value) {
625
630
  }
626
631
  return null;
627
632
  }
628
- function InputPrompt({ onSubmit, onImageDetected, disabled = false, history = [] }) {
633
+ function InputPrompt({
634
+ onSubmit,
635
+ onImageDetected,
636
+ disabled = false,
637
+ history = [],
638
+ prefillInput,
639
+ onPrefillConsumed
640
+ }) {
629
641
  const [value, setValue] = useState("");
630
642
  const [selectedIndex, setSelectedIndex] = useState(0);
631
643
  const [historyIndex, setHistoryIndex] = useState(-1);
632
644
  const [tempInput, setTempInput] = useState("");
633
645
  const [inputKey, setInputKey] = useState(0);
646
+ useEffect(() => {
647
+ if (prefillInput) {
648
+ setValue(prefillInput);
649
+ setInputKey((prev) => prev + 1);
650
+ onPrefillConsumed?.();
651
+ }
652
+ }, [prefillInput, onPrefillConsumed]);
634
653
  const [fileAutocomplete, setFileAutocomplete] = useState(null);
635
654
  const [fileSelectedIndex, setFileSelectedIndex] = useState(0);
636
655
  const shouldShowCommandAutocomplete = value.startsWith("/") && !disabled && !fileAutocomplete?.active;
@@ -779,7 +798,7 @@ function InputPrompt({ onSubmit, onImageDetected, disabled = false, history = []
779
798
  value,
780
799
  onChange: handleChange,
781
800
  onSubmit: handleSubmit,
782
- placeholder: disabled ? "Thinking..." : "Type your message, /help for commands, or @file to reference",
801
+ placeholder: disabled ? "" : "Type your message, /help for commands, or @file to reference",
783
802
  showCursor: !disabled
784
803
  }
785
804
  )), shouldShowCommandAutocomplete && /* @__PURE__ */ React4.createElement(CommandAutocomplete, { commands: filteredCommands, selectedIndex }), fileAutocomplete?.active && /* @__PURE__ */ React4.createElement(FileAutocomplete, { files: filteredFiles, selectedIndex: fileSelectedIndex, query: fileAutocomplete.query }));
@@ -810,6 +829,7 @@ var useCliStore = create((set) => ({
810
829
  addAgentStep: (step) => set((state) => ({
811
830
  agentSteps: [...state.agentSteps, step]
812
831
  })),
832
+ setAgentSteps: (steps) => set({ agentSteps: steps }),
813
833
  clearAgentSteps: () => set({ agentSteps: [] }),
814
834
  // Permission prompt
815
835
  permissionPrompt: null,
@@ -829,7 +849,7 @@ var AgentThinking = React6.memo(function AgentThinking2() {
829
849
  if (!isThinking) {
830
850
  return null;
831
851
  }
832
- return /* @__PURE__ */ React6.createElement(Box6, { borderStyle: "single", borderColor: "yellow", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React6.createElement(ThoughtStream, { steps: agentSteps }));
852
+ return /* @__PURE__ */ React6.createElement(Box6, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React6.createElement(ThoughtStream, { steps: agentSteps }));
833
853
  });
834
854
 
835
855
  // src/components/PermissionPrompt.tsx
@@ -1224,7 +1244,9 @@ function App({
1224
1244
  commandHistory = [],
1225
1245
  config,
1226
1246
  availableModels = [],
1227
- onSaveConfig
1247
+ onSaveConfig,
1248
+ prefillInput,
1249
+ onPrefillConsumed
1228
1250
  }) {
1229
1251
  const messages = useCliStore((state) => state.session?.messages || []);
1230
1252
  const sessionName = useCliStore((state) => state.session?.name || "New Session");
@@ -1282,18 +1304,21 @@ ${errorBlock}`;
1282
1304
  canBeTrusted: permissionPrompt.canBeTrusted,
1283
1305
  onResponse: onPermissionResponse
1284
1306
  }
1285
- )) : /* @__PURE__ */ React9.createElement(React9.Fragment, null, /* @__PURE__ */ React9.createElement(Static, { items: messages }, (message, index) => /* @__PURE__ */ React9.createElement(Box9, { key: index, flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React9.createElement(MessageItem, { message }))), /* @__PURE__ */ React9.createElement(AgentThinking, null), exitRequested && /* @__PURE__ */ React9.createElement(Box9, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React9.createElement(Text8, { color: "yellow", bold: true }, "Press Ctrl+C again to exit")), /* @__PURE__ */ React9.createElement(Box9, { borderStyle: "single", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React9.createElement(
1307
+ )) : /* @__PURE__ */ React9.createElement(React9.Fragment, null, /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column" }, messages.map((message, index) => /* @__PURE__ */ React9.createElement(Box9, { key: `${message.timestamp}-${message.role}-${index}`, flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React9.createElement(MessageItem, { message })))), /* @__PURE__ */ React9.createElement(AgentThinking, null), exitRequested && /* @__PURE__ */ React9.createElement(Box9, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React9.createElement(Text8, { color: "yellow", bold: true }, "Press Ctrl+C again to exit")), /* @__PURE__ */ React9.createElement(Box9, { borderStyle: "single", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React9.createElement(
1286
1308
  InputPrompt,
1287
1309
  {
1288
1310
  onSubmit: handleSubmit,
1289
1311
  onImageDetected,
1290
1312
  disabled: isThinking,
1291
- history: commandHistory
1313
+ history: commandHistory,
1314
+ prefillInput,
1315
+ onPrefillConsumed
1292
1316
  }
1293
1317
  ))));
1294
1318
  }
1295
1319
  function MessageItem({ message }) {
1296
- return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React9.createElement(Box9, null, /* @__PURE__ */ React9.createElement(Text8, { bold: true, color: message.role === "user" ? "cyan" : "green" }, message.role === "user" ? "\u{1F464} You" : "\u{1F916} Assistant"), /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, " \u2022 ", new Date(message.timestamp).toLocaleTimeString())), /* @__PURE__ */ React9.createElement(Box9, { paddingLeft: 2 }, message.metadata?.permissionDenied ? /* @__PURE__ */ React9.createElement(Text8, { color: "yellow" }, "\u26A0\uFE0F ", message.content) : /* @__PURE__ */ React9.createElement(Text8, null, message.content)), message.metadata?.steps && message.metadata.steps.length > 0 && /* @__PURE__ */ React9.createElement(Box9, { paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React9.createElement(Text8, { dimColor: true, bold: true }, "\u{1F527} Agent Reasoning Trace (", message.metadata.steps.filter((s) => s.type === "action").length, " ", "tools used, ", message.metadata.steps.length, " total steps)", message.metadata.tokenUsage && ` \u2022 ${message.metadata.tokenUsage.total} tokens`), /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, "Step types: ", message.metadata.steps.map((s) => s.type).join(", ")), message.metadata.steps.map((step, idx) => {
1320
+ const isUser = message.role === "user";
1321
+ return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React9.createElement(Box9, null, /* @__PURE__ */ React9.createElement(Text8, { bold: true, color: isUser ? "cyan" : "green" }, isUser ? "\u{1F464} You" : "\u{1F916} Assistant"), /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, " \u2022 ", new Date(message.timestamp).toLocaleTimeString())), isUser && message.content && /* @__PURE__ */ React9.createElement(Box9, { paddingLeft: 2 }, /* @__PURE__ */ React9.createElement(Text8, { backgroundColor: "whiteBright", color: "black" }, " ", message.content, " ")), !isUser && message.metadata?.steps && message.metadata.steps.length > 0 && /* @__PURE__ */ React9.createElement(Box9, { paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React9.createElement(Text8, { dimColor: true, bold: true }, "\u{1F527} Agent Reasoning Trace (", message.metadata.steps.filter((s) => s.type === "action").length, " ", "tools used, ", message.metadata.steps.length, " total steps)", message.metadata.tokenUsage && ` \u2022 ${message.metadata.tokenUsage.total} tokens`), /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, "Step types: ", message.metadata.steps.map((s) => s.type).join(", ")), message.metadata.steps.map((step, idx) => {
1297
1322
  if (step.type === "thought") {
1298
1323
  return /* @__PURE__ */ React9.createElement(Box9, { key: idx, paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React9.createElement(Text8, { color: "blue" }, "\u{1F4AD} Thought:"), /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, ` ${step.content.slice(0, 200)}${step.content.length > 200 ? "..." : ""}`));
1299
1324
  }
@@ -1305,7 +1330,7 @@ function MessageItem({ message }) {
1305
1330
  return /* @__PURE__ */ React9.createElement(Box9, { key: idx, paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React9.createElement(Text8, { color: "yellow" }, "\u{1F527} Action: ", toolName), toolInput && /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, ` Input: ${typeof toolInput === "string" ? toolInput : JSON.stringify(toolInput).slice(0, 100)}`), result && /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, ` Result: ${typeof result === "string" ? result.slice(0, 200) : JSON.stringify(result).slice(0, 200)}${(typeof result === "string" ? result.length : JSON.stringify(result).length) > 200 ? "..." : ""}`));
1306
1331
  }
1307
1332
  return null;
1308
- }).filter(Boolean)), message.metadata?.tokenUsage && (!message.metadata.steps || message.metadata.steps.length === 0) && /* @__PURE__ */ React9.createElement(Box9, { paddingLeft: 2 }, /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, `${message.metadata.tokenUsage.total} tokens`)));
1333
+ }).filter(Boolean)), !isUser && message.content !== "..." && /* @__PURE__ */ React9.createElement(Box9, { paddingLeft: 2, marginTop: message.metadata?.steps?.length ? 1 : 0 }, message.metadata?.permissionDenied ? /* @__PURE__ */ React9.createElement(Text8, { color: "yellow" }, "\u26A0\uFE0F ", message.content) : /* @__PURE__ */ React9.createElement(Text8, null, message.content)), message.metadata?.tokenUsage && (!message.metadata.steps || message.metadata.steps.length === 0) && /* @__PURE__ */ React9.createElement(Box9, { paddingLeft: 2 }, /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, `${message.metadata.tokenUsage.total} tokens`)));
1309
1334
  }
1310
1335
 
1311
1336
  // src/components/MessageList.tsx
@@ -1380,9 +1405,78 @@ function TrustLocationSelector({ inProject, onSelect, onCancel }) {
1380
1405
  ), /* @__PURE__ */ React11.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, "Use \u2191\u2193 arrows to navigate, Enter to select, Ctrl+C to cancel")));
1381
1406
  }
1382
1407
 
1408
+ // src/components/RewindSelector.tsx
1409
+ import React12, { useState as useState3 } from "react";
1410
+ import { Box as Box12, Text as Text11, useInput as useInput3 } from "ink";
1411
+ import SelectInput3 from "ink-select-input";
1412
+ function RewindSelector({ messages, onSelect, onCancel }) {
1413
+ const [step, setStep] = useState3("selection");
1414
+ const [selectedMessageIndex, setSelectedMessageIndex] = useState3(null);
1415
+ useInput3((input, key) => {
1416
+ if (key.escape) {
1417
+ if (step === "confirmation") {
1418
+ setStep("selection");
1419
+ setSelectedMessageIndex(null);
1420
+ } else {
1421
+ onCancel();
1422
+ }
1423
+ }
1424
+ });
1425
+ const userMessages = messages.map((msg, idx) => ({ msg, originalIndex: idx })).filter(({ msg }) => msg.role === "user");
1426
+ const items = userMessages.map(({ msg, originalIndex }, index) => {
1427
+ const preview = msg.content.length > 50 ? msg.content.substring(0, 50) + "..." : msg.content;
1428
+ const timestamp = new Date(msg.timestamp).toLocaleString();
1429
+ const position = index + 1;
1430
+ return {
1431
+ label: `[${position}] ${timestamp} - ${preview}`,
1432
+ value: originalIndex
1433
+ };
1434
+ });
1435
+ const handleSelectionSelect = (item) => {
1436
+ setSelectedMessageIndex(item.value);
1437
+ setStep("confirmation");
1438
+ };
1439
+ const handleConfirmationSelect = (item) => {
1440
+ if (item.value === "confirm" && selectedMessageIndex !== null) {
1441
+ onSelect(selectedMessageIndex);
1442
+ } else {
1443
+ setStep("selection");
1444
+ setSelectedMessageIndex(null);
1445
+ }
1446
+ };
1447
+ const messagesToRemove = selectedMessageIndex !== null && selectedMessageIndex >= 0 && selectedMessageIndex < messages.length ? messages.slice(selectedMessageIndex) : [];
1448
+ const tokensToRemove = messagesToRemove.reduce((sum2, msg) => {
1449
+ return sum2 + (msg.metadata?.tokenUsage?.total || 0);
1450
+ }, 0);
1451
+ if (step === "selection") {
1452
+ return /* @__PURE__ */ React12.createElement(Box12, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React12.createElement(Box12, { marginBottom: 1 }, /* @__PURE__ */ React12.createElement(Text11, { bold: true }, "Select a point to rewind to:")), /* @__PURE__ */ React12.createElement(
1453
+ SelectInput3,
1454
+ {
1455
+ items,
1456
+ onSelect: handleSelectionSelect,
1457
+ itemComponent: ({ isSelected, label }) => /* @__PURE__ */ React12.createElement(Box12, null, /* @__PURE__ */ React12.createElement(Text11, { color: isSelected ? "cyan" : void 0 }, isSelected ? "\u276F " : " ", label))
1458
+ }
1459
+ ), /* @__PURE__ */ React12.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, "Use \u2191\u2193 arrows to navigate, Enter to select, Esc to cancel")));
1460
+ }
1461
+ const confirmationItems = [
1462
+ { label: "Yes, rewind to this point", value: "confirm" },
1463
+ { label: "No, go back to selection", value: "cancel" }
1464
+ ];
1465
+ const selectedMessage = selectedMessageIndex !== null && selectedMessageIndex >= 0 && selectedMessageIndex < messages.length ? messages[selectedMessageIndex] : null;
1466
+ const selectedPreview = selectedMessage ? selectedMessage.content.length > 50 ? selectedMessage.content.substring(0, 50) + "..." : selectedMessage.content : "";
1467
+ return /* @__PURE__ */ React12.createElement(Box12, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React12.createElement(Box12, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React12.createElement(Text11, { bold: true }, "Confirm rewind operation:"), /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, "Message: ", selectedPreview), /* @__PURE__ */ React12.createElement(Text11, { color: "yellow" }, "This will remove ", messagesToRemove.length, " message(s) (", tokensToRemove.toLocaleString(), " tokens)"), /* @__PURE__ */ React12.createElement(Text11, { color: "cyan" }, "The selected message will be placed in your input for editing.")), /* @__PURE__ */ React12.createElement(
1468
+ SelectInput3,
1469
+ {
1470
+ items: confirmationItems,
1471
+ onSelect: handleConfirmationSelect,
1472
+ itemComponent: ({ isSelected, label }) => /* @__PURE__ */ React12.createElement(Box12, null, /* @__PURE__ */ React12.createElement(Text11, { color: isSelected ? "cyan" : void 0 }, isSelected ? "\u276F " : " ", label))
1473
+ }
1474
+ ), /* @__PURE__ */ React12.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, "Use \u2191\u2193 arrows to navigate, Enter to select, Esc to go back")));
1475
+ }
1476
+
1383
1477
  // src/components/LoginFlow.tsx
1384
- import React12, { useState as useState3, useEffect as useEffect2 } from "react";
1385
- import { Box as Box12, Text as Text11 } from "ink";
1478
+ import React13, { useState as useState4, useEffect as useEffect2 } from "react";
1479
+ import { Box as Box13, Text as Text12 } from "ink";
1386
1480
  import Spinner2 from "ink-spinner";
1387
1481
  import jwt from "jsonwebtoken";
1388
1482
  import open from "open";
@@ -1498,10 +1592,10 @@ var OAuthClient = class {
1498
1592
 
1499
1593
  // src/components/LoginFlow.tsx
1500
1594
  function LoginFlow({ apiUrl = "http://localhost:3000", configStore, onSuccess, onError }) {
1501
- const [status, setStatus] = useState3("initiating");
1502
- const [deviceFlow, setDeviceFlow] = useState3(null);
1503
- const [statusMessage, setStatusMessage] = useState3("Initiating device authorization...");
1504
- const [error, setError] = useState3(null);
1595
+ const [status, setStatus] = useState4("initiating");
1596
+ const [deviceFlow, setDeviceFlow] = useState4(null);
1597
+ const [statusMessage, setStatusMessage] = useState4("Initiating device authorization...");
1598
+ const [error, setError] = useState4(null);
1505
1599
  useEffect2(() => {
1506
1600
  const runLoginFlow = async () => {
1507
1601
  const oauth = new OAuthClient(apiUrl);
@@ -1545,15 +1639,15 @@ function LoginFlow({ apiUrl = "http://localhost:3000", configStore, onSuccess, o
1545
1639
  }
1546
1640
  }, [deviceFlow, status]);
1547
1641
  if (status === "initiating") {
1548
- return /* @__PURE__ */ React12.createElement(Box12, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React12.createElement(Box12, null, /* @__PURE__ */ React12.createElement(Text11, { color: "cyan" }, /* @__PURE__ */ React12.createElement(Spinner2, { type: "dots" }), " Initiating device authorization...")));
1642
+ return /* @__PURE__ */ React13.createElement(Box13, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React13.createElement(Box13, null, /* @__PURE__ */ React13.createElement(Text12, { color: "cyan" }, /* @__PURE__ */ React13.createElement(Spinner2, { type: "dots" }), " Initiating device authorization...")));
1549
1643
  }
1550
1644
  if (status === "error") {
1551
- return /* @__PURE__ */ React12.createElement(Box12, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React12.createElement(Box12, { marginBottom: 1 }, /* @__PURE__ */ React12.createElement(Text11, { color: "red", bold: true }, "\u2716 Authentication Failed")), /* @__PURE__ */ React12.createElement(Box12, null, /* @__PURE__ */ React12.createElement(Text11, { color: "red" }, error)));
1645
+ return /* @__PURE__ */ React13.createElement(Box13, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React13.createElement(Box13, { marginBottom: 1 }, /* @__PURE__ */ React13.createElement(Text12, { color: "red", bold: true }, "\u2716 Authentication Failed")), /* @__PURE__ */ React13.createElement(Box13, null, /* @__PURE__ */ React13.createElement(Text12, { color: "red" }, error)));
1552
1646
  }
1553
1647
  if (status === "success") {
1554
- return /* @__PURE__ */ React12.createElement(Box12, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React12.createElement(Box12, { marginBottom: 1 }, /* @__PURE__ */ React12.createElement(Text11, { color: "green", bold: true }, "\u2714 Successfully authenticated!")), /* @__PURE__ */ React12.createElement(Box12, null, /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, "You can now use B4M CLI with your account.")));
1648
+ return /* @__PURE__ */ React13.createElement(Box13, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React13.createElement(Box13, { marginBottom: 1 }, /* @__PURE__ */ React13.createElement(Text12, { color: "green", bold: true }, "\u2714 Successfully authenticated!")), /* @__PURE__ */ React13.createElement(Box13, null, /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, "You can now use B4M CLI with your account.")));
1555
1649
  }
1556
- return /* @__PURE__ */ React12.createElement(Box12, { flexDirection: "column", padding: 1, borderStyle: "round", borderColor: "cyan" }, /* @__PURE__ */ React12.createElement(Box12, { marginBottom: 1 }, /* @__PURE__ */ React12.createElement(Text11, { color: "cyan", bold: true }, "\u{1F510} Device Authorization")), /* @__PURE__ */ React12.createElement(Box12, { marginBottom: 1 }, /* @__PURE__ */ React12.createElement(Text11, null, "Opening browser automatically... If it doesn't open, please visit:")), /* @__PURE__ */ React12.createElement(Box12, { marginBottom: 1, paddingLeft: 2 }, /* @__PURE__ */ React12.createElement(Text11, { color: "blue", bold: true }, deviceFlow?.verification_uri)), /* @__PURE__ */ React12.createElement(Box12, { marginBottom: 1 }, /* @__PURE__ */ React12.createElement(Text11, null, "And enter this code when prompted:")), /* @__PURE__ */ React12.createElement(Box12, { marginBottom: 1, paddingLeft: 2 }, /* @__PURE__ */ React12.createElement(Text11, { color: "yellow", bold: true }, deviceFlow?.user_code)), /* @__PURE__ */ React12.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React12.createElement(Text11, { color: "cyan" }, /* @__PURE__ */ React12.createElement(Spinner2, { type: "dots" }), " ", statusMessage)), /* @__PURE__ */ React12.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, "Expires in ", deviceFlow ? Math.floor(deviceFlow.expires_in / 60) : 0, " minutes")));
1650
+ return /* @__PURE__ */ React13.createElement(Box13, { flexDirection: "column", padding: 1, borderStyle: "round", borderColor: "cyan" }, /* @__PURE__ */ React13.createElement(Box13, { marginBottom: 1 }, /* @__PURE__ */ React13.createElement(Text12, { color: "cyan", bold: true }, "\u{1F510} Device Authorization")), /* @__PURE__ */ React13.createElement(Box13, { marginBottom: 1 }, /* @__PURE__ */ React13.createElement(Text12, null, "Opening browser automatically... If it doesn't open, please visit:")), /* @__PURE__ */ React13.createElement(Box13, { marginBottom: 1, paddingLeft: 2 }, /* @__PURE__ */ React13.createElement(Text12, { color: "blue", bold: true }, deviceFlow?.verification_uri)), /* @__PURE__ */ React13.createElement(Box13, { marginBottom: 1 }, /* @__PURE__ */ React13.createElement(Text12, null, "And enter this code when prompted:")), /* @__PURE__ */ React13.createElement(Box13, { marginBottom: 1, paddingLeft: 2 }, /* @__PURE__ */ React13.createElement(Text12, { color: "yellow", bold: true }, deviceFlow?.user_code)), /* @__PURE__ */ React13.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(Text12, { color: "cyan" }, /* @__PURE__ */ React13.createElement(Spinner2, { type: "dots" }), " ", statusMessage)), /* @__PURE__ */ React13.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, "Expires in ", deviceFlow ? Math.floor(deviceFlow.expires_in / 60) : 0, " minutes")));
1557
1651
  }
1558
1652
 
1559
1653
  // src/storage/SessionStore.ts
@@ -2439,10 +2533,9 @@ ${options.context}` : this.getSystemPrompt()
2439
2533
  content: query
2440
2534
  }
2441
2535
  ];
2442
- console.log("[DEBUG ReActAgent] Messages array being sent to LLM:");
2443
2536
  messages.forEach((msg, i) => {
2444
2537
  const content = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
2445
- console.log(` [${i}] ${msg.role}: ${content.substring(0, 150)}...`);
2538
+ this.context.logger.debug(` [${i}] ${msg.role}: ${content.substring(0, 150)}...`);
2446
2539
  });
2447
2540
  let finalAnswer = "";
2448
2541
  let reachedMaxIterations = false;
@@ -4835,8 +4928,8 @@ async function processAndStoreImages(images, context) {
4835
4928
  const buffer = await downloadImage(image);
4836
4929
  const fileType = await fileTypeFromBuffer2(buffer);
4837
4930
  const filename = `${uuidv45()}.${fileType?.ext}`;
4838
- const path13 = await context.imageGenerateStorage.upload(buffer, filename, {});
4839
- return path13;
4931
+ const path14 = await context.imageGenerateStorage.upload(buffer, filename, {});
4932
+ return path14;
4840
4933
  }));
4841
4934
  }
4842
4935
  async function updateQuestAndReturnMarkdown(storedImageUrls, context) {
@@ -6048,8 +6141,8 @@ async function processAndStoreImage(imageUrl, context) {
6048
6141
  const buffer = await downloadImage2(imageUrl);
6049
6142
  const fileType = await fileTypeFromBuffer3(buffer);
6050
6143
  const filename = `${uuidv46()}.${fileType?.ext}`;
6051
- const path13 = await context.imageGenerateStorage.upload(buffer, filename, {});
6052
- return path13;
6144
+ const path14 = await context.imageGenerateStorage.upload(buffer, filename, {});
6145
+ return path14;
6053
6146
  }
6054
6147
  async function updateQuestAndReturnMarkdown2(storedImagePath, context) {
6055
6148
  await context.onFinish?.("edit_image", storedImagePath);
@@ -8461,6 +8554,381 @@ var deleteFileTool = {
8461
8554
  })
8462
8555
  };
8463
8556
 
8557
+ // ../../b4m-core/packages/services/dist/src/llm/tools/implementation/bashExecute/index.js
8558
+ import { spawn } from "child_process";
8559
+ import path11 from "path";
8560
+ var DEFAULT_TIMEOUT_MS = 6e4;
8561
+ var MAX_OUTPUT_SIZE = 100 * 1024;
8562
+ var DANGEROUS_PATTERNS = [
8563
+ // Destructive file operations
8564
+ {
8565
+ pattern: /\brm\s+(-[a-zA-Z]*r[a-zA-Z]*\s+|.*\s+-[a-zA-Z]*r).*\//i,
8566
+ reason: "Recursive delete with path",
8567
+ block: true
8568
+ },
8569
+ {
8570
+ pattern: /\brm\s+(-[a-zA-Z]*f[a-zA-Z]*\s+|.*\s+-[a-zA-Z]*f).*--no-preserve-root/i,
8571
+ reason: "Force delete without preserve root",
8572
+ block: true
8573
+ },
8574
+ {
8575
+ pattern: /\brm\s+-[a-zA-Z]*r[a-zA-Z]*f[a-zA-Z]*\s+\//i,
8576
+ reason: "Recursive force delete on root paths",
8577
+ block: true
8578
+ },
8579
+ {
8580
+ pattern: /\brm\s+-[a-zA-Z]*f[a-zA-Z]*r[a-zA-Z]*\s+\//i,
8581
+ reason: "Force recursive delete on root paths",
8582
+ block: true
8583
+ },
8584
+ // System-level dangerous commands
8585
+ { pattern: /\bsudo\b/i, reason: "Elevated privileges (sudo)", block: true },
8586
+ { pattern: /\bsu\s+(-|root)/i, reason: "Switch to root user", block: true },
8587
+ { pattern: /\bchmod\s+777\b/i, reason: "Overly permissive chmod", block: false },
8588
+ { pattern: /\bchown\s+-R\s+root/i, reason: "Recursive chown to root", block: true },
8589
+ // Disk/partition operations
8590
+ { pattern: /\bmkfs\b/i, reason: "Filesystem creation", block: true },
8591
+ { pattern: /\bfdisk\b/i, reason: "Disk partitioning", block: true },
8592
+ { pattern: /\bdd\s+.*of=\/dev\//i, reason: "Direct disk write", block: true },
8593
+ // Network attacks
8594
+ { pattern: /\b(nc|netcat)\s+.*-e\s+\/bin\/(ba)?sh/i, reason: "Reverse shell attempt", block: true },
8595
+ { pattern: /\bcurl\s+.*\|\s*(ba)?sh/i, reason: "Piping remote script to shell", block: true },
8596
+ { pattern: /\bwget\s+.*\|\s*(ba)?sh/i, reason: "Piping remote script to shell", block: true },
8597
+ // Fork bombs and resource exhaustion
8598
+ { pattern: /:\(\)\s*\{\s*:\|:&\s*\}\s*;/i, reason: "Fork bomb", block: true },
8599
+ { pattern: /\bwhile\s+true.*do.*done.*&/i, reason: "Infinite loop in background", block: false },
8600
+ // Credential/sensitive data access
8601
+ { pattern: /\/etc\/shadow/i, reason: "Access to shadow file", block: true },
8602
+ { pattern: /\/etc\/passwd.*>/i, reason: "Modifying passwd file", block: true },
8603
+ { pattern: /\baws\s+.*--profile\s+/i, reason: "AWS profile access", block: false },
8604
+ // History/log manipulation
8605
+ { pattern: /\bhistory\s+-c\b/i, reason: "Clearing shell history", block: false },
8606
+ { pattern: />\s*\/var\/log\//i, reason: "Overwriting system logs", block: true },
8607
+ // Dangerous redirects
8608
+ { pattern: />\s*\/dev\/sda/i, reason: "Writing to block device", block: true },
8609
+ { pattern: />\s*\/dev\/null.*2>&1.*</i, reason: "Potentially hiding output", block: false },
8610
+ // Environment manipulation
8611
+ { pattern: /\bexport\s+PATH\s*=\s*[^$]/i, reason: "Overwriting PATH", block: false },
8612
+ { pattern: /\bexport\s+LD_PRELOAD/i, reason: "LD_PRELOAD manipulation", block: true },
8613
+ // Process/system control
8614
+ { pattern: /\bkill\s+-9\s+(-1|1)\b/i, reason: "Killing all processes", block: true },
8615
+ { pattern: /\bkillall\s+-9\b/i, reason: "Force killing processes", block: false },
8616
+ { pattern: /\bshutdown\b/i, reason: "System shutdown", block: true },
8617
+ { pattern: /\breboot\b/i, reason: "System reboot", block: true },
8618
+ { pattern: /\binit\s+[06]\b/i, reason: "System runlevel change", block: true }
8619
+ ];
8620
+ var SAFE_COMMAND_PREFIXES = [
8621
+ "ls",
8622
+ "cat",
8623
+ "head",
8624
+ "tail",
8625
+ "grep",
8626
+ "find",
8627
+ "echo",
8628
+ "pwd",
8629
+ "whoami",
8630
+ "date",
8631
+ "cal",
8632
+ "wc",
8633
+ "sort",
8634
+ "uniq",
8635
+ "cut",
8636
+ "tr",
8637
+ "sed",
8638
+ "awk",
8639
+ "git",
8640
+ "npm",
8641
+ "pnpm",
8642
+ "yarn",
8643
+ "node",
8644
+ "npx",
8645
+ "tsx",
8646
+ "ts-node",
8647
+ "python",
8648
+ "python3",
8649
+ "pip",
8650
+ "pip3",
8651
+ "docker",
8652
+ "docker-compose",
8653
+ "curl",
8654
+ "wget",
8655
+ // These are safe for fetching, blocked when piped to shell
8656
+ "mkdir",
8657
+ "touch",
8658
+ "cp",
8659
+ "mv",
8660
+ // File operations (still require permission)
8661
+ "which",
8662
+ "whereis",
8663
+ "type",
8664
+ "file",
8665
+ "stat",
8666
+ "env",
8667
+ "printenv",
8668
+ "set",
8669
+ "man",
8670
+ "help",
8671
+ "info",
8672
+ "diff",
8673
+ "comm",
8674
+ "cmp",
8675
+ "tar",
8676
+ "zip",
8677
+ "unzip",
8678
+ "gzip",
8679
+ "gunzip",
8680
+ "ssh",
8681
+ "scp",
8682
+ "rsync",
8683
+ // Network tools
8684
+ "make",
8685
+ "cmake",
8686
+ "cargo",
8687
+ "go",
8688
+ "rustc",
8689
+ "gcc",
8690
+ "g++",
8691
+ // Build tools
8692
+ "jest",
8693
+ "vitest",
8694
+ "mocha",
8695
+ "pytest",
8696
+ // Test runners
8697
+ "eslint",
8698
+ "prettier",
8699
+ "tsc"
8700
+ // Linters/formatters
8701
+ ];
8702
+ function checkDangerousPatterns(command) {
8703
+ for (const { pattern, reason, block } of DANGEROUS_PATTERNS) {
8704
+ if (pattern.test(command)) {
8705
+ return { blocked: block, reason };
8706
+ }
8707
+ }
8708
+ return { blocked: false };
8709
+ }
8710
+ function getBaseCommand(command) {
8711
+ const trimmed = command.trim();
8712
+ const match = trimmed.match(/^(\S+)/);
8713
+ return match ? match[1] : "";
8714
+ }
8715
+ function isSafeCommandPrefix(command) {
8716
+ const baseCommand = getBaseCommand(command);
8717
+ return SAFE_COMMAND_PREFIXES.some((safe) => baseCommand === safe || baseCommand.endsWith(`/${safe}`));
8718
+ }
8719
+ async function executeBashCommand(params) {
8720
+ const { command, cwd: relativeCwd, timeout = DEFAULT_TIMEOUT_MS } = params;
8721
+ if (!command || command.trim().length === 0) {
8722
+ return {
8723
+ stdout: "",
8724
+ stderr: "Error: Command cannot be empty",
8725
+ exitCode: 1,
8726
+ timedOut: false,
8727
+ blocked: true,
8728
+ blockedReason: "Empty command"
8729
+ };
8730
+ }
8731
+ const dangerCheck = checkDangerousPatterns(command);
8732
+ if (dangerCheck.blocked) {
8733
+ return {
8734
+ stdout: "",
8735
+ stderr: `Command blocked for safety: ${dangerCheck.reason}`,
8736
+ exitCode: 1,
8737
+ timedOut: false,
8738
+ blocked: true,
8739
+ blockedReason: dangerCheck.reason
8740
+ };
8741
+ }
8742
+ const baseCwd = process.cwd();
8743
+ const targetCwd = relativeCwd ? path11.resolve(baseCwd, relativeCwd) : baseCwd;
8744
+ const effectiveTimeout = Math.min(timeout, 5 * 60 * 1e3);
8745
+ return new Promise((resolve3) => {
8746
+ let stdout = "";
8747
+ let stderr = "";
8748
+ let timedOut = false;
8749
+ const proc = spawn("bash", ["-c", command], {
8750
+ cwd: targetCwd,
8751
+ env: {
8752
+ ...process.env,
8753
+ // Prevent color codes that might be hard to read
8754
+ NO_COLOR: "1",
8755
+ FORCE_COLOR: "0"
8756
+ },
8757
+ stdio: ["ignore", "pipe", "pipe"]
8758
+ });
8759
+ const timeoutId = setTimeout(() => {
8760
+ timedOut = true;
8761
+ proc.kill("SIGTERM");
8762
+ setTimeout(() => {
8763
+ if (!proc.killed) {
8764
+ proc.kill("SIGKILL");
8765
+ }
8766
+ }, 5e3);
8767
+ }, effectiveTimeout);
8768
+ proc.stdout.on("data", (data) => {
8769
+ if (stdout.length < MAX_OUTPUT_SIZE) {
8770
+ stdout += data.toString();
8771
+ if (stdout.length > MAX_OUTPUT_SIZE) {
8772
+ stdout = stdout.slice(0, MAX_OUTPUT_SIZE) + "\n... [output truncated]";
8773
+ }
8774
+ }
8775
+ });
8776
+ proc.stderr.on("data", (data) => {
8777
+ if (stderr.length < MAX_OUTPUT_SIZE) {
8778
+ stderr += data.toString();
8779
+ if (stderr.length > MAX_OUTPUT_SIZE) {
8780
+ stderr = stderr.slice(0, MAX_OUTPUT_SIZE) + "\n... [output truncated]";
8781
+ }
8782
+ }
8783
+ });
8784
+ proc.on("close", (exitCode) => {
8785
+ clearTimeout(timeoutId);
8786
+ resolve3({
8787
+ stdout: stdout.trim(),
8788
+ stderr: stderr.trim(),
8789
+ exitCode,
8790
+ timedOut,
8791
+ blocked: false
8792
+ });
8793
+ });
8794
+ proc.on("error", (error) => {
8795
+ clearTimeout(timeoutId);
8796
+ resolve3({
8797
+ stdout: "",
8798
+ stderr: `Failed to execute command: ${error.message}`,
8799
+ exitCode: 1,
8800
+ timedOut: false,
8801
+ blocked: false
8802
+ });
8803
+ });
8804
+ });
8805
+ }
8806
+ function formatResult(result, command) {
8807
+ const parts = [];
8808
+ parts.push(`$ ${command}`);
8809
+ parts.push("");
8810
+ if (result.blocked) {
8811
+ parts.push(`BLOCKED: ${result.blockedReason}`);
8812
+ parts.push("");
8813
+ parts.push("This command was blocked for safety reasons.");
8814
+ parts.push("If you believe this is a false positive, please run the command manually.");
8815
+ return parts.join("\n");
8816
+ }
8817
+ if (result.timedOut) {
8818
+ parts.push("WARNING: Command timed out and was terminated.");
8819
+ parts.push("");
8820
+ }
8821
+ if (result.stdout) {
8822
+ parts.push(result.stdout);
8823
+ }
8824
+ if (result.stderr) {
8825
+ if (result.stdout) {
8826
+ parts.push("");
8827
+ }
8828
+ parts.push("STDERR:");
8829
+ parts.push(result.stderr);
8830
+ }
8831
+ if (result.exitCode !== 0 && result.exitCode !== null) {
8832
+ parts.push("");
8833
+ parts.push(`Exit code: ${result.exitCode}`);
8834
+ }
8835
+ if (!result.stdout && !result.stderr && !result.timedOut) {
8836
+ parts.push("(command completed with no output)");
8837
+ }
8838
+ return parts.join("\n");
8839
+ }
8840
+ var bashExecuteTool = {
8841
+ name: "bash_execute",
8842
+ implementation: (context) => ({
8843
+ toolFn: async (value) => {
8844
+ const params = value;
8845
+ const isSafe = isSafeCommandPrefix(params.command);
8846
+ context.logger.info("Bash: Executing command", {
8847
+ command: params.command,
8848
+ cwd: params.cwd || ".",
8849
+ timeout: params.timeout || DEFAULT_TIMEOUT_MS,
8850
+ isSafeCommand: isSafe
8851
+ });
8852
+ if (context.onStart) {
8853
+ await context.onStart("bash_execute", {
8854
+ command: params.command,
8855
+ cwd: params.cwd
8856
+ });
8857
+ }
8858
+ try {
8859
+ const result = await executeBashCommand(params);
8860
+ const formattedResult = formatResult(result, params.command);
8861
+ context.logger.info("Bash: Command completed", {
8862
+ exitCode: result.exitCode,
8863
+ timedOut: result.timedOut,
8864
+ blocked: result.blocked
8865
+ });
8866
+ if (context.onFinish) {
8867
+ await context.onFinish("bash_execute", {
8868
+ command: params.command,
8869
+ exitCode: result.exitCode,
8870
+ blocked: result.blocked
8871
+ });
8872
+ }
8873
+ return formattedResult;
8874
+ } catch (error) {
8875
+ context.logger.error("Bash: Command failed", error);
8876
+ if (context.onFinish) {
8877
+ await context.onFinish("bash_execute", {
8878
+ command: params.command,
8879
+ error: error instanceof Error ? error.message : "Unknown error"
8880
+ });
8881
+ }
8882
+ throw error;
8883
+ }
8884
+ },
8885
+ toolSchema: {
8886
+ name: "bash_execute",
8887
+ description: `Execute a bash command in the terminal. Use this for running shell commands, scripts, build tools, git operations, and other CLI tasks.
8888
+
8889
+ SAFETY NOTES:
8890
+ - Commands are executed in the current working directory (or specified cwd)
8891
+ - Dangerous commands (sudo, rm -rf /, etc.) are automatically blocked
8892
+ - Commands have a default timeout of 60 seconds (max 5 minutes)
8893
+ - Output is limited to prevent overwhelming responses
8894
+ - This tool ALWAYS requires user permission before execution
8895
+
8896
+ COMMON USE CASES:
8897
+ - Running build commands: npm run build, make, cargo build
8898
+ - Git operations: git status, git log, git diff
8899
+ - Viewing system info: ls, pwd, cat, head, tail
8900
+ - Running tests: npm test, pytest, cargo test
8901
+ - Package management: npm install, pip install
8902
+ - File operations: mkdir, cp, mv (with permission)
8903
+
8904
+ BLOCKED OPERATIONS:
8905
+ - sudo and privilege escalation
8906
+ - Recursive deletes on system paths
8907
+ - Direct disk operations
8908
+ - Fork bombs and resource exhaustion
8909
+ - Piping remote scripts to shell`,
8910
+ parameters: {
8911
+ type: "object",
8912
+ properties: {
8913
+ command: {
8914
+ type: "string",
8915
+ description: "The bash command to execute. Can include pipes, redirects, and chained commands."
8916
+ },
8917
+ cwd: {
8918
+ type: "string",
8919
+ description: "Working directory for the command (optional). Can be relative or absolute path. Defaults to current directory."
8920
+ },
8921
+ timeout: {
8922
+ type: "number",
8923
+ description: "Timeout in milliseconds (optional, default: 60000, max: 300000). Command will be terminated if it exceeds this time."
8924
+ }
8925
+ },
8926
+ required: ["command"]
8927
+ }
8928
+ }
8929
+ })
8930
+ };
8931
+
8464
8932
  // ../../b4m-core/packages/services/dist/src/llm/tools/index.js
8465
8933
  var tools = {
8466
8934
  dice_roll: diceRollTool,
@@ -8488,7 +8956,9 @@ var tools = {
8488
8956
  create_file: createFileTool,
8489
8957
  glob_files: globFilesTool,
8490
8958
  grep_search: grepSearchTool,
8491
- delete_file: deleteFileTool
8959
+ delete_file: deleteFileTool,
8960
+ // Shell execution
8961
+ bash_execute: bashExecuteTool
8492
8962
  };
8493
8963
  var generateTools = (userId, user, logger2, { db }, storage, imageGenerateStorage, statusUpdate, onStart, onFinish, llm, config, model) => {
8494
8964
  const context = {
@@ -8768,21 +9238,21 @@ var NoOpStorage = class extends BaseStorage {
8768
9238
  async upload(input, destination, options) {
8769
9239
  return `/tmp/${destination}`;
8770
9240
  }
8771
- async download(path13) {
9241
+ async download(path14) {
8772
9242
  throw new Error("Download not supported in CLI");
8773
9243
  }
8774
- async delete(path13) {
9244
+ async delete(path14) {
8775
9245
  }
8776
- async getSignedUrl(path13) {
8777
- return `/tmp/${path13}`;
9246
+ async getSignedUrl(path14) {
9247
+ return `/tmp/${path14}`;
8778
9248
  }
8779
- getPublicUrl(path13) {
8780
- return `/tmp/${path13}`;
9249
+ getPublicUrl(path14) {
9250
+ return `/tmp/${path14}`;
8781
9251
  }
8782
- async getPreview(path13) {
8783
- return `/tmp/${path13}`;
9252
+ async getPreview(path14) {
9253
+ return `/tmp/${path14}`;
8784
9254
  }
8785
- async getMetadata(path13) {
9255
+ async getMetadata(path14) {
8786
9256
  return { size: 0, contentType: "application/octet-stream" };
8787
9257
  }
8788
9258
  };
@@ -8840,6 +9310,10 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
8840
9310
  } catch (error) {
8841
9311
  preview = `[Could not generate preview: ${error instanceof Error ? error.message : "Unknown error"}]`;
8842
9312
  }
9313
+ } else if (toolName === "bash_execute" && args?.command) {
9314
+ const cwd = args.cwd ? ` (in ${args.cwd})` : "";
9315
+ const timeout = args.timeout ? ` [timeout: ${args.timeout}ms]` : "";
9316
+ preview = `$ ${args.command}${cwd}${timeout}`;
8843
9317
  }
8844
9318
  const response = await showPermissionPrompt(toolName, args, preview);
8845
9319
  if (response.action === "deny") {
@@ -8924,6 +9398,8 @@ function generateCliTools(userId, llm, model, permissionManager, showPermissionP
8924
9398
  glob_files: {},
8925
9399
  grep_search: {},
8926
9400
  delete_file: {},
9401
+ // Shell execution (always requires permission)
9402
+ bash_execute: {},
8927
9403
  // Tools requiring API keys (only include if API key is available)
8928
9404
  ...hasSerperKey && { web_search: {} },
8929
9405
  // Requires SERPER_API_KEY
@@ -8991,6 +9467,7 @@ var DEFAULT_TOOL_CATEGORIES = {
8991
9467
  create_file: "prompt_always",
8992
9468
  delete_file: "prompt_always",
8993
9469
  shell_execute: "prompt_always",
9470
+ bash_execute: "prompt_always",
8994
9471
  git_commit: "prompt_always",
8995
9472
  git_push: "prompt_always",
8996
9473
  // ===== PROMPT DEFAULT (Repository read tools) =====
@@ -9154,7 +9631,7 @@ function getEnvironmentName(configApiConfig) {
9154
9631
 
9155
9632
  // src/utils/Logger.ts
9156
9633
  import fs10 from "fs/promises";
9157
- import path11 from "path";
9634
+ import path12 from "path";
9158
9635
  import os from "os";
9159
9636
  var Logger2 = class _Logger {
9160
9637
  constructor() {
@@ -9177,9 +9654,9 @@ var Logger2 = class _Logger {
9177
9654
  */
9178
9655
  async initialize(sessionId) {
9179
9656
  this.sessionId = sessionId;
9180
- const debugDir = path11.join(os.homedir(), ".bike4mind", "debug");
9657
+ const debugDir = path12.join(os.homedir(), ".bike4mind", "debug");
9181
9658
  await fs10.mkdir(debugDir, { recursive: true });
9182
- this.logFilePath = path11.join(debugDir, `${sessionId}.txt`);
9659
+ this.logFilePath = path12.join(debugDir, `${sessionId}.txt`);
9183
9660
  await this.writeToFile("INFO", "=== CLI SESSION START ===");
9184
9661
  }
9185
9662
  /**
@@ -9389,12 +9866,12 @@ var Logger2 = class _Logger {
9389
9866
  async cleanupOldLogs() {
9390
9867
  if (!this.fileLoggingEnabled) return;
9391
9868
  try {
9392
- const debugDir = path11.join(os.homedir(), ".bike4mind", "debug");
9869
+ const debugDir = path12.join(os.homedir(), ".bike4mind", "debug");
9393
9870
  const files = await fs10.readdir(debugDir);
9394
9871
  const now = Date.now();
9395
9872
  const thirtyDaysAgo = now - 30 * 24 * 60 * 60 * 1e3;
9396
9873
  for (const file of files) {
9397
- const filePath = path11.join(debugDir, file);
9874
+ const filePath = path12.join(debugDir, file);
9398
9875
  const stats = await fs10.stat(filePath);
9399
9876
  if (stats.mtime.getTime() < thirtyDaysAgo) {
9400
9877
  await fs10.unlink(filePath);
@@ -9410,7 +9887,7 @@ var logger = Logger2.getInstance();
9410
9887
  // ../../b4m-core/packages/mcp/dist/src/client.js
9411
9888
  import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
9412
9889
  import { Client as Client2 } from "@modelcontextprotocol/sdk/client/index.js";
9413
- import path12 from "path";
9890
+ import path13 from "path";
9414
9891
  import { existsSync as existsSync8, readdirSync as readdirSync3 } from "fs";
9415
9892
  var MCPClient = class {
9416
9893
  // Note: This class handles MCP server communication with repository filtering
@@ -9451,16 +9928,16 @@ var MCPClient = class {
9451
9928
  const root = process.env.INIT_CWD || process.cwd();
9452
9929
  const candidatePaths = [
9453
9930
  // When running from SST Lambda with node_modules structure (copyFiles)
9454
- path12.join(root, `node_modules/@bike4mind/mcp/dist/src/${this.serverName}/index.js`),
9931
+ path13.join(root, `node_modules/@bike4mind/mcp/dist/src/${this.serverName}/index.js`),
9455
9932
  // When running from SST Lambda deployed environment (/var/task)
9456
- path12.join(root, `b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
9933
+ path13.join(root, `b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
9457
9934
  // When running from SST Lambda (.sst/artifacts/mcpHandler-dev), navigate to monorepo root (3 levels up)
9458
- path12.join(root, `../../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
9935
+ path13.join(root, `../../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
9459
9936
  // When running from packages/client (Next.js app), navigate to monorepo root (2 levels up)
9460
- path12.join(root, `../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
9937
+ path13.join(root, `../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
9461
9938
  // Original paths (backward compatibility)
9462
- path12.join(root, `/b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
9463
- path12.join(root, "core", "mcp", "servers", this.serverName, "dist", "index.js")
9939
+ path13.join(root, `/b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
9940
+ path13.join(root, "core", "mcp", "servers", this.serverName, "dist", "index.js")
9464
9941
  ];
9465
9942
  const serverScriptPath = candidatePaths.find((p) => existsSync8(p));
9466
9943
  if (!serverScriptPath) {
@@ -10261,7 +10738,7 @@ import { isAxiosError as isAxiosError2 } from "axios";
10261
10738
  // package.json
10262
10739
  var package_default = {
10263
10740
  name: "@bike4mind/cli",
10264
- version: "0.2.7-ja-fix-confluence-table-data-5752.17142+305b1c6f1",
10741
+ version: "0.2.8-cli-bash-tools.17140+f678d9888",
10265
10742
  type: "module",
10266
10743
  description: "Interactive CLI tool for Bike4Mind with ReAct agents",
10267
10744
  license: "UNLICENSED",
@@ -10364,10 +10841,10 @@ var package_default = {
10364
10841
  },
10365
10842
  devDependencies: {
10366
10843
  "@bike4mind/agents": "0.1.0",
10367
- "@bike4mind/common": "2.38.1-ja-fix-confluence-table-data-5752.17142+305b1c6f1",
10368
- "@bike4mind/mcp": "1.20.1-ja-fix-confluence-table-data-5752.17142+305b1c6f1",
10369
- "@bike4mind/services": "2.33.1-ja-fix-confluence-table-data-5752.17142+305b1c6f1",
10370
- "@bike4mind/utils": "2.1.2-ja-fix-confluence-table-data-5752.17142+305b1c6f1",
10844
+ "@bike4mind/common": "2.38.2-cli-bash-tools.17140+f678d9888",
10845
+ "@bike4mind/mcp": "1.20.2-cli-bash-tools.17140+f678d9888",
10846
+ "@bike4mind/services": "2.33.2-cli-bash-tools.17140+f678d9888",
10847
+ "@bike4mind/utils": "2.1.3-cli-bash-tools.17140+f678d9888",
10371
10848
  "@types/better-sqlite3": "^7.6.12",
10372
10849
  "@types/diff": "^5.0.9",
10373
10850
  "@types/jsonwebtoken": "^9.0.4",
@@ -10380,7 +10857,7 @@ var package_default = {
10380
10857
  typescript: "^5.9.3",
10381
10858
  vitest: "^3.2.4"
10382
10859
  },
10383
- gitHead: "305b1c6f12a188c60bbc63a1c1f5f6a13860c49e"
10860
+ gitHead: "f678d98888d841ba0496d91a1225dd89edb21e35"
10384
10861
  };
10385
10862
 
10386
10863
  // src/config/constants.ts
@@ -10402,7 +10879,7 @@ var usageCache = null;
10402
10879
  function CliApp() {
10403
10880
  const { exit } = useApp();
10404
10881
  const imageRenderer = new ImageRenderer();
10405
- const [state, setState] = useState4({
10882
+ const [state, setState] = useState5({
10406
10883
  session: null,
10407
10884
  sessionStore: new SessionStore(),
10408
10885
  configStore: new ConfigStore(),
@@ -10415,11 +10892,12 @@ function CliApp() {
10415
10892
  mcpManager: null,
10416
10893
  permissionManager: null,
10417
10894
  permissionPrompt: null,
10418
- trustLocationSelector: null
10895
+ trustLocationSelector: null,
10896
+ rewindSelector: null
10419
10897
  });
10420
- const [isInitialized, setIsInitialized] = useState4(false);
10421
- const [initError, setInitError] = useState4(null);
10422
- const [commandHistory, setCommandHistory] = useState4([]);
10898
+ const [isInitialized, setIsInitialized] = useState5(false);
10899
+ const [initError, setInitError] = useState5(null);
10900
+ const [commandHistory, setCommandHistory] = useState5([]);
10423
10901
  const imageStoreInitPromise = useRef(null);
10424
10902
  const setStoreSession = useCliStore((state2) => state2.setSession);
10425
10903
  const setPermissionPrompt = useCliStore((state2) => state2.setPermissionPrompt);
@@ -10460,7 +10938,7 @@ function CliApp() {
10460
10938
  process.exit(0);
10461
10939
  }, 100);
10462
10940
  }, [state.session, state.sessionStore, state.mcpManager, state.agent, state.imageStore]);
10463
- useInput3((input, key) => {
10941
+ useInput4((input, key) => {
10464
10942
  if (key.ctrl && input === "c") {
10465
10943
  const now = Date.now();
10466
10944
  if (exitTimestamp && now - exitTimestamp < EXIT_TIMEOUT_MS) {
@@ -10718,6 +11196,29 @@ Remember: Use context from previous messages to understand follow-up questions.`
10718
11196
  console.log("\u{1F4A1} Run /login to authenticate with your B4M account.\n");
10719
11197
  return;
10720
11198
  }
11199
+ const currentSteps = [];
11200
+ const stepHandler = (step) => {
11201
+ currentSteps.push(step);
11202
+ const currentSession = useCliStore.getState().session;
11203
+ if (currentSession) {
11204
+ const messages = [...currentSession.messages];
11205
+ const lastMessage = messages[messages.length - 1];
11206
+ if (lastMessage && lastMessage.role === "assistant") {
11207
+ messages[messages.length - 1] = {
11208
+ ...lastMessage,
11209
+ metadata: {
11210
+ ...lastMessage.metadata,
11211
+ steps: [...currentSteps]
11212
+ }
11213
+ };
11214
+ setStoreSession({
11215
+ ...currentSession,
11216
+ messages
11217
+ });
11218
+ }
11219
+ }
11220
+ };
11221
+ state.agent.on("action", stepHandler);
10721
11222
  try {
10722
11223
  let messageContent = message;
10723
11224
  let userMessageContent = message;
@@ -10731,6 +11232,21 @@ Remember: Use context from previous messages to understand follow-up questions.`
10731
11232
  content: userMessageContent,
10732
11233
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
10733
11234
  };
11235
+ const pendingAssistantMessage = {
11236
+ role: "assistant",
11237
+ content: "...",
11238
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
11239
+ metadata: {
11240
+ steps: []
11241
+ }
11242
+ };
11243
+ const sessionWithMessages = {
11244
+ ...state.session,
11245
+ messages: [...state.session.messages, userMessage, pendingAssistantMessage],
11246
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
11247
+ };
11248
+ setState((prev) => ({ ...prev, session: sessionWithMessages }));
11249
+ setStoreSession(sessionWithMessages);
10734
11250
  const recentMessages = state.session.messages.slice(-20);
10735
11251
  const previousMessages = recentMessages.filter((msg) => msg.role === "user" || msg.role === "assistant").map((msg) => ({
10736
11252
  role: msg.role,
@@ -10744,26 +11260,28 @@ Remember: Use context from previous messages to understand follow-up questions.`
10744
11260
  console.log("\n\u26A0\uFE0F Action denied by user\n");
10745
11261
  }
10746
11262
  const successfulToolCalls = result.steps.filter((s) => s.type === "observation").length;
10747
- const assistantMessage = {
11263
+ const currentSession = useCliStore.getState().session;
11264
+ if (!currentSession) return;
11265
+ const finalMessages = [...currentSession.messages];
11266
+ const finalAssistantMessage = {
10748
11267
  role: "assistant",
10749
11268
  content: result.finalAnswer,
10750
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
11269
+ timestamp: pendingAssistantMessage.timestamp,
10751
11270
  metadata: {
10752
11271
  tokenUsage: {
10753
11272
  prompt: 0,
10754
- // TODO: Extract from result
10755
11273
  completion: 0,
10756
11274
  total: result.completionInfo.totalTokens
10757
11275
  },
10758
11276
  steps: result.steps,
10759
11277
  // Complete history: thoughts, actions, observations
10760
11278
  permissionDenied
10761
- // Mark if this ended due to permission denial
10762
11279
  }
10763
11280
  };
11281
+ finalMessages[finalMessages.length - 1] = finalAssistantMessage;
10764
11282
  const updatedSession = {
10765
- ...state.session,
10766
- messages: [...state.session.messages, userMessage, assistantMessage],
11283
+ ...currentSession,
11284
+ messages: finalMessages,
10767
11285
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
10768
11286
  metadata: {
10769
11287
  ...state.session.metadata,
@@ -10783,6 +11301,8 @@ Remember: Use context from previous messages to understand follow-up questions.`
10783
11301
  }
10784
11302
  }
10785
11303
  console.error("Error processing message:", error);
11304
+ } finally {
11305
+ state.agent.off("action", stepHandler);
10786
11306
  }
10787
11307
  };
10788
11308
  const handleImageDetected = async (imageData) => {
@@ -10814,6 +11334,30 @@ Remember: Use context from previous messages to understand follow-up questions.`
10814
11334
  throw error;
10815
11335
  }
10816
11336
  };
11337
+ const recalculateSessionMetadata = (messages) => {
11338
+ let totalTokens = 0;
11339
+ let totalCost = 0;
11340
+ let toolCallCount = 0;
11341
+ for (const msg of messages) {
11342
+ if (msg.metadata) {
11343
+ if (msg.metadata.tokenUsage) {
11344
+ totalTokens += msg.metadata.tokenUsage.total || 0;
11345
+ }
11346
+ if (msg.metadata.cost) {
11347
+ totalCost += msg.metadata.cost;
11348
+ }
11349
+ if (msg.metadata.steps) {
11350
+ const observations = msg.metadata.steps.filter((s) => s.type === "observation");
11351
+ toolCallCount += observations.length;
11352
+ }
11353
+ }
11354
+ }
11355
+ return {
11356
+ totalTokens,
11357
+ totalCost,
11358
+ toolCallCount
11359
+ };
11360
+ };
10817
11361
  const handleCommand = async (command, args) => {
10818
11362
  switch (command) {
10819
11363
  case "help":
@@ -10822,6 +11366,7 @@ Available commands:
10822
11366
  /help - Show this help message
10823
11367
  /exit - Exit the CLI
10824
11368
  /clear - Start a new session
11369
+ /rewind - Rewind conversation to a previous point
10825
11370
  /login - Authenticate with your B4M account
10826
11371
  /logout - Clear authentication and sign out
10827
11372
  /whoami - Show current authenticated user
@@ -11097,6 +11642,65 @@ Project Configuration:
11097
11642
  `);
11098
11643
  break;
11099
11644
  }
11645
+ case "rewind":
11646
+ case "undo": {
11647
+ if (!state.session) {
11648
+ console.log("No active session to rewind");
11649
+ return;
11650
+ }
11651
+ if (state.session.messages.length === 0) {
11652
+ console.log("\u26A0\uFE0F Conversation is empty. Nothing to rewind.");
11653
+ return;
11654
+ }
11655
+ const userMessages = state.session.messages.filter((msg) => msg.role === "user");
11656
+ if (userMessages.length === 0) {
11657
+ console.log("\u26A0\uFE0F No user messages found. Nothing to rewind.");
11658
+ return;
11659
+ }
11660
+ if (userMessages.length === 1) {
11661
+ console.log("\u26A0\uFE0F Only one exchange in the conversation. Use /clear to start a new session instead.");
11662
+ return;
11663
+ }
11664
+ const handleRewindSelect = async (messageIndex) => {
11665
+ setState((prev) => ({ ...prev, rewindSelector: null }));
11666
+ if (messageIndex === null) {
11667
+ console.log("\u274C Rewind operation cancelled");
11668
+ return;
11669
+ }
11670
+ if (!state.session) {
11671
+ console.log("\u274C No active session");
11672
+ return;
11673
+ }
11674
+ const selectedMessage = state.session.messages[messageIndex];
11675
+ const prefillContent = selectedMessage?.content || "";
11676
+ const rewindedMessages = state.session.messages.slice(0, messageIndex);
11677
+ const newMetadata = recalculateSessionMetadata(rewindedMessages);
11678
+ const rewindedSession = {
11679
+ ...state.session,
11680
+ messages: rewindedMessages,
11681
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
11682
+ metadata: newMetadata
11683
+ };
11684
+ setState((prev) => ({
11685
+ ...prev,
11686
+ session: rewindedSession,
11687
+ prefillInput: prefillContent
11688
+ }));
11689
+ setStoreSession(rewindedSession);
11690
+ await state.sessionStore.save(rewindedSession);
11691
+ console.log("\u2705 Conversation rewound successfully");
11692
+ console.log(`\u{1F4CA} Current state: ${rewindedMessages.length} messages, ${newMetadata.totalTokens} tokens`);
11693
+ console.log(`\u{1F4DD} Your message has been placed in the input. Edit and send when ready.
11694
+ `);
11695
+ };
11696
+ setState((prev) => ({
11697
+ ...prev,
11698
+ rewindSelector: {
11699
+ resolve: handleRewindSelect
11700
+ }
11701
+ }));
11702
+ break;
11703
+ }
11100
11704
  case "usage": {
11101
11705
  const usageAuthTokens = await state.configStore.getAuthTokens();
11102
11706
  if (!usageAuthTokens || new Date(usageAuthTokens.expiresAt) <= /* @__PURE__ */ new Date()) {
@@ -11250,12 +11854,12 @@ No usage data available for the last ${USAGE_DAYS} days.`);
11250
11854
  setState((prev) => ({ ...prev, config: updatedConfig }));
11251
11855
  };
11252
11856
  if (initError) {
11253
- return /* @__PURE__ */ React13.createElement(Box13, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React13.createElement(Text12, { color: "red", bold: true }, "\u274C Initialization Error"), /* @__PURE__ */ React13.createElement(Text12, null, initError), /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, "\n", "Tip: Run /config to set up your API keys"));
11857
+ return /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React14.createElement(Text13, { color: "red", bold: true }, "\u274C Initialization Error"), /* @__PURE__ */ React14.createElement(Text13, null, initError), /* @__PURE__ */ React14.createElement(Text13, { dimColor: true }, "\n", "Tip: Run /config to set up your API keys"));
11254
11858
  }
11255
11859
  if (state.trustLocationSelector) {
11256
11860
  const projectDir = state.configStore.getProjectConfigDir();
11257
11861
  const inProject = projectDir !== null;
11258
- return /* @__PURE__ */ React13.createElement(
11862
+ return /* @__PURE__ */ React14.createElement(
11259
11863
  TrustLocationSelector,
11260
11864
  {
11261
11865
  inProject,
@@ -11272,9 +11876,27 @@ No usage data available for the last ${USAGE_DAYS} days.`);
11272
11876
  }
11273
11877
  );
11274
11878
  }
11879
+ if (state.rewindSelector && state.session) {
11880
+ return /* @__PURE__ */ React14.createElement(
11881
+ RewindSelector,
11882
+ {
11883
+ messages: state.session.messages,
11884
+ onSelect: (messageIndex) => {
11885
+ if (state.rewindSelector) {
11886
+ state.rewindSelector.resolve(messageIndex);
11887
+ }
11888
+ },
11889
+ onCancel: () => {
11890
+ if (state.rewindSelector) {
11891
+ state.rewindSelector.resolve(null);
11892
+ }
11893
+ }
11894
+ }
11895
+ );
11896
+ }
11275
11897
  if (state.showLoginFlow) {
11276
11898
  const loginApiUrl = getApiUrl(state.config?.apiConfig);
11277
- return /* @__PURE__ */ React13.createElement(
11899
+ return /* @__PURE__ */ React14.createElement(
11278
11900
  LoginFlow,
11279
11901
  {
11280
11902
  apiUrl: loginApiUrl,
@@ -11297,9 +11919,9 @@ No usage data available for the last ${USAGE_DAYS} days.`);
11297
11919
  );
11298
11920
  }
11299
11921
  if (!isInitialized) {
11300
- return /* @__PURE__ */ React13.createElement(Box13, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React13.createElement(Text12, null, "\u{1F680} Initializing..."));
11922
+ return /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React14.createElement(Text13, null, "\u{1F680} Initializing..."));
11301
11923
  }
11302
- return /* @__PURE__ */ React13.createElement(
11924
+ return /* @__PURE__ */ React14.createElement(
11303
11925
  App,
11304
11926
  {
11305
11927
  onMessage: handleMessage,
@@ -11309,6 +11931,10 @@ No usage data available for the last ${USAGE_DAYS} days.`);
11309
11931
  config: state.config,
11310
11932
  availableModels: state.availableModels,
11311
11933
  onSaveConfig: handleSaveConfig,
11934
+ prefillInput: state.prefillInput,
11935
+ onPrefillConsumed: () => {
11936
+ setState((prev) => ({ ...prev, prefillInput: void 0 }));
11937
+ },
11312
11938
  onPermissionResponse: (response) => {
11313
11939
  if (state.permissionPrompt) {
11314
11940
  state.permissionPrompt.resolve({ action: response });
@@ -11334,6 +11960,6 @@ var isDevMode = import.meta.url.includes("/src/") || process.env.NODE_ENV === "d
11334
11960
  if (isDevMode) {
11335
11961
  console.log("\u{1F527} Running in development mode (using TypeScript source)\n");
11336
11962
  }
11337
- render(/* @__PURE__ */ React13.createElement(CliApp, null), {
11963
+ render(/* @__PURE__ */ React14.createElement(CliApp, null), {
11338
11964
  exitOnCtrlC: false
11339
11965
  });