@bike4mind/cli 0.2.8-cli-bash-tools.17146 → 0.2.8-feat-cli-context-file-loading.17148

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-6S7HV2GF.js";
8
- import "./chunk-F2K7OCDJ.js";
9
- import "./chunk-RJYG7BUV.js";
7
+ } from "./chunk-3CCBDIFR.js";
8
+ import "./chunk-LIRY24M5.js";
9
+ import "./chunk-YXHQN7SK.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-SE2T5GED.js";
18
+ } from "./chunk-DNSBC3LO.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-HD4QQGS6.js";
76
+ } from "./chunk-H6SHASMZ.js";
77
77
  import {
78
78
  __require
79
79
  } from "./chunk-PDX44BCA.js";
80
80
 
81
81
  // src/index.tsx
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";
82
+ import React15, { useState as useState6, useEffect as useEffect3, useCallback, useRef } from "react";
83
+ import { render, Box as Box14, Text as Text14, useApp, useInput as useInput5 } from "ink";
84
84
  import { v4 as uuidv49 } from "uuid";
85
85
 
86
86
  // src/components/App.tsx
87
- import React9 from "react";
88
- import { Box as Box9, Text as Text8 } from "ink";
87
+ import React10 from "react";
88
+ import { Box as Box9, Text as Text9, Static } from "ink";
89
89
 
90
90
  // src/components/StatusBar.tsx
91
91
  import React from "react";
@@ -95,27 +95,127 @@ var StatusBar = React.memo(function StatusBar2({ sessionName, model, tokenUsage
95
95
  });
96
96
 
97
97
  // src/components/InputPrompt.tsx
98
- import React4, { useState, useMemo, useEffect } from "react";
99
- import { Box as Box4, Text as Text4, useInput } from "ink";
100
- import TextInput from "ink-text-input";
98
+ import React5, { useState as useState2, useMemo, useEffect } from "react";
99
+ import { Box as Box4, Text as Text5, useInput as useInput2 } from "ink";
100
+
101
+ // src/components/CustomTextInput.tsx
102
+ import React2, { useState } from "react";
103
+ import { Text as Text2, useInput } from "ink";
104
+ function CustomTextInput({
105
+ value,
106
+ onChange,
107
+ onSubmit,
108
+ placeholder = "",
109
+ showCursor = true
110
+ }) {
111
+ const [cursorOffset, setCursorOffset] = useState(value.length);
112
+ useInput(
113
+ (input, key) => {
114
+ if (key.return && !key.meta && !key.shift) {
115
+ onSubmit(value);
116
+ return;
117
+ }
118
+ if (key.ctrl) {
119
+ switch (input) {
120
+ case "u":
121
+ {
122
+ const lines = value.split("\n");
123
+ let currentLineStart = 0;
124
+ let currentLineIndex = 0;
125
+ let charCount = 0;
126
+ for (let i = 0; i < lines.length; i++) {
127
+ const lineLength = lines[i].length;
128
+ if (charCount + lineLength >= cursorOffset) {
129
+ currentLineIndex = i;
130
+ currentLineStart = charCount;
131
+ break;
132
+ }
133
+ charCount += lineLength + 1;
134
+ }
135
+ lines.splice(currentLineIndex, 1);
136
+ const newValue = lines.join("\n");
137
+ onChange(newValue);
138
+ setCursorOffset(Math.min(currentLineStart, newValue.length));
139
+ }
140
+ return;
141
+ case "k":
142
+ onChange(value.slice(0, cursorOffset));
143
+ return;
144
+ case "w":
145
+ {
146
+ const beforeCursor2 = value.slice(0, cursorOffset);
147
+ const afterCursor2 = value.slice(cursorOffset);
148
+ const trimmed = beforeCursor2.trimEnd();
149
+ const lastSpace = trimmed.lastIndexOf(" ");
150
+ const newBefore = lastSpace === -1 ? "" : trimmed.slice(0, lastSpace + 1);
151
+ const newValue = newBefore + afterCursor2;
152
+ onChange(newValue);
153
+ setCursorOffset(newBefore.length);
154
+ }
155
+ return;
156
+ case "a":
157
+ setCursorOffset(0);
158
+ return;
159
+ case "e":
160
+ setCursorOffset(value.length);
161
+ return;
162
+ case "l":
163
+ onChange("");
164
+ return;
165
+ }
166
+ }
167
+ if (key.backspace || key.delete) {
168
+ if (cursorOffset > 0) {
169
+ const newValue = value.slice(0, cursorOffset - 1) + value.slice(cursorOffset);
170
+ onChange(newValue);
171
+ setCursorOffset(cursorOffset - 1);
172
+ }
173
+ return;
174
+ }
175
+ if (key.leftArrow) {
176
+ setCursorOffset(Math.max(0, cursorOffset - 1));
177
+ return;
178
+ }
179
+ if (key.rightArrow) {
180
+ setCursorOffset(Math.min(value.length, cursorOffset + 1));
181
+ return;
182
+ }
183
+ if (!key.ctrl && !key.meta && input.length === 1) {
184
+ const sanitizedInput = input === "\r" ? "\n" : input;
185
+ const newValue = value.slice(0, cursorOffset) + sanitizedInput + value.slice(cursorOffset);
186
+ onChange(newValue);
187
+ setCursorOffset(cursorOffset + 1);
188
+ }
189
+ },
190
+ { isActive: true }
191
+ );
192
+ const hasValue = value.length > 0;
193
+ if (!hasValue) {
194
+ return /* @__PURE__ */ React2.createElement(Text2, null, showCursor ? /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(Text2, { inverse: true }, " "), /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, placeholder)) : /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, placeholder));
195
+ }
196
+ const beforeCursor = value.slice(0, cursorOffset);
197
+ const cursorChar = value[cursorOffset] || " ";
198
+ const afterCursor = value.slice(cursorOffset + 1);
199
+ return /* @__PURE__ */ React2.createElement(Text2, null, beforeCursor, showCursor && /* @__PURE__ */ React2.createElement(Text2, { inverse: true }, cursorChar), !showCursor && cursorChar, afterCursor);
200
+ }
101
201
 
102
202
  // src/components/CommandAutocomplete.tsx
103
- import React2 from "react";
104
- import { Box as Box2, Text as Text2 } from "ink";
203
+ import React3 from "react";
204
+ import { Box as Box2, Text as Text3 } from "ink";
105
205
  function CommandAutocomplete({ commands, selectedIndex }) {
106
206
  if (commands.length === 0) {
107
- return /* @__PURE__ */ React2.createElement(Box2, { marginLeft: 2, marginTop: 1 }, /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, "No matching commands"));
207
+ return /* @__PURE__ */ React3.createElement(Box2, { marginLeft: 2, marginTop: 1 }, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, "No matching commands"));
108
208
  }
109
- return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", marginLeft: 2, marginTop: 1 }, /* @__PURE__ */ React2.createElement(Box2, { marginBottom: 1 }, /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, commands.length === 1 ? "1 command" : `${commands.length} commands`, " \u2022 Use \u2191\u2193 to navigate, Enter to select")), commands.map((cmd, index) => {
209
+ return /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column", marginLeft: 2, marginTop: 1 }, /* @__PURE__ */ React3.createElement(Box2, { marginBottom: 1 }, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, commands.length === 1 ? "1 command" : `${commands.length} commands`, " \u2022 Use \u2191\u2193 to navigate, Enter to select")), commands.map((cmd, index) => {
110
210
  const args = cmd.args ? ` ${cmd.args}` : "";
111
211
  const isSelected = index === selectedIndex;
112
- return /* @__PURE__ */ React2.createElement(Box2, { key: cmd.name, marginLeft: 1 }, /* @__PURE__ */ React2.createElement(Text2, { color: isSelected ? "cyan" : void 0, bold: isSelected }, isSelected ? "\u25B8 " : " ", "/", cmd.name, args, " - ", cmd.description));
212
+ return /* @__PURE__ */ React3.createElement(Box2, { key: cmd.name, marginLeft: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: isSelected ? "cyan" : void 0, bold: isSelected }, isSelected ? "\u25B8 " : " ", "/", cmd.name, args, " - ", cmd.description));
113
213
  }));
114
214
  }
115
215
 
116
216
  // src/components/FileAutocomplete.tsx
117
- import React3 from "react";
118
- import { Box as Box3, Text as Text3 } from "ink";
217
+ import React4 from "react";
218
+ import { Box as Box3, Text as Text4 } from "ink";
119
219
 
120
220
  // src/utils/fileSearch.ts
121
221
  import * as fs from "fs";
@@ -304,14 +404,14 @@ var MAX_FILE_SIZE = 10 * 1024 * 1024;
304
404
  // src/components/FileAutocomplete.tsx
305
405
  function FileAutocomplete({ files, selectedIndex, query }) {
306
406
  if (files.length === 0) {
307
- return /* @__PURE__ */ React3.createElement(Box3, { marginLeft: 2, marginTop: 1 }, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, "No matching files", query ? ` for "${query}"` : ""));
407
+ return /* @__PURE__ */ React4.createElement(Box3, { marginLeft: 2, marginTop: 1 }, /* @__PURE__ */ React4.createElement(Text4, { dimColor: true }, "No matching files", query ? ` for "${query}"` : ""));
308
408
  }
309
- return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", marginLeft: 2, marginTop: 1 }, /* @__PURE__ */ React3.createElement(Box3, { marginBottom: 1 }, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, files.length === 1 ? "1 match" : `${files.length} matches`, " - Use up/down to navigate, Tab to select")), files.map((file, index) => {
409
+ return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", marginLeft: 2, marginTop: 1 }, /* @__PURE__ */ React4.createElement(Box3, { marginBottom: 1 }, /* @__PURE__ */ React4.createElement(Text4, { dimColor: true }, files.length === 1 ? "1 match" : `${files.length} matches`, " - Use up/down to navigate, Tab to select")), files.map((file, index) => {
310
410
  const isSelected = index === selectedIndex;
311
411
  const icon = file.isDirectory ? "[folder]" : "[file] ";
312
412
  const sizeDisplay = file.isDirectory ? "" : file.size !== void 0 ? ` (${formatFileSize(file.size)})` : "";
313
413
  const pathDisplay = file.isDirectory ? `${file.path}/` : file.path;
314
- return /* @__PURE__ */ React3.createElement(Box3, { key: file.path, marginLeft: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: isSelected ? "cyan" : void 0, bold: isSelected }, isSelected ? "> " : " "), /* @__PURE__ */ React3.createElement(Text3, { color: file.isDirectory ? "yellow" : isSelected ? "cyan" : void 0, bold: isSelected }, icon), /* @__PURE__ */ React3.createElement(Text3, { color: isSelected ? "cyan" : void 0, bold: isSelected }, " ", pathDisplay), /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, sizeDisplay));
414
+ return /* @__PURE__ */ React4.createElement(Box3, { key: file.path, marginLeft: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: isSelected ? "cyan" : void 0, bold: isSelected }, isSelected ? "> " : " "), /* @__PURE__ */ React4.createElement(Text4, { color: file.isDirectory ? "yellow" : isSelected ? "cyan" : void 0, bold: isSelected }, icon), /* @__PURE__ */ React4.createElement(Text4, { color: isSelected ? "cyan" : void 0, bold: isSelected }, " ", pathDisplay), /* @__PURE__ */ React4.createElement(Text4, { dimColor: true }, sizeDisplay));
315
415
  }));
316
416
  }
317
417
 
@@ -638,11 +738,11 @@ function InputPrompt({
638
738
  prefillInput,
639
739
  onPrefillConsumed
640
740
  }) {
641
- const [value, setValue] = useState("");
642
- const [selectedIndex, setSelectedIndex] = useState(0);
643
- const [historyIndex, setHistoryIndex] = useState(-1);
644
- const [tempInput, setTempInput] = useState("");
645
- const [inputKey, setInputKey] = useState(0);
741
+ const [value, setValue] = useState2("");
742
+ const [selectedIndex, setSelectedIndex] = useState2(0);
743
+ const [historyIndex, setHistoryIndex] = useState2(-1);
744
+ const [tempInput, setTempInput] = useState2("");
745
+ const [inputKey, setInputKey] = useState2(0);
646
746
  useEffect(() => {
647
747
  if (prefillInput) {
648
748
  setValue(prefillInput);
@@ -650,8 +750,8 @@ function InputPrompt({
650
750
  onPrefillConsumed?.();
651
751
  }
652
752
  }, [prefillInput, onPrefillConsumed]);
653
- const [fileAutocomplete, setFileAutocomplete] = useState(null);
654
- const [fileSelectedIndex, setFileSelectedIndex] = useState(0);
753
+ const [fileAutocomplete, setFileAutocomplete] = useState2(null);
754
+ const [fileSelectedIndex, setFileSelectedIndex] = useState2(0);
655
755
  const shouldShowCommandAutocomplete = value.startsWith("/") && !disabled && !fileAutocomplete?.active;
656
756
  const commandQuery = shouldShowCommandAutocomplete ? value.slice(1) : "";
657
757
  const filteredCommands = useMemo(() => {
@@ -668,7 +768,7 @@ function InputPrompt({
668
768
  useEffect(() => {
669
769
  setFileSelectedIndex(0);
670
770
  }, [filteredFiles]);
671
- useInput((input, key) => {
771
+ useInput2((_input, key) => {
672
772
  if (fileAutocomplete?.active && filteredFiles.length > 0) {
673
773
  if (key.upArrow) {
674
774
  setFileSelectedIndex((prev) => prev > 0 ? prev - 1 : filteredFiles.length - 1);
@@ -725,7 +825,6 @@ function InputPrompt({
725
825
  const pathToInsert = file.isDirectory ? `@${file.path}/` : `@${file.path}`;
726
826
  const newValue = beforeAt + pathToInsert + afterQuery;
727
827
  setValue(newValue);
728
- setInputKey((prev) => prev + 1);
729
828
  if (file.isDirectory) {
730
829
  setFileAutocomplete({
731
830
  active: true,
@@ -752,7 +851,6 @@ function InputPrompt({
752
851
  if (selectedCommand.args) {
753
852
  setValue(commandText + " ");
754
853
  setHistoryIndex(-1);
755
- setInputKey((prev) => prev + 1);
756
854
  return;
757
855
  }
758
856
  setValue("");
@@ -771,7 +869,6 @@ function InputPrompt({
771
869
  if (imageEvent && onImageDetected) {
772
870
  const placeholder = await onImageDetected(imageEvent.data);
773
871
  setValue(`${placeholder} `);
774
- setInputKey((prev) => prev + 1);
775
872
  return;
776
873
  }
777
874
  }
@@ -791,29 +888,29 @@ function InputPrompt({
791
888
  setFileAutocomplete(null);
792
889
  }
793
890
  };
794
- return /* @__PURE__ */ React4.createElement(Box4, { flexDirection: "column" }, /* @__PURE__ */ React4.createElement(Box4, null, /* @__PURE__ */ React4.createElement(Text4, { bold: true, color: "cyan" }, "> "), /* @__PURE__ */ React4.createElement(
795
- TextInput,
891
+ return /* @__PURE__ */ React5.createElement(Box4, { flexDirection: "column" }, /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(Text5, { bold: true, color: "cyan" }, "> "), /* @__PURE__ */ React5.createElement(
892
+ CustomTextInput,
796
893
  {
797
894
  key: inputKey,
798
895
  value,
799
896
  onChange: handleChange,
800
897
  onSubmit: handleSubmit,
801
- placeholder: disabled ? "" : "Type your message, /help for commands, or @file to reference",
898
+ placeholder: disabled ? "Thinking..." : "Type your message, /help for commands, or @file to reference",
802
899
  showCursor: !disabled
803
900
  }
804
- )), shouldShowCommandAutocomplete && /* @__PURE__ */ React4.createElement(CommandAutocomplete, { commands: filteredCommands, selectedIndex }), fileAutocomplete?.active && /* @__PURE__ */ React4.createElement(FileAutocomplete, { files: filteredFiles, selectedIndex: fileSelectedIndex, query: fileAutocomplete.query }));
901
+ )), shouldShowCommandAutocomplete && /* @__PURE__ */ React5.createElement(CommandAutocomplete, { commands: filteredCommands, selectedIndex }), fileAutocomplete?.active && /* @__PURE__ */ React5.createElement(FileAutocomplete, { files: filteredFiles, selectedIndex: fileSelectedIndex, query: fileAutocomplete.query }));
805
902
  }
806
903
 
807
904
  // src/components/AgentThinking.tsx
808
- import React6 from "react";
905
+ import React7 from "react";
809
906
  import { Box as Box6 } from "ink";
810
907
 
811
908
  // src/components/ThoughtStream.tsx
812
- import React5 from "react";
813
- import { Box as Box5, Text as Text5 } from "ink";
909
+ import React6 from "react";
910
+ import { Box as Box5, Text as Text6 } from "ink";
814
911
  import Spinner from "ink-spinner";
815
- var ThoughtStream = React5.memo(function ThoughtStream2({ steps }) {
816
- return /* @__PURE__ */ React5.createElement(Box5, { flexDirection: "column", gap: 1 }, steps.map((step, index) => /* @__PURE__ */ React5.createElement(Box5, { key: index, flexDirection: "column" }, step.type === "thought" && /* @__PURE__ */ React5.createElement(Box5, null, /* @__PURE__ */ React5.createElement(Text5, { color: "magenta" }, "\u{1F914} Thought: "), /* @__PURE__ */ React5.createElement(Text5, null, step.content)), step.type === "action" && /* @__PURE__ */ React5.createElement(Box5, { flexDirection: "column" }, /* @__PURE__ */ React5.createElement(Box5, null, /* @__PURE__ */ React5.createElement(Text5, { color: "yellow" }, "\u26A1 Action: "), /* @__PURE__ */ React5.createElement(Text5, { bold: true }, step.metadata?.toolName || "unknown")), step.metadata?.toolInput && /* @__PURE__ */ React5.createElement(Box5, { paddingLeft: 2 }, /* @__PURE__ */ React5.createElement(Text5, { dimColor: true }, JSON.stringify(step.metadata.toolInput, null, 2)))), step.type === "observation" && /* @__PURE__ */ React5.createElement(Box5, { flexDirection: "column" }, /* @__PURE__ */ React5.createElement(Box5, null, /* @__PURE__ */ React5.createElement(Text5, { color: "blue" }, "\u{1F4CA} Observation: ")), /* @__PURE__ */ React5.createElement(Box5, { paddingLeft: 2 }, /* @__PURE__ */ React5.createElement(Text5, null, step.content))), step.type === "final_answer" && /* @__PURE__ */ React5.createElement(Box5, { flexDirection: "column" }, /* @__PURE__ */ React5.createElement(Box5, null, /* @__PURE__ */ React5.createElement(Text5, { color: "green", bold: true }, "\u2705 Final Answer:", " ")), /* @__PURE__ */ React5.createElement(Box5, { paddingLeft: 2 }, /* @__PURE__ */ React5.createElement(Text5, null, step.content)), step.metadata?.tokenUsage && /* @__PURE__ */ React5.createElement(Box5, { paddingLeft: 2 }, /* @__PURE__ */ React5.createElement(Text5, { dimColor: true }, "(", step.metadata.tokenUsage.total, " tokens)"))))), !steps.some((s) => s.type === "final_answer") && /* @__PURE__ */ React5.createElement(Box5, null, /* @__PURE__ */ React5.createElement(Text5, { color: "yellow" }, /* @__PURE__ */ React5.createElement(Spinner, { type: "dots" })), /* @__PURE__ */ React5.createElement(Text5, null, " ", steps.length === 0 ? "Thinking..." : "Processing...")));
912
+ var ThoughtStream = React6.memo(function ThoughtStream2({ steps }) {
913
+ return /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column", gap: 1 }, steps.map((step, index) => /* @__PURE__ */ React6.createElement(Box5, { key: index, flexDirection: "column" }, step.type === "thought" && /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Text6, { color: "magenta" }, "\u{1F914} Thought: "), /* @__PURE__ */ React6.createElement(Text6, null, step.content)), step.type === "action" && /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, "\u26A1 Action: "), /* @__PURE__ */ React6.createElement(Text6, { bold: true }, step.metadata?.toolName || "unknown")), step.metadata?.toolInput && /* @__PURE__ */ React6.createElement(Box5, { paddingLeft: 2 }, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, JSON.stringify(step.metadata.toolInput, null, 2)))), step.type === "observation" && /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Text6, { color: "blue" }, "\u{1F4CA} Observation: ")), /* @__PURE__ */ React6.createElement(Box5, { paddingLeft: 2 }, /* @__PURE__ */ React6.createElement(Text6, null, step.content))), step.type === "final_answer" && /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Text6, { color: "green", bold: true }, "\u2705 Final Answer:", " ")), /* @__PURE__ */ React6.createElement(Box5, { paddingLeft: 2 }, /* @__PURE__ */ React6.createElement(Text6, null, step.content)), step.metadata?.tokenUsage && /* @__PURE__ */ React6.createElement(Box5, { paddingLeft: 2 }, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "(", step.metadata.tokenUsage.total, " tokens)"))))), !steps.some((s) => s.type === "final_answer") && /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, /* @__PURE__ */ React6.createElement(Spinner, { type: "dots" })), /* @__PURE__ */ React6.createElement(Text6, null, " ", steps.length === 0 ? "Thinking..." : "Processing...")));
817
914
  });
818
915
 
819
916
  // src/store/index.ts
@@ -829,7 +926,6 @@ var useCliStore = create((set) => ({
829
926
  addAgentStep: (step) => set((state) => ({
830
927
  agentSteps: [...state.agentSteps, step]
831
928
  })),
832
- setAgentSteps: (steps) => set({ agentSteps: steps }),
833
929
  clearAgentSteps: () => set({ agentSteps: [] }),
834
930
  // Permission prompt
835
931
  permissionPrompt: null,
@@ -843,32 +939,32 @@ var useCliStore = create((set) => ({
843
939
  }));
844
940
 
845
941
  // src/components/AgentThinking.tsx
846
- var AgentThinking = React6.memo(function AgentThinking2() {
942
+ var AgentThinking = React7.memo(function AgentThinking2() {
847
943
  const isThinking = useCliStore((state) => state.isThinking);
848
944
  const agentSteps = useCliStore((state) => state.agentSteps);
849
945
  if (!isThinking) {
850
946
  return null;
851
947
  }
852
- return /* @__PURE__ */ React6.createElement(Box6, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React6.createElement(ThoughtStream, { steps: agentSteps }));
948
+ return /* @__PURE__ */ React7.createElement(Box6, { borderStyle: "single", borderColor: "yellow", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React7.createElement(ThoughtStream, { steps: agentSteps }));
853
949
  });
854
950
 
855
951
  // src/components/PermissionPrompt.tsx
856
- import React7 from "react";
857
- import { Box as Box7, Text as Text6 } from "ink";
952
+ import React8 from "react";
953
+ import { Box as Box7, Text as Text7 } from "ink";
858
954
  import SelectInput from "ink-select-input";
859
955
  function renderDiffPreview(preview) {
860
956
  const lines = preview.split("\n");
861
957
  return lines.map((line, index) => {
862
958
  if (line.startsWith("+")) {
863
- return /* @__PURE__ */ React7.createElement(Text6, { key: index, color: "green" }, line);
959
+ return /* @__PURE__ */ React8.createElement(Text7, { key: index, color: "green" }, line);
864
960
  }
865
961
  if (line.startsWith("-")) {
866
- return /* @__PURE__ */ React7.createElement(Text6, { key: index, color: "red" }, line);
962
+ return /* @__PURE__ */ React8.createElement(Text7, { key: index, color: "red" }, line);
867
963
  }
868
964
  if (line.startsWith("@@")) {
869
- return /* @__PURE__ */ React7.createElement(Text6, { key: index, color: "cyan" }, line);
965
+ return /* @__PURE__ */ React8.createElement(Text7, { key: index, color: "cyan" }, line);
870
966
  }
871
- return /* @__PURE__ */ React7.createElement(Text6, { key: index, dimColor: true }, line);
967
+ return /* @__PURE__ */ React8.createElement(Text7, { key: index, dimColor: true }, line);
872
968
  });
873
969
  }
874
970
  function PermissionPrompt({
@@ -888,12 +984,12 @@ function PermissionPrompt({
888
984
  { label: "\u2717 Deny", value: "deny" }
889
985
  ];
890
986
  const argsString = typeof args === "string" ? args : JSON.stringify(args, null, 2);
891
- return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", borderStyle: "bold", borderColor: "yellow", padding: 1, marginY: 1 }, /* @__PURE__ */ React7.createElement(Box7, null, /* @__PURE__ */ React7.createElement(Text6, { bold: true, color: "yellow" }, "\u26A0\uFE0F Permission Required")), /* @__PURE__ */ React7.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React7.createElement(Text6, { dimColor: true }, "Tool: "), /* @__PURE__ */ React7.createElement(Text6, { bold: true, color: "cyan" }, toolName)), toolDescription && /* @__PURE__ */ React7.createElement(Box7, null, /* @__PURE__ */ React7.createElement(Text6, { dimColor: true }, "Action: "), /* @__PURE__ */ React7.createElement(Text6, null, toolDescription)), /* @__PURE__ */ React7.createElement(Box7, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React7.createElement(Text6, { bold: true }, "Arguments:"), /* @__PURE__ */ React7.createElement(Box7, { paddingLeft: 2, flexDirection: "column" }, /* @__PURE__ */ React7.createElement(Text6, { dimColor: true }, argsString))), preview && /* @__PURE__ */ React7.createElement(Box7, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React7.createElement(Text6, { bold: true }, "Preview:"), /* @__PURE__ */ React7.createElement(Box7, { borderStyle: "single", borderColor: "gray", paddingX: 1, flexDirection: "column" }, renderDiffPreview(preview))), !canBeTrusted && /* @__PURE__ */ React7.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React7.createElement(Text6, { color: "red", dimColor: true }, "Note: This tool cannot be trusted due to its dangerous nature.")), /* @__PURE__ */ React7.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React7.createElement(SelectInput, { items, onSelect: (item) => onResponse(item.value) })));
987
+ return /* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column", borderStyle: "bold", borderColor: "yellow", padding: 1, marginY: 1 }, /* @__PURE__ */ React8.createElement(Box7, null, /* @__PURE__ */ React8.createElement(Text7, { bold: true, color: "yellow" }, "\u26A0\uFE0F Permission Required")), /* @__PURE__ */ React8.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, "Tool: "), /* @__PURE__ */ React8.createElement(Text7, { bold: true, color: "cyan" }, toolName)), toolDescription && /* @__PURE__ */ React8.createElement(Box7, null, /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, "Action: "), /* @__PURE__ */ React8.createElement(Text7, null, toolDescription)), /* @__PURE__ */ React8.createElement(Box7, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React8.createElement(Text7, { bold: true }, "Arguments:"), /* @__PURE__ */ React8.createElement(Box7, { paddingLeft: 2, flexDirection: "column" }, /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, argsString))), preview && /* @__PURE__ */ React8.createElement(Box7, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React8.createElement(Text7, { bold: true }, "Preview:"), /* @__PURE__ */ React8.createElement(Box7, { borderStyle: "single", borderColor: "gray", paddingX: 1, flexDirection: "column" }, renderDiffPreview(preview))), !canBeTrusted && /* @__PURE__ */ React8.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text7, { color: "red", dimColor: true }, "Note: This tool cannot be trusted due to its dangerous nature.")), /* @__PURE__ */ React8.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(SelectInput, { items, onSelect: (item) => onResponse(item.value) })));
892
988
  }
893
989
 
894
990
  // src/components/ConfigEditor.tsx
895
- import React8, { useState as useState2, useMemo as useMemo2 } from "react";
896
- import { Box as Box8, Text as Text7, useInput as useInput2 } from "ink";
991
+ import React9, { useState as useState3, useMemo as useMemo2 } from "react";
992
+ import { Box as Box8, Text as Text8, useInput as useInput3 } from "ink";
897
993
  var MAX_ITERATIONS_OPTIONS = [
898
994
  { label: "10", value: 10 },
899
995
  { label: "20", value: 20 },
@@ -1024,10 +1120,10 @@ function buildConfigItems(availableModels) {
1024
1120
  return items;
1025
1121
  }
1026
1122
  function ConfigEditor({ config, availableModels, onSave, onClose }) {
1027
- const [selectedIndex, setSelectedIndex] = useState2(0);
1028
- const [editedConfig, setEditedConfig] = useState2(config);
1029
- const [saveError, setSaveError] = useState2(null);
1030
- const [isSaving, setIsSaving] = useState2(false);
1123
+ const [selectedIndex, setSelectedIndex] = useState3(0);
1124
+ const [editedConfig, setEditedConfig] = useState3(config);
1125
+ const [saveError, setSaveError] = useState3(null);
1126
+ const [isSaving, setIsSaving] = useState3(false);
1031
1127
  const configItems = useMemo2(() => buildConfigItems(availableModels), [availableModels]);
1032
1128
  const hasChanges = useMemo2(() => {
1033
1129
  return JSON.stringify(config.preferences) !== JSON.stringify(editedConfig.preferences) || config.defaultModel !== editedConfig.defaultModel;
@@ -1047,7 +1143,7 @@ function ConfigEditor({ config, availableModels, onSave, onClose }) {
1047
1143
  }
1048
1144
  onClose();
1049
1145
  };
1050
- useInput2((input, key) => {
1146
+ useInput3((input, key) => {
1051
1147
  const currentItem = configItems[selectedIndex];
1052
1148
  if (key.upArrow) {
1053
1149
  setSelectedIndex((prev) => prev > 0 ? prev - 1 : configItems.length - 1);
@@ -1112,13 +1208,13 @@ function ConfigEditor({ config, availableModels, onSave, onClose }) {
1112
1208
  }
1113
1209
  return String(value);
1114
1210
  };
1115
- return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, marginY: 1 }, /* @__PURE__ */ React8.createElement(Box8, { justifyContent: "space-between", marginBottom: 1 }, /* @__PURE__ */ React8.createElement(Text7, { bold: true, color: "cyan" }, "Settings"), isSaving ? /* @__PURE__ */ React8.createElement(Text7, { color: "yellow" }, "Saving...") : hasChanges ? /* @__PURE__ */ React8.createElement(Text7, { dimColor: true, color: "yellow" }, "(unsaved changes)") : null), saveError && /* @__PURE__ */ React8.createElement(Box8, { marginBottom: 1 }, /* @__PURE__ */ React8.createElement(Text7, { color: "red" }, "Error: ", saveError)), /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", marginBottom: 1 }, configItems.map((item, index) => {
1211
+ return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, marginY: 1 }, /* @__PURE__ */ React9.createElement(Box8, { justifyContent: "space-between", marginBottom: 1 }, /* @__PURE__ */ React9.createElement(Text8, { bold: true, color: "cyan" }, "Settings"), isSaving ? /* @__PURE__ */ React9.createElement(Text8, { color: "yellow" }, "Saving...") : hasChanges ? /* @__PURE__ */ React9.createElement(Text8, { dimColor: true, color: "yellow" }, "(unsaved changes)") : null), saveError && /* @__PURE__ */ React9.createElement(Box8, { marginBottom: 1 }, /* @__PURE__ */ React9.createElement(Text8, { color: "red" }, "Error: ", saveError)), /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", marginBottom: 1 }, configItems.map((item, index) => {
1116
1212
  const isSelected = index === selectedIndex;
1117
1213
  const value = item.getValue(editedConfig);
1118
1214
  const displayValue = formatValue(item, value);
1119
1215
  const hasOptions = item.type === "select" || item.type === "boolean" || item.type === "number";
1120
- return /* @__PURE__ */ React8.createElement(Box8, { key: item.key }, /* @__PURE__ */ React8.createElement(Text7, { color: isSelected ? "cyan" : void 0 }, isSelected ? "> " : " "), /* @__PURE__ */ React8.createElement(Box8, { width: 18 }, /* @__PURE__ */ React8.createElement(Text7, { bold: isSelected, color: isSelected ? "white" : "gray" }, item.label, ":")), /* @__PURE__ */ React8.createElement(Box8, null, hasOptions && isSelected && /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, "< "), /* @__PURE__ */ React8.createElement(Text7, { bold: isSelected, color: isSelected ? "green" : void 0 }, displayValue), hasOptions && isSelected && /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, " >")));
1121
- })), /* @__PURE__ */ React8.createElement(Box8, { borderStyle: "single", borderColor: "gray", paddingX: 1 }, /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, "\u2191/\u2193: Navigate | Space/\u2190/\u2192: Change | q/Esc: Save & Exit")));
1216
+ return /* @__PURE__ */ React9.createElement(Box8, { key: item.key }, /* @__PURE__ */ React9.createElement(Text8, { color: isSelected ? "cyan" : void 0 }, isSelected ? "> " : " "), /* @__PURE__ */ React9.createElement(Box8, { width: 18 }, /* @__PURE__ */ React9.createElement(Text8, { bold: isSelected, color: isSelected ? "white" : "gray" }, item.label, ":")), /* @__PURE__ */ React9.createElement(Box8, null, hasOptions && isSelected && /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, "< "), /* @__PURE__ */ React9.createElement(Text8, { bold: isSelected, color: isSelected ? "green" : void 0 }, displayValue), hasOptions && isSelected && /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, " >")));
1217
+ })), /* @__PURE__ */ React9.createElement(Box8, { borderStyle: "single", borderColor: "gray", paddingX: 1 }, /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, "\u2191/\u2193: Navigate | Space/\u2190/\u2192: Change | q/Esc: Save & Exit")));
1122
1218
  }
1123
1219
 
1124
1220
  // src/utils/processFileReferences.ts
@@ -1258,7 +1354,7 @@ function App({
1258
1354
  const setShowConfigEditor = useCliStore((state) => state.setShowConfigEditor);
1259
1355
  const exitRequested = useCliStore((state) => state.exitRequested);
1260
1356
  const setIsThinking = useCliStore((state) => state.setIsThinking);
1261
- const handleSubmit = React9.useCallback(
1357
+ const handleSubmit = React10.useCallback(
1262
1358
  async (input) => {
1263
1359
  const trimmed = input.trim();
1264
1360
  if (!trimmed) return;
@@ -1287,7 +1383,7 @@ ${errorBlock}`;
1287
1383
  },
1288
1384
  [onMessage, onCommand, setIsThinking]
1289
1385
  );
1290
- return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column" }, /* @__PURE__ */ React9.createElement(StatusBar, { sessionName, model: currentModel, tokenUsage: totalTokens }), showConfigEditor && config && onSaveConfig ? /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React9.createElement(
1386
+ return /* @__PURE__ */ React10.createElement(Box9, { flexDirection: "column" }, /* @__PURE__ */ React10.createElement(StatusBar, { sessionName, model: currentModel, tokenUsage: totalTokens }), showConfigEditor && config && onSaveConfig ? /* @__PURE__ */ React10.createElement(Box9, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React10.createElement(
1291
1387
  ConfigEditor,
1292
1388
  {
1293
1389
  config,
@@ -1295,7 +1391,7 @@ ${errorBlock}`;
1295
1391
  onSave: onSaveConfig,
1296
1392
  onClose: () => setShowConfigEditor(false)
1297
1393
  }
1298
- )) : permissionPrompt ? /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React9.createElement(
1394
+ )) : permissionPrompt ? /* @__PURE__ */ React10.createElement(Box9, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React10.createElement(
1299
1395
  PermissionPrompt,
1300
1396
  {
1301
1397
  toolName: permissionPrompt.toolName,
@@ -1304,7 +1400,7 @@ ${errorBlock}`;
1304
1400
  canBeTrusted: permissionPrompt.canBeTrusted,
1305
1401
  onResponse: onPermissionResponse
1306
1402
  }
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(
1403
+ )) : /* @__PURE__ */ React10.createElement(React10.Fragment, null, /* @__PURE__ */ React10.createElement(Static, { items: messages }, (message, index) => /* @__PURE__ */ React10.createElement(Box9, { key: index, flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React10.createElement(MessageItem, { message }))), /* @__PURE__ */ React10.createElement(AgentThinking, null), exitRequested && /* @__PURE__ */ React10.createElement(Box9, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React10.createElement(Text9, { color: "yellow", bold: true }, "Press Ctrl+C again to exit")), /* @__PURE__ */ React10.createElement(Box9, { borderStyle: "single", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React10.createElement(
1308
1404
  InputPrompt,
1309
1405
  {
1310
1406
  onSubmit: handleSubmit,
@@ -1317,37 +1413,36 @@ ${errorBlock}`;
1317
1413
  ))));
1318
1414
  }
1319
1415
  function MessageItem({ message }) {
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) => {
1416
+ return /* @__PURE__ */ React10.createElement(Box9, { flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React10.createElement(Box9, null, /* @__PURE__ */ React10.createElement(Text9, { bold: true, color: message.role === "user" ? "cyan" : "green" }, message.role === "user" ? "\u{1F464} You" : "\u{1F916} Assistant"), /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, " \u2022 ", new Date(message.timestamp).toLocaleTimeString())), /* @__PURE__ */ React10.createElement(Box9, { paddingLeft: 2 }, message.metadata?.permissionDenied ? /* @__PURE__ */ React10.createElement(Text9, { color: "yellow" }, "\u26A0\uFE0F ", message.content) : /* @__PURE__ */ React10.createElement(Text9, null, message.content)), message.metadata?.steps && message.metadata.steps.length > 0 && /* @__PURE__ */ React10.createElement(Box9, { paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Text9, { 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__ */ React10.createElement(Text9, { dimColor: true }, "Step types: ", message.metadata.steps.map((s) => s.type).join(", ")), message.metadata.steps.map((step, idx) => {
1322
1417
  if (step.type === "thought") {
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 ? "..." : ""}`));
1418
+ return /* @__PURE__ */ React10.createElement(Box9, { key: idx, paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Text9, { color: "blue" }, "\u{1F4AD} Thought:"), /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, ` ${step.content.slice(0, 200)}${step.content.length > 200 ? "..." : ""}`));
1324
1419
  }
1325
1420
  if (step.type === "action") {
1326
1421
  const toolName = step.metadata?.toolName || "unknown";
1327
1422
  const toolInput = step.metadata?.toolInput;
1328
1423
  const observationStep = message.metadata.steps[idx + 1];
1329
1424
  const result = observationStep?.type === "observation" ? observationStep.content : null;
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 ? "..." : ""}`));
1425
+ return /* @__PURE__ */ React10.createElement(Box9, { key: idx, paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Text9, { color: "yellow" }, "\u{1F527} Action: ", toolName), toolInput && /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, ` Input: ${typeof toolInput === "string" ? toolInput : JSON.stringify(toolInput).slice(0, 100)}`), result && /* @__PURE__ */ React10.createElement(Text9, { 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 ? "..." : ""}`));
1331
1426
  }
1332
1427
  return null;
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`)));
1428
+ }).filter(Boolean)), message.metadata?.tokenUsage && (!message.metadata.steps || message.metadata.steps.length === 0) && /* @__PURE__ */ React10.createElement(Box9, { paddingLeft: 2 }, /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, `${message.metadata.tokenUsage.total} tokens`)));
1334
1429
  }
1335
1430
 
1336
1431
  // src/components/MessageList.tsx
1337
- import React10 from "react";
1338
- import { Box as Box10, Text as Text9 } from "ink";
1432
+ import React11 from "react";
1433
+ import { Box as Box10, Text as Text10 } from "ink";
1339
1434
  function stripThinkingTags(content) {
1340
1435
  return content.replace(/<think>[\s\S]*?<\/think>/g, "").trim();
1341
1436
  }
1342
- var MessageList = React10.memo(
1437
+ var MessageList = React11.memo(
1343
1438
  function MessageList2({ messages }) {
1344
1439
  if (messages.length === 0) {
1345
- return /* @__PURE__ */ React10.createElement(Box10, { paddingY: 1 }, /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, "No messages yet. Type a message to start!"));
1440
+ return /* @__PURE__ */ React11.createElement(Box10, { paddingY: 1 }, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, "No messages yet. Type a message to start!"));
1346
1441
  }
1347
- return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", gap: 1, paddingY: 1 }, messages.map((message, index) => /* @__PURE__ */ React10.createElement(Box10, { key: index, flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Text9, { bold: true, color: message.role === "user" ? "cyan" : "green" }, message.role === "user" ? "\u{1F464} You" : "\u{1F916} Assistant"), /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, " \u2022 ", new Date(message.timestamp).toLocaleTimeString())), /* @__PURE__ */ React10.createElement(Box10, { paddingLeft: 2 }, message.metadata?.permissionDenied ? /* @__PURE__ */ React10.createElement(Text9, { color: "yellow" }, "\u26A0\uFE0F ", stripThinkingTags(message.content)) : /* @__PURE__ */ React10.createElement(Text9, null, stripThinkingTags(message.content))), message.metadata?.steps && message.metadata.steps.length > 0 && /* @__PURE__ */ React10.createElement(Box10, { paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Text9, { 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__ */ React10.createElement(Text9, { dimColor: true }, "Step types: ", message.metadata.steps.map((s) => s.type).join(", ")), message.metadata.steps.map((step, idx) => {
1442
+ return /* @__PURE__ */ React11.createElement(Box10, { flexDirection: "column", gap: 1, paddingY: 1 }, messages.map((message, index) => /* @__PURE__ */ React11.createElement(Box10, { key: index, flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React11.createElement(Box10, null, /* @__PURE__ */ React11.createElement(Text10, { bold: true, color: message.role === "user" ? "cyan" : "green" }, message.role === "user" ? "\u{1F464} You" : "\u{1F916} Assistant"), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " \u2022 ", new Date(message.timestamp).toLocaleTimeString())), /* @__PURE__ */ React11.createElement(Box10, { paddingLeft: 2 }, message.metadata?.permissionDenied ? /* @__PURE__ */ React11.createElement(Text10, { color: "yellow" }, "\u26A0\uFE0F ", stripThinkingTags(message.content)) : /* @__PURE__ */ React11.createElement(Text10, null, stripThinkingTags(message.content))), message.metadata?.steps && message.metadata.steps.length > 0 && /* @__PURE__ */ React11.createElement(Box10, { paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React11.createElement(Text10, { 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__ */ React11.createElement(Text10, { dimColor: true }, "Step types: ", message.metadata.steps.map((s) => s.type).join(", ")), message.metadata.steps.map((step, idx) => {
1348
1443
  if (step.type === "thought") {
1349
- return /* @__PURE__ */ React10.createElement(Box10, { key: idx, paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Text9, { color: "blue" }, "\u{1F4AD} Thought:"), /* @__PURE__ */ React10.createElement(
1350
- Text9,
1444
+ return /* @__PURE__ */ React11.createElement(Box10, { key: idx, paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React11.createElement(Text10, { color: "blue" }, "\u{1F4AD} Thought:"), /* @__PURE__ */ React11.createElement(
1445
+ Text10,
1351
1446
  {
1352
1447
  dimColor: true
1353
1448
  },
@@ -1359,10 +1454,10 @@ var MessageList = React10.memo(
1359
1454
  const toolInput = step.metadata?.toolInput;
1360
1455
  const observationStep = message.metadata.steps[idx + 1];
1361
1456
  const result = observationStep?.type === "observation" ? observationStep.content : null;
1362
- return /* @__PURE__ */ React10.createElement(Box10, { key: idx, paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Text9, { color: "yellow" }, "\u{1F527} Action: ", toolName), toolInput && /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, ` Input: ${typeof toolInput === "string" ? toolInput : JSON.stringify(toolInput).slice(0, 100)}`), result && /* @__PURE__ */ React10.createElement(Text9, { 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 ? "..." : ""}`));
1457
+ return /* @__PURE__ */ React11.createElement(Box10, { key: idx, paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React11.createElement(Text10, { color: "yellow" }, "\u{1F527} Action: ", toolName), toolInput && /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, ` Input: ${typeof toolInput === "string" ? toolInput : JSON.stringify(toolInput).slice(0, 100)}`), result && /* @__PURE__ */ React11.createElement(Text10, { 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 ? "..." : ""}`));
1363
1458
  }
1364
1459
  return null;
1365
- }).filter(Boolean)), message.metadata?.tokenUsage && (!message.metadata.steps || message.metadata.steps.length === 0) && /* @__PURE__ */ React10.createElement(Box10, { paddingLeft: 2 }, /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, `${message.metadata.tokenUsage.total} tokens`)))));
1460
+ }).filter(Boolean)), message.metadata?.tokenUsage && (!message.metadata.steps || message.metadata.steps.length === 0) && /* @__PURE__ */ React11.createElement(Box10, { paddingLeft: 2 }, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, `${message.metadata.tokenUsage.total} tokens`)))));
1366
1461
  },
1367
1462
  (prevProps, nextProps) => {
1368
1463
  if (prevProps.messages.length !== nextProps.messages.length) {
@@ -1373,8 +1468,8 @@ var MessageList = React10.memo(
1373
1468
  );
1374
1469
 
1375
1470
  // src/components/TrustLocationSelector.tsx
1376
- import React11 from "react";
1377
- import { Box as Box11, Text as Text10 } from "ink";
1471
+ import React12 from "react";
1472
+ import { Box as Box11, Text as Text11 } from "ink";
1378
1473
  import SelectInput2 from "ink-select-input";
1379
1474
  function TrustLocationSelector({ inProject, onSelect, onCancel }) {
1380
1475
  const items = [];
@@ -1395,24 +1490,24 @@ function TrustLocationSelector({ inProject, onSelect, onCancel }) {
1395
1490
  const handleSelect = (item) => {
1396
1491
  onSelect(item.value);
1397
1492
  };
1398
- return /* @__PURE__ */ React11.createElement(Box11, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React11.createElement(Box11, { marginBottom: 1 }, /* @__PURE__ */ React11.createElement(Text10, { bold: true }, "Where should this rule be saved?")), /* @__PURE__ */ React11.createElement(
1493
+ return /* @__PURE__ */ React12.createElement(Box11, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React12.createElement(Box11, { marginBottom: 1 }, /* @__PURE__ */ React12.createElement(Text11, { bold: true }, "Where should this rule be saved?")), /* @__PURE__ */ React12.createElement(
1399
1494
  SelectInput2,
1400
1495
  {
1401
1496
  items,
1402
1497
  onSelect: handleSelect,
1403
- itemComponent: ({ isSelected, label }) => /* @__PURE__ */ React11.createElement(Box11, null, /* @__PURE__ */ React11.createElement(Text10, { color: isSelected ? "cyan" : void 0 }, isSelected ? "\u276F " : " ", label))
1498
+ itemComponent: ({ isSelected, label }) => /* @__PURE__ */ React12.createElement(Box11, null, /* @__PURE__ */ React12.createElement(Text11, { color: isSelected ? "cyan" : void 0 }, isSelected ? "\u276F " : " ", label))
1404
1499
  }
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")));
1500
+ ), /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, "Use \u2191\u2193 arrows to navigate, Enter to select, Ctrl+C to cancel")));
1406
1501
  }
1407
1502
 
1408
1503
  // 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";
1504
+ import React13, { useState as useState4 } from "react";
1505
+ import { Box as Box12, Text as Text12, useInput as useInput4 } from "ink";
1411
1506
  import SelectInput3 from "ink-select-input";
1412
1507
  function RewindSelector({ messages, onSelect, onCancel }) {
1413
- const [step, setStep] = useState3("selection");
1414
- const [selectedMessageIndex, setSelectedMessageIndex] = useState3(null);
1415
- useInput3((input, key) => {
1508
+ const [step, setStep] = useState4("selection");
1509
+ const [selectedMessageIndex, setSelectedMessageIndex] = useState4(null);
1510
+ useInput4((input, key) => {
1416
1511
  if (key.escape) {
1417
1512
  if (step === "confirmation") {
1418
1513
  setStep("selection");
@@ -1449,14 +1544,14 @@ function RewindSelector({ messages, onSelect, onCancel }) {
1449
1544
  return sum2 + (msg.metadata?.tokenUsage?.total || 0);
1450
1545
  }, 0);
1451
1546
  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(
1547
+ return /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React13.createElement(Box12, { marginBottom: 1 }, /* @__PURE__ */ React13.createElement(Text12, { bold: true }, "Select a point to rewind to:")), /* @__PURE__ */ React13.createElement(
1453
1548
  SelectInput3,
1454
1549
  {
1455
1550
  items,
1456
1551
  onSelect: handleSelectionSelect,
1457
- itemComponent: ({ isSelected, label }) => /* @__PURE__ */ React12.createElement(Box12, null, /* @__PURE__ */ React12.createElement(Text11, { color: isSelected ? "cyan" : void 0 }, isSelected ? "\u276F " : " ", label))
1552
+ itemComponent: ({ isSelected, label }) => /* @__PURE__ */ React13.createElement(Box12, null, /* @__PURE__ */ React13.createElement(Text12, { color: isSelected ? "cyan" : void 0 }, isSelected ? "\u276F " : " ", label))
1458
1553
  }
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")));
1554
+ ), /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, "Use \u2191\u2193 arrows to navigate, Enter to select, Esc to cancel")));
1460
1555
  }
1461
1556
  const confirmationItems = [
1462
1557
  { label: "Yes, rewind to this point", value: "confirm" },
@@ -1464,19 +1559,19 @@ function RewindSelector({ messages, onSelect, onCancel }) {
1464
1559
  ];
1465
1560
  const selectedMessage = selectedMessageIndex !== null && selectedMessageIndex >= 0 && selectedMessageIndex < messages.length ? messages[selectedMessageIndex] : null;
1466
1561
  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(
1562
+ return /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React13.createElement(Box12, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React13.createElement(Text12, { bold: true }, "Confirm rewind operation:"), /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, "Message: ", selectedPreview), /* @__PURE__ */ React13.createElement(Text12, { color: "yellow" }, "This will remove ", messagesToRemove.length, " message(s) (", tokensToRemove.toLocaleString(), " tokens)"), /* @__PURE__ */ React13.createElement(Text12, { color: "cyan" }, "The selected message will be placed in your input for editing.")), /* @__PURE__ */ React13.createElement(
1468
1563
  SelectInput3,
1469
1564
  {
1470
1565
  items: confirmationItems,
1471
1566
  onSelect: handleConfirmationSelect,
1472
- itemComponent: ({ isSelected, label }) => /* @__PURE__ */ React12.createElement(Box12, null, /* @__PURE__ */ React12.createElement(Text11, { color: isSelected ? "cyan" : void 0 }, isSelected ? "\u276F " : " ", label))
1567
+ itemComponent: ({ isSelected, label }) => /* @__PURE__ */ React13.createElement(Box12, null, /* @__PURE__ */ React13.createElement(Text12, { color: isSelected ? "cyan" : void 0 }, isSelected ? "\u276F " : " ", label))
1473
1568
  }
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")));
1569
+ ), /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, "Use \u2191\u2193 arrows to navigate, Enter to select, Esc to go back")));
1475
1570
  }
1476
1571
 
1477
1572
  // src/components/LoginFlow.tsx
1478
- import React13, { useState as useState4, useEffect as useEffect2 } from "react";
1479
- import { Box as Box13, Text as Text12 } from "ink";
1573
+ import React14, { useState as useState5, useEffect as useEffect2 } from "react";
1574
+ import { Box as Box13, Text as Text13 } from "ink";
1480
1575
  import Spinner2 from "ink-spinner";
1481
1576
  import jwt from "jsonwebtoken";
1482
1577
  import open from "open";
@@ -1592,10 +1687,10 @@ var OAuthClient = class {
1592
1687
 
1593
1688
  // src/components/LoginFlow.tsx
1594
1689
  function LoginFlow({ apiUrl = "http://localhost:3000", configStore, onSuccess, onError }) {
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);
1690
+ const [status, setStatus] = useState5("initiating");
1691
+ const [deviceFlow, setDeviceFlow] = useState5(null);
1692
+ const [statusMessage, setStatusMessage] = useState5("Initiating device authorization...");
1693
+ const [error, setError] = useState5(null);
1599
1694
  useEffect2(() => {
1600
1695
  const runLoginFlow = async () => {
1601
1696
  const oauth = new OAuthClient(apiUrl);
@@ -1639,15 +1734,15 @@ function LoginFlow({ apiUrl = "http://localhost:3000", configStore, onSuccess, o
1639
1734
  }
1640
1735
  }, [deviceFlow, status]);
1641
1736
  if (status === "initiating") {
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...")));
1737
+ return /* @__PURE__ */ React14.createElement(Box13, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React14.createElement(Box13, null, /* @__PURE__ */ React14.createElement(Text13, { color: "cyan" }, /* @__PURE__ */ React14.createElement(Spinner2, { type: "dots" }), " Initiating device authorization...")));
1643
1738
  }
1644
1739
  if (status === "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)));
1740
+ return /* @__PURE__ */ React14.createElement(Box13, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React14.createElement(Box13, { marginBottom: 1 }, /* @__PURE__ */ React14.createElement(Text13, { color: "red", bold: true }, "\u2716 Authentication Failed")), /* @__PURE__ */ React14.createElement(Box13, null, /* @__PURE__ */ React14.createElement(Text13, { color: "red" }, error)));
1646
1741
  }
1647
1742
  if (status === "success") {
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.")));
1743
+ return /* @__PURE__ */ React14.createElement(Box13, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React14.createElement(Box13, { marginBottom: 1 }, /* @__PURE__ */ React14.createElement(Text13, { color: "green", bold: true }, "\u2714 Successfully authenticated!")), /* @__PURE__ */ React14.createElement(Box13, null, /* @__PURE__ */ React14.createElement(Text13, { dimColor: true }, "You can now use B4M CLI with your account.")));
1649
1744
  }
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")));
1745
+ return /* @__PURE__ */ React14.createElement(Box13, { flexDirection: "column", padding: 1, borderStyle: "round", borderColor: "cyan" }, /* @__PURE__ */ React14.createElement(Box13, { marginBottom: 1 }, /* @__PURE__ */ React14.createElement(Text13, { color: "cyan", bold: true }, "\u{1F510} Device Authorization")), /* @__PURE__ */ React14.createElement(Box13, { marginBottom: 1 }, /* @__PURE__ */ React14.createElement(Text13, null, "Opening browser automatically... If it doesn't open, please visit:")), /* @__PURE__ */ React14.createElement(Box13, { marginBottom: 1, paddingLeft: 2 }, /* @__PURE__ */ React14.createElement(Text13, { color: "blue", bold: true }, deviceFlow?.verification_uri)), /* @__PURE__ */ React14.createElement(Box13, { marginBottom: 1 }, /* @__PURE__ */ React14.createElement(Text13, null, "And enter this code when prompted:")), /* @__PURE__ */ React14.createElement(Box13, { marginBottom: 1, paddingLeft: 2 }, /* @__PURE__ */ React14.createElement(Text13, { color: "yellow", bold: true }, deviceFlow?.user_code)), /* @__PURE__ */ React14.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text13, { color: "cyan" }, /* @__PURE__ */ React14.createElement(Spinner2, { type: "dots" }), " ", statusMessage)), /* @__PURE__ */ React14.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text13, { dimColor: true }, "Expires in ", deviceFlow ? Math.floor(deviceFlow.expires_in / 60) : 0, " minutes")));
1651
1746
  }
1652
1747
 
1653
1748
  // src/storage/SessionStore.ts
@@ -2533,9 +2628,10 @@ ${options.context}` : this.getSystemPrompt()
2533
2628
  content: query
2534
2629
  }
2535
2630
  ];
2631
+ console.log("[DEBUG ReActAgent] Messages array being sent to LLM:");
2536
2632
  messages.forEach((msg, i) => {
2537
2633
  const content = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
2538
- this.context.logger.debug(` [${i}] ${msg.role}: ${content.substring(0, 150)}...`);
2634
+ console.log(` [${i}] ${msg.role}: ${content.substring(0, 150)}...`);
2539
2635
  });
2540
2636
  let finalAnswer = "";
2541
2637
  let reachedMaxIterations = false;
@@ -8554,381 +8650,6 @@ var deleteFileTool = {
8554
8650
  })
8555
8651
  };
8556
8652
 
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
-
8932
8653
  // ../../b4m-core/packages/services/dist/src/llm/tools/index.js
8933
8654
  var tools = {
8934
8655
  dice_roll: diceRollTool,
@@ -8956,9 +8677,7 @@ var tools = {
8956
8677
  create_file: createFileTool,
8957
8678
  glob_files: globFilesTool,
8958
8679
  grep_search: grepSearchTool,
8959
- delete_file: deleteFileTool,
8960
- // Shell execution
8961
- bash_execute: bashExecuteTool
8680
+ delete_file: deleteFileTool
8962
8681
  };
8963
8682
  var generateTools = (userId, user, logger2, { db }, storage, imageGenerateStorage, statusUpdate, onStart, onFinish, llm, config, model) => {
8964
8683
  const context = {
@@ -9233,7 +8952,7 @@ async function generateFileDeletePreview(args) {
9233
8952
  if (!existsSync7(args.path)) {
9234
8953
  return `[File does not exist: ${args.path}]`;
9235
8954
  }
9236
- const stats = await import("fs/promises").then((fs11) => fs11.stat(args.path));
8955
+ const stats = await import("fs/promises").then((fs12) => fs12.stat(args.path));
9237
8956
  return `[File will be deleted]
9238
8957
 
9239
8958
  Path: ${args.path}
@@ -9246,7 +8965,7 @@ Last modified: ${stats.mtime.toLocaleString()}`;
9246
8965
 
9247
8966
  // src/utils/Logger.ts
9248
8967
  import fs10 from "fs/promises";
9249
- import path12 from "path";
8968
+ import path11 from "path";
9250
8969
  import os from "os";
9251
8970
  var Logger2 = class _Logger {
9252
8971
  constructor() {
@@ -9269,9 +8988,9 @@ var Logger2 = class _Logger {
9269
8988
  */
9270
8989
  async initialize(sessionId) {
9271
8990
  this.sessionId = sessionId;
9272
- const debugDir = path12.join(os.homedir(), ".bike4mind", "debug");
8991
+ const debugDir = path11.join(os.homedir(), ".bike4mind", "debug");
9273
8992
  await fs10.mkdir(debugDir, { recursive: true });
9274
- this.logFilePath = path12.join(debugDir, `${sessionId}.txt`);
8993
+ this.logFilePath = path11.join(debugDir, `${sessionId}.txt`);
9275
8994
  await this.writeToFile("INFO", "=== CLI SESSION START ===");
9276
8995
  }
9277
8996
  /**
@@ -9481,12 +9200,12 @@ var Logger2 = class _Logger {
9481
9200
  async cleanupOldLogs() {
9482
9201
  if (!this.fileLoggingEnabled) return;
9483
9202
  try {
9484
- const debugDir = path12.join(os.homedir(), ".bike4mind", "debug");
9203
+ const debugDir = path11.join(os.homedir(), ".bike4mind", "debug");
9485
9204
  const files = await fs10.readdir(debugDir);
9486
9205
  const now = Date.now();
9487
9206
  const thirtyDaysAgo = now - 30 * 24 * 60 * 60 * 1e3;
9488
9207
  for (const file of files) {
9489
- const filePath = path12.join(debugDir, file);
9208
+ const filePath = path11.join(debugDir, file);
9490
9209
  const stats = await fs10.stat(filePath);
9491
9210
  if (stats.mtime.getTime() < thirtyDaysAgo) {
9492
9211
  await fs10.unlink(filePath);
@@ -9653,10 +9372,6 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
9653
9372
  } catch (error) {
9654
9373
  preview = `[Could not generate preview: ${error instanceof Error ? error.message : "Unknown error"}]`;
9655
9374
  }
9656
- } else if (toolName === "bash_execute" && args?.command) {
9657
- const cwd = args.cwd ? ` (in ${args.cwd})` : "";
9658
- const timeout = args.timeout ? ` [timeout: ${args.timeout}ms]` : "";
9659
- preview = `$ ${args.command}${cwd}${timeout}`;
9660
9375
  }
9661
9376
  const response = await showPermissionPrompt(toolName, args, preview);
9662
9377
  if (response.action === "deny") {
@@ -9727,8 +9442,6 @@ function generateCliTools(userId, llm, model, permissionManager, showPermissionP
9727
9442
  glob_files: {},
9728
9443
  grep_search: {},
9729
9444
  delete_file: {},
9730
- // Shell execution (always requires permission)
9731
- bash_execute: {},
9732
9445
  // Server-side tools (executed via /api/ai/v1/tools Lambda)
9733
9446
  // Routed by ToolRouter to use B4M company API keys
9734
9447
  weather_info: {},
@@ -9794,7 +9507,6 @@ var DEFAULT_TOOL_CATEGORIES = {
9794
9507
  create_file: "prompt_always",
9795
9508
  delete_file: "prompt_always",
9796
9509
  shell_execute: "prompt_always",
9797
- bash_execute: "prompt_always",
9798
9510
  git_commit: "prompt_always",
9799
9511
  git_push: "prompt_always",
9800
9512
  // ===== PROMPT DEFAULT (Repository read tools) =====
@@ -9956,6 +9668,118 @@ function getEnvironmentName(configApiConfig) {
9956
9668
  return "Bike4Mind";
9957
9669
  }
9958
9670
 
9671
+ // src/utils/contextLoader.ts
9672
+ import * as fs11 from "fs";
9673
+ import * as path12 from "path";
9674
+ import { homedir as homedir4 } from "os";
9675
+ var CONTEXT_FILE_SIZE_LIMIT = 100 * 1024;
9676
+ var PROJECT_CONTEXT_FILES = [
9677
+ "CLAUDE.local.md",
9678
+ // gitignored, highest priority
9679
+ "CLAUDE.md",
9680
+ "AGENTS.md",
9681
+ // cross-tool standard
9682
+ "AI.local.md",
9683
+ // gitignored
9684
+ "AI.md",
9685
+ "INSTRUCTIONS.md"
9686
+ ];
9687
+ var GLOBAL_CONTEXT_FILES = ["AI.local.md", "AI.md"];
9688
+ function formatFileSize2(bytes) {
9689
+ if (bytes < 1024) return `${bytes}B`;
9690
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
9691
+ return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
9692
+ }
9693
+ function tryReadContextFile(dir, filename, source) {
9694
+ const filePath = path12.join(dir, filename);
9695
+ try {
9696
+ const stats = fs11.lstatSync(filePath);
9697
+ if (stats.isDirectory()) {
9698
+ return null;
9699
+ }
9700
+ if (stats.isSymbolicLink()) {
9701
+ return {
9702
+ error: `${source === "global" ? "Global" : "Project"} ${filename} is a symlink (not allowed for security)`
9703
+ };
9704
+ }
9705
+ if (stats.size > CONTEXT_FILE_SIZE_LIMIT) {
9706
+ return {
9707
+ error: `${source === "global" ? "Global" : "Project"} ${filename} exceeds 100KB limit (${formatFileSize2(stats.size)})`
9708
+ };
9709
+ }
9710
+ const content = fs11.readFileSync(filePath, "utf-8");
9711
+ return {
9712
+ filename,
9713
+ content,
9714
+ source,
9715
+ path: filePath
9716
+ };
9717
+ } catch (err) {
9718
+ if (err.code === "ENOENT") {
9719
+ return null;
9720
+ }
9721
+ if (err.code === "EACCES") {
9722
+ return {
9723
+ error: `Cannot read ${source} ${filename}: permission denied`
9724
+ };
9725
+ }
9726
+ return {
9727
+ error: `Cannot read ${source} ${filename}: ${err instanceof Error ? err.message : "Unknown error"}`
9728
+ };
9729
+ }
9730
+ }
9731
+ function findContextFile(dir, candidates, source) {
9732
+ for (const filename of candidates) {
9733
+ const result = tryReadContextFile(dir, filename, source);
9734
+ if (result === null) {
9735
+ continue;
9736
+ }
9737
+ if ("error" in result) {
9738
+ return { result: null, error: result.error };
9739
+ }
9740
+ return { result, error: null };
9741
+ }
9742
+ return { result: null, error: null };
9743
+ }
9744
+ function mergeContextContent(global, project) {
9745
+ if (global && project) {
9746
+ return `${global.content}
9747
+
9748
+ ---
9749
+
9750
+ ${project.content}`;
9751
+ }
9752
+ if (global) {
9753
+ return global.content;
9754
+ }
9755
+ if (project) {
9756
+ return project.content;
9757
+ }
9758
+ return "";
9759
+ }
9760
+ async function loadContextFiles(projectDir) {
9761
+ const errors = [];
9762
+ const globalDir = path12.join(homedir4(), ".bike4mind");
9763
+ const projectDirectory = projectDir || process.cwd();
9764
+ const [globalResult, projectResult] = await Promise.all([
9765
+ Promise.resolve(findContextFile(globalDir, GLOBAL_CONTEXT_FILES, "global")),
9766
+ Promise.resolve(findContextFile(projectDirectory, PROJECT_CONTEXT_FILES, "project"))
9767
+ ]);
9768
+ if (globalResult.error) {
9769
+ errors.push(globalResult.error);
9770
+ }
9771
+ if (projectResult.error) {
9772
+ errors.push(projectResult.error);
9773
+ }
9774
+ const mergedContent = mergeContextContent(globalResult.result, projectResult.result);
9775
+ return {
9776
+ globalContext: globalResult.result,
9777
+ projectContext: projectResult.result,
9778
+ mergedContent,
9779
+ errors
9780
+ };
9781
+ }
9782
+
9959
9783
  // ../../b4m-core/packages/mcp/dist/src/client.js
9960
9784
  import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
9961
9785
  import { Client as Client2 } from "@modelcontextprotocol/sdk/client/index.js";
@@ -10813,7 +10637,7 @@ import { isAxiosError as isAxiosError2 } from "axios";
10813
10637
  // package.json
10814
10638
  var package_default = {
10815
10639
  name: "@bike4mind/cli",
10816
- version: "0.2.8-cli-bash-tools.17146+9129ce1ea",
10640
+ version: "0.2.8-feat-cli-context-file-loading.17148+ce4df6add",
10817
10641
  type: "module",
10818
10642
  description: "Interactive CLI tool for Bike4Mind with ReAct agents",
10819
10643
  license: "UNLICENSED",
@@ -10916,10 +10740,10 @@ var package_default = {
10916
10740
  },
10917
10741
  devDependencies: {
10918
10742
  "@bike4mind/agents": "0.1.0",
10919
- "@bike4mind/common": "2.38.2-cli-bash-tools.17146+9129ce1ea",
10920
- "@bike4mind/mcp": "1.20.2-cli-bash-tools.17146+9129ce1ea",
10921
- "@bike4mind/services": "2.33.2-cli-bash-tools.17146+9129ce1ea",
10922
- "@bike4mind/utils": "2.1.3-cli-bash-tools.17146+9129ce1ea",
10743
+ "@bike4mind/common": "2.38.2-feat-cli-context-file-loading.17148+ce4df6add",
10744
+ "@bike4mind/mcp": "1.20.2-feat-cli-context-file-loading.17148+ce4df6add",
10745
+ "@bike4mind/services": "2.33.2-feat-cli-context-file-loading.17148+ce4df6add",
10746
+ "@bike4mind/utils": "2.1.3-feat-cli-context-file-loading.17148+ce4df6add",
10923
10747
  "@types/better-sqlite3": "^7.6.12",
10924
10748
  "@types/diff": "^5.0.9",
10925
10749
  "@types/jsonwebtoken": "^9.0.4",
@@ -10932,7 +10756,7 @@ var package_default = {
10932
10756
  typescript: "^5.9.3",
10933
10757
  vitest: "^3.2.4"
10934
10758
  },
10935
- gitHead: "9129ce1ea5d8589dec80ac92bf32ca954c6844fc"
10759
+ gitHead: "ce4df6add3c7091ebe97f2b87790ef684c56404d"
10936
10760
  };
10937
10761
 
10938
10762
  // src/config/constants.ts
@@ -10954,7 +10778,7 @@ var usageCache = null;
10954
10778
  function CliApp() {
10955
10779
  const { exit } = useApp();
10956
10780
  const imageRenderer = new ImageRenderer();
10957
- const [state, setState] = useState5({
10781
+ const [state, setState] = useState6({
10958
10782
  session: null,
10959
10783
  sessionStore: new SessionStore(),
10960
10784
  configStore: new ConfigStore(),
@@ -10970,9 +10794,9 @@ function CliApp() {
10970
10794
  trustLocationSelector: null,
10971
10795
  rewindSelector: null
10972
10796
  });
10973
- const [isInitialized, setIsInitialized] = useState5(false);
10974
- const [initError, setInitError] = useState5(null);
10975
- const [commandHistory, setCommandHistory] = useState5([]);
10797
+ const [isInitialized, setIsInitialized] = useState6(false);
10798
+ const [initError, setInitError] = useState6(null);
10799
+ const [commandHistory, setCommandHistory] = useState6([]);
10976
10800
  const imageStoreInitPromise = useRef(null);
10977
10801
  const setStoreSession = useCliStore((state2) => state2.setSession);
10978
10802
  const setPermissionPrompt = useCliStore((state2) => state2.setPermissionPrompt);
@@ -11013,7 +10837,7 @@ function CliApp() {
11013
10837
  process.exit(0);
11014
10838
  }, 100);
11015
10839
  }, [state.session, state.sessionStore, state.mcpManager, state.agent, state.imageStore]);
11016
- useInput4((input, key) => {
10840
+ useInput5((input, key) => {
11017
10841
  if (key.ctrl && input === "c") {
11018
10842
  const now = Date.now();
11019
10843
  if (exitTimestamp && now - exitTimestamp < EXIT_TIMEOUT_MS) {
@@ -11183,6 +11007,24 @@ function CliApp() {
11183
11007
  }
11184
11008
  const allTools = [...b4mTools, ...mcpTools];
11185
11009
  console.log(`\u2705 Total: ${allTools.length} tool(s) available`);
11010
+ const projectDir = state.configStore.getProjectConfigDir();
11011
+ const contextResult = await loadContextFiles(projectDir);
11012
+ if (contextResult.globalContext) {
11013
+ console.log(`\u{1F4C4} Global context: ${contextResult.globalContext.filename}`);
11014
+ }
11015
+ if (contextResult.projectContext) {
11016
+ console.log(`\u{1F4C4} Project context: ${contextResult.projectContext.filename}`);
11017
+ }
11018
+ for (const error of contextResult.errors) {
11019
+ console.log(`\u26A0\uFE0F Context file error: ${error}`);
11020
+ }
11021
+ const contextSection = contextResult.mergedContent ? `
11022
+
11023
+ ## Project Context
11024
+
11025
+ Follow these project-specific instructions:
11026
+
11027
+ ${contextResult.mergedContent}` : "";
11186
11028
  const cliSystemPrompt = `You are an autonomous AI assistant with access to tools. Your job is to help users by taking action and solving problems proactively.
11187
11029
 
11188
11030
  CORE BEHAVIOR:
@@ -11212,7 +11054,7 @@ EXAMPLES:
11212
11054
  - "enhance README" \u2192 file_read \u2192 generate \u2192 create_file
11213
11055
  - "what packages installed?" \u2192 glob_files "**/package.json" \u2192 file_read
11214
11056
 
11215
- Remember: Use context from previous messages to understand follow-up questions.`;
11057
+ Remember: Use context from previous messages to understand follow-up questions.${contextSection}`;
11216
11058
  const maxIterations = config.preferences.maxIterations === null ? 999999 : config.preferences.maxIterations;
11217
11059
  const agent = new ReActAgent({
11218
11060
  userId: config.userId,
@@ -11267,29 +11109,6 @@ Remember: Use context from previous messages to understand follow-up questions.`
11267
11109
  console.log("\u{1F4A1} Run /login to authenticate with your B4M account.\n");
11268
11110
  return;
11269
11111
  }
11270
- const currentSteps = [];
11271
- const stepHandler = (step) => {
11272
- currentSteps.push(step);
11273
- const currentSession = useCliStore.getState().session;
11274
- if (currentSession) {
11275
- const messages = [...currentSession.messages];
11276
- const lastMessage = messages[messages.length - 1];
11277
- if (lastMessage && lastMessage.role === "assistant") {
11278
- messages[messages.length - 1] = {
11279
- ...lastMessage,
11280
- metadata: {
11281
- ...lastMessage.metadata,
11282
- steps: [...currentSteps]
11283
- }
11284
- };
11285
- setStoreSession({
11286
- ...currentSession,
11287
- messages
11288
- });
11289
- }
11290
- }
11291
- };
11292
- state.agent.on("action", stepHandler);
11293
11112
  try {
11294
11113
  let messageContent = message;
11295
11114
  let userMessageContent = message;
@@ -11303,21 +11122,6 @@ Remember: Use context from previous messages to understand follow-up questions.`
11303
11122
  content: userMessageContent,
11304
11123
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
11305
11124
  };
11306
- const pendingAssistantMessage = {
11307
- role: "assistant",
11308
- content: "...",
11309
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
11310
- metadata: {
11311
- steps: []
11312
- }
11313
- };
11314
- const sessionWithMessages = {
11315
- ...state.session,
11316
- messages: [...state.session.messages, userMessage, pendingAssistantMessage],
11317
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
11318
- };
11319
- setState((prev) => ({ ...prev, session: sessionWithMessages }));
11320
- setStoreSession(sessionWithMessages);
11321
11125
  const recentMessages = state.session.messages.slice(-20);
11322
11126
  const previousMessages = recentMessages.filter((msg) => msg.role === "user" || msg.role === "assistant").map((msg) => ({
11323
11127
  role: msg.role,
@@ -11331,28 +11135,26 @@ Remember: Use context from previous messages to understand follow-up questions.`
11331
11135
  console.log("\n\u26A0\uFE0F Action denied by user\n");
11332
11136
  }
11333
11137
  const successfulToolCalls = result.steps.filter((s) => s.type === "observation").length;
11334
- const currentSession = useCliStore.getState().session;
11335
- if (!currentSession) return;
11336
- const finalMessages = [...currentSession.messages];
11337
- const finalAssistantMessage = {
11138
+ const assistantMessage = {
11338
11139
  role: "assistant",
11339
11140
  content: result.finalAnswer,
11340
- timestamp: pendingAssistantMessage.timestamp,
11141
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
11341
11142
  metadata: {
11342
11143
  tokenUsage: {
11343
11144
  prompt: 0,
11145
+ // TODO: Extract from result
11344
11146
  completion: 0,
11345
11147
  total: result.completionInfo.totalTokens
11346
11148
  },
11347
11149
  steps: result.steps,
11348
11150
  // Complete history: thoughts, actions, observations
11349
11151
  permissionDenied
11152
+ // Mark if this ended due to permission denial
11350
11153
  }
11351
11154
  };
11352
- finalMessages[finalMessages.length - 1] = finalAssistantMessage;
11353
11155
  const updatedSession = {
11354
- ...currentSession,
11355
- messages: finalMessages,
11156
+ ...state.session,
11157
+ messages: [...state.session.messages, userMessage, assistantMessage],
11356
11158
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
11357
11159
  metadata: {
11358
11160
  ...state.session.metadata,
@@ -11372,8 +11174,6 @@ Remember: Use context from previous messages to understand follow-up questions.`
11372
11174
  }
11373
11175
  }
11374
11176
  console.error("Error processing message:", error);
11375
- } finally {
11376
- state.agent.off("action", stepHandler);
11377
11177
  }
11378
11178
  };
11379
11179
  const handleImageDetected = async (imageData) => {
@@ -11925,12 +11725,12 @@ No usage data available for the last ${USAGE_DAYS} days.`);
11925
11725
  setState((prev) => ({ ...prev, config: updatedConfig }));
11926
11726
  };
11927
11727
  if (initError) {
11928
- 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"));
11728
+ return /* @__PURE__ */ React15.createElement(Box14, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React15.createElement(Text14, { color: "red", bold: true }, "\u274C Initialization Error"), /* @__PURE__ */ React15.createElement(Text14, null, initError), /* @__PURE__ */ React15.createElement(Text14, { dimColor: true }, "\n", "Tip: Run /config to set up your API keys"));
11929
11729
  }
11930
11730
  if (state.trustLocationSelector) {
11931
11731
  const projectDir = state.configStore.getProjectConfigDir();
11932
11732
  const inProject = projectDir !== null;
11933
- return /* @__PURE__ */ React14.createElement(
11733
+ return /* @__PURE__ */ React15.createElement(
11934
11734
  TrustLocationSelector,
11935
11735
  {
11936
11736
  inProject,
@@ -11948,7 +11748,7 @@ No usage data available for the last ${USAGE_DAYS} days.`);
11948
11748
  );
11949
11749
  }
11950
11750
  if (state.rewindSelector && state.session) {
11951
- return /* @__PURE__ */ React14.createElement(
11751
+ return /* @__PURE__ */ React15.createElement(
11952
11752
  RewindSelector,
11953
11753
  {
11954
11754
  messages: state.session.messages,
@@ -11967,7 +11767,7 @@ No usage data available for the last ${USAGE_DAYS} days.`);
11967
11767
  }
11968
11768
  if (state.showLoginFlow) {
11969
11769
  const loginApiUrl = getApiUrl(state.config?.apiConfig);
11970
- return /* @__PURE__ */ React14.createElement(
11770
+ return /* @__PURE__ */ React15.createElement(
11971
11771
  LoginFlow,
11972
11772
  {
11973
11773
  apiUrl: loginApiUrl,
@@ -11990,9 +11790,9 @@ No usage data available for the last ${USAGE_DAYS} days.`);
11990
11790
  );
11991
11791
  }
11992
11792
  if (!isInitialized) {
11993
- return /* @__PURE__ */ React14.createElement(Box14, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React14.createElement(Text13, null, "\u{1F680} Initializing..."));
11793
+ return /* @__PURE__ */ React15.createElement(Box14, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React15.createElement(Text14, null, "\u{1F680} Initializing..."));
11994
11794
  }
11995
- return /* @__PURE__ */ React14.createElement(
11795
+ return /* @__PURE__ */ React15.createElement(
11996
11796
  App,
11997
11797
  {
11998
11798
  onMessage: handleMessage,
@@ -12031,6 +11831,6 @@ var isDevMode = import.meta.url.includes("/src/") || process.env.NODE_ENV === "d
12031
11831
  if (isDevMode) {
12032
11832
  console.log("\u{1F527} Running in development mode (using TypeScript source)\n");
12033
11833
  }
12034
- render(/* @__PURE__ */ React14.createElement(CliApp, null), {
11834
+ render(/* @__PURE__ */ React15.createElement(CliApp, null), {
12035
11835
  exitOnCtrlC: false
12036
11836
  });