@bike4mind/cli 0.2.1-quest-file-uploads.17007 → 0.2.2

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-QXGU6KYI.js";
8
- import "./chunk-LZMRYJ3B.js";
9
- import "./chunk-F3ETXO5N.js";
7
+ } from "./chunk-GZTILMGE.js";
8
+ import "./chunk-Y4HMTEDH.js";
9
+ import "./chunk-5N4PG5EH.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-U3GPYBTD.js";
18
+ } from "./chunk-NZADYDFG.js";
19
19
  import {
20
20
  Logger
21
21
  } from "./chunk-AMDXHL6S.js";
@@ -29,6 +29,7 @@ import {
29
29
  AuthEvents,
30
30
  BFL_IMAGE_MODELS,
31
31
  BFL_SAFETY_TOLERANCE,
32
+ CREDIT_DEDUCT_TRANSACTION_TYPES,
32
33
  ChatCompletionCreateInputSchema,
33
34
  ChatModels,
34
35
  CollectionType,
@@ -78,13 +79,13 @@ import {
78
79
  } from "./chunk-PDX44BCA.js";
79
80
 
80
81
  // src/index.tsx
81
- import React10, { useState as useState3, useEffect as useEffect3, useCallback } from "react";
82
- import { render, Box as Box10, Text as Text9, useApp, useInput as useInput2 } from "ink";
82
+ import React11, { useState as useState3, useEffect as useEffect3, useCallback } from "react";
83
+ import { render, Box as Box11, Text as Text10, useApp, useInput as useInput2 } from "ink";
83
84
  import { v4 as uuidv49 } from "uuid";
84
85
 
85
86
  // src/components/App.tsx
86
- import React7 from "react";
87
- import { Box as Box7, Text as Text6, Static } from "ink";
87
+ import React8 from "react";
88
+ import { Box as Box8, Text as Text7, Static } from "ink";
88
89
 
89
90
  // src/components/StatusBar.tsx
90
91
  import React from "react";
@@ -94,8 +95,8 @@ var StatusBar = React.memo(function StatusBar2({ sessionName, model, tokenUsage
94
95
  });
95
96
 
96
97
  // src/components/InputPrompt.tsx
97
- import React3, { useState, useMemo, useEffect } from "react";
98
- import { Box as Box3, Text as Text3, useInput } from "ink";
98
+ import React4, { useState, useMemo, useEffect } from "react";
99
+ import { Box as Box4, Text as Text4, useInput } from "ink";
99
100
  import TextInput from "ink-text-input";
100
101
 
101
102
  // src/components/CommandAutocomplete.tsx
@@ -112,8 +113,210 @@ function CommandAutocomplete({ commands, selectedIndex }) {
112
113
  }));
113
114
  }
114
115
 
115
- // src/utils/fuzzySearch.ts
116
+ // src/components/FileAutocomplete.tsx
117
+ import React3 from "react";
118
+ import { Box as Box3, Text as Text3 } from "ink";
119
+
120
+ // src/utils/fileSearch.ts
121
+ import * as fs from "fs";
122
+ import * as path from "path";
116
123
  import Fuse from "fuse.js";
124
+ var DEFAULT_IGNORE_PATTERNS = [
125
+ "node_modules",
126
+ ".git",
127
+ ".next",
128
+ ".turbo",
129
+ "dist",
130
+ "build",
131
+ ".cache",
132
+ "coverage",
133
+ ".DS_Store",
134
+ ".env",
135
+ ".env.local",
136
+ ".env.secrets"
137
+ ];
138
+ function walkDirectory(basePath = process.cwd(), maxDepth = 5, ignorePatterns = DEFAULT_IGNORE_PATTERNS) {
139
+ const results = [];
140
+ const normalizedBase = path.resolve(basePath);
141
+ function walk(currentPath, depth) {
142
+ if (depth > maxDepth) return;
143
+ try {
144
+ const entries = fs.readdirSync(currentPath, { withFileTypes: true });
145
+ for (const entry of entries) {
146
+ if (ignorePatterns.some((pattern) => entry.name === pattern || entry.name.startsWith(pattern))) {
147
+ continue;
148
+ }
149
+ const fullPath = path.join(currentPath, entry.name);
150
+ const relativePath = path.relative(normalizedBase, fullPath);
151
+ if (entry.isDirectory()) {
152
+ results.push({
153
+ path: relativePath,
154
+ isDirectory: true
155
+ });
156
+ walk(fullPath, depth + 1);
157
+ } else if (entry.isFile()) {
158
+ try {
159
+ const stats = fs.statSync(fullPath);
160
+ results.push({
161
+ path: relativePath,
162
+ isDirectory: false,
163
+ size: stats.size
164
+ });
165
+ } catch {
166
+ results.push({
167
+ path: relativePath,
168
+ isDirectory: false
169
+ });
170
+ }
171
+ }
172
+ }
173
+ } catch {
174
+ }
175
+ }
176
+ walk(normalizedBase, 0);
177
+ return results;
178
+ }
179
+ function formatFileSize(bytes) {
180
+ if (bytes < 1024) return `${bytes} B`;
181
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
182
+ if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
183
+ return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;
184
+ }
185
+ var cachedFiles = null;
186
+ var cacheTimestamp = 0;
187
+ var CACHE_TTL_MS = 3e4;
188
+ function getCachedFiles() {
189
+ const now = Date.now();
190
+ if (!cachedFiles || now - cacheTimestamp > CACHE_TTL_MS) {
191
+ cachedFiles = walkDirectory();
192
+ cacheTimestamp = now;
193
+ }
194
+ return cachedFiles;
195
+ }
196
+ function searchFiles(query) {
197
+ const files = getCachedFiles();
198
+ if (!query || query.trim() === "") {
199
+ return files.filter((f) => !f.path.includes(path.sep)).slice(0, 20);
200
+ }
201
+ const queryDir = path.dirname(query);
202
+ let searchPool = files;
203
+ if (queryDir && queryDir !== ".") {
204
+ const normalizedDir = queryDir.replace(/\\/g, "/");
205
+ searchPool = files.filter((f) => {
206
+ const normalizedPath = f.path.replace(/\\/g, "/");
207
+ return normalizedPath.startsWith(normalizedDir + "/") || normalizedPath === normalizedDir;
208
+ });
209
+ if (searchPool.length === 0) {
210
+ searchPool = files;
211
+ }
212
+ }
213
+ const fuse2 = new Fuse(searchPool, {
214
+ keys: [{ name: "path", weight: 1 }],
215
+ threshold: 0.4,
216
+ // Allow some fuzzy matching
217
+ includeScore: true,
218
+ minMatchCharLength: 1,
219
+ // Use extended search for better path matching
220
+ useExtendedSearch: false
221
+ });
222
+ const results = fuse2.search(query);
223
+ return results.slice(0, 20).map((result) => result.item);
224
+ }
225
+ function isPathWithinCwd(filePath) {
226
+ const cwd = path.resolve(process.cwd());
227
+ const absolutePath = path.resolve(cwd, filePath);
228
+ let resolvedCwd = cwd;
229
+ let resolvedPath = absolutePath;
230
+ try {
231
+ const realCwd = fs.realpathSync.native(cwd);
232
+ if (realCwd) {
233
+ resolvedCwd = realCwd;
234
+ }
235
+ } catch {
236
+ }
237
+ try {
238
+ const realPath = fs.realpathSync.native(absolutePath);
239
+ if (realPath) {
240
+ resolvedPath = realPath;
241
+ }
242
+ } catch {
243
+ const relativePath2 = path.relative(cwd, absolutePath);
244
+ resolvedPath = path.resolve(resolvedCwd, relativePath2);
245
+ }
246
+ const normalizedCwd = resolvedCwd.toLowerCase();
247
+ const normalizedPath = resolvedPath.toLowerCase();
248
+ const isWithin = normalizedPath === normalizedCwd || normalizedPath.startsWith(normalizedCwd + path.sep);
249
+ if (!isWithin) {
250
+ return false;
251
+ }
252
+ const relativePath = path.relative(resolvedCwd, resolvedPath);
253
+ return !relativePath.startsWith("..") && !path.isAbsolute(relativePath);
254
+ }
255
+ function isBinaryFile(filePath) {
256
+ const binaryExtensions = [
257
+ ".png",
258
+ ".jpg",
259
+ ".jpeg",
260
+ ".gif",
261
+ ".bmp",
262
+ ".ico",
263
+ ".webp",
264
+ // Note: .svg is NOT included because SVG is XML text format that can be safely read
265
+ ".pdf",
266
+ ".doc",
267
+ ".docx",
268
+ ".xls",
269
+ ".xlsx",
270
+ ".ppt",
271
+ ".pptx",
272
+ ".zip",
273
+ ".tar",
274
+ ".gz",
275
+ ".rar",
276
+ ".7z",
277
+ ".exe",
278
+ ".dll",
279
+ ".so",
280
+ ".dylib",
281
+ ".bin",
282
+ ".dat",
283
+ ".mp3",
284
+ ".mp4",
285
+ ".wav",
286
+ ".avi",
287
+ ".mov",
288
+ ".mkv",
289
+ ".ttf",
290
+ ".otf",
291
+ ".woff",
292
+ ".woff2",
293
+ ".eot",
294
+ ".class",
295
+ ".pyc",
296
+ ".o",
297
+ ".obj"
298
+ ];
299
+ const ext = path.extname(filePath).toLowerCase();
300
+ return binaryExtensions.includes(ext);
301
+ }
302
+ var MAX_FILE_SIZE = 10 * 1024 * 1024;
303
+
304
+ // src/components/FileAutocomplete.tsx
305
+ function FileAutocomplete({ files, selectedIndex, query }) {
306
+ 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}"` : ""));
308
+ }
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) => {
310
+ const isSelected = index === selectedIndex;
311
+ const icon = file.isDirectory ? "[folder]" : "[file] ";
312
+ const sizeDisplay = file.isDirectory ? "" : file.size !== void 0 ? ` (${formatFileSize(file.size)})` : "";
313
+ 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));
315
+ }));
316
+ }
317
+
318
+ // src/utils/fuzzySearch.ts
319
+ import Fuse2 from "fuse.js";
117
320
 
118
321
  // src/config/commands.ts
119
322
  var COMMANDS = [
@@ -177,11 +380,15 @@ var COMMANDS = [
177
380
  {
178
381
  name: "trusted",
179
382
  description: "List all trusted tools"
383
+ },
384
+ {
385
+ name: "usage",
386
+ description: "Show credit usage and balance"
180
387
  }
181
388
  ];
182
389
 
183
390
  // src/utils/fuzzySearch.ts
184
- var fuse = new Fuse(COMMANDS, {
391
+ var fuse = new Fuse2(COMMANDS, {
185
392
  keys: [
186
393
  { name: "name", weight: 0.7 },
187
394
  // Prioritize command name
@@ -202,23 +409,65 @@ function searchCommands(query) {
202
409
  }
203
410
 
204
411
  // src/components/InputPrompt.tsx
412
+ function findAtTrigger(value) {
413
+ for (let i = value.length - 1; i >= 0; i--) {
414
+ if (value[i] === "@") {
415
+ const isValid = i === 0 || value[i - 1] === " ";
416
+ if (isValid) {
417
+ const query = value.slice(i + 1);
418
+ if (query.includes(" ")) {
419
+ return null;
420
+ }
421
+ return { startIndex: i, query };
422
+ }
423
+ }
424
+ }
425
+ return null;
426
+ }
205
427
  function InputPrompt({ onSubmit, disabled = false, history = [] }) {
206
428
  const [value, setValue] = useState("");
207
429
  const [selectedIndex, setSelectedIndex] = useState(0);
208
430
  const [historyIndex, setHistoryIndex] = useState(-1);
209
431
  const [tempInput, setTempInput] = useState("");
210
432
  const [inputKey, setInputKey] = useState(0);
211
- const shouldShowAutocomplete = value.startsWith("/") && !disabled;
212
- const query = shouldShowAutocomplete ? value.slice(1) : "";
433
+ const [fileAutocomplete, setFileAutocomplete] = useState(null);
434
+ const [fileSelectedIndex, setFileSelectedIndex] = useState(0);
435
+ const shouldShowCommandAutocomplete = value.startsWith("/") && !disabled && !fileAutocomplete?.active;
436
+ const commandQuery = shouldShowCommandAutocomplete ? value.slice(1) : "";
213
437
  const filteredCommands = useMemo(() => {
214
- if (!shouldShowAutocomplete) return [];
215
- return searchCommands(query);
216
- }, [shouldShowAutocomplete, query]);
438
+ if (!shouldShowCommandAutocomplete) return [];
439
+ return searchCommands(commandQuery);
440
+ }, [shouldShowCommandAutocomplete, commandQuery]);
441
+ const filteredFiles = useMemo(() => {
442
+ if (!fileAutocomplete?.active) return [];
443
+ return searchFiles(fileAutocomplete.query);
444
+ }, [fileAutocomplete?.active, fileAutocomplete?.query]);
217
445
  useEffect(() => {
218
446
  setSelectedIndex(0);
219
447
  }, [filteredCommands]);
448
+ useEffect(() => {
449
+ setFileSelectedIndex(0);
450
+ }, [filteredFiles]);
220
451
  useInput((input, key) => {
221
- if (shouldShowAutocomplete && filteredCommands.length > 0) {
452
+ if (fileAutocomplete?.active && filteredFiles.length > 0) {
453
+ if (key.upArrow) {
454
+ setFileSelectedIndex((prev) => prev > 0 ? prev - 1 : filteredFiles.length - 1);
455
+ return;
456
+ } else if (key.downArrow) {
457
+ setFileSelectedIndex((prev) => prev < filteredFiles.length - 1 ? prev + 1 : 0);
458
+ return;
459
+ } else if (key.tab) {
460
+ const selectedFile = filteredFiles[fileSelectedIndex];
461
+ if (selectedFile) {
462
+ insertSelectedFile(selectedFile);
463
+ }
464
+ return;
465
+ } else if (key.escape) {
466
+ setFileAutocomplete(null);
467
+ return;
468
+ }
469
+ }
470
+ if (shouldShowCommandAutocomplete && filteredCommands.length > 0) {
222
471
  if (key.upArrow) {
223
472
  setSelectedIndex((prev) => prev > 0 ? prev - 1 : filteredCommands.length - 1);
224
473
  } else if (key.downArrow) {
@@ -226,7 +475,7 @@ function InputPrompt({ onSubmit, disabled = false, history = [] }) {
226
475
  }
227
476
  return;
228
477
  }
229
- if (!shouldShowAutocomplete && history.length > 0) {
478
+ if (!shouldShowCommandAutocomplete && !fileAutocomplete?.active && history.length > 0) {
230
479
  if (key.upArrow) {
231
480
  if (historyIndex === -1) {
232
481
  setTempInput(value);
@@ -249,9 +498,35 @@ function InputPrompt({ onSubmit, disabled = false, history = [] }) {
249
498
  }
250
499
  }
251
500
  });
501
+ const insertSelectedFile = (file) => {
502
+ if (!fileAutocomplete) return;
503
+ const beforeAt = value.slice(0, fileAutocomplete.startIndex);
504
+ const afterQuery = value.slice(fileAutocomplete.startIndex + 1 + fileAutocomplete.query.length);
505
+ const pathToInsert = file.isDirectory ? `@${file.path}/` : `@${file.path}`;
506
+ const newValue = beforeAt + pathToInsert + afterQuery;
507
+ setValue(newValue);
508
+ setInputKey((prev) => prev + 1);
509
+ if (file.isDirectory) {
510
+ setFileAutocomplete({
511
+ active: true,
512
+ startIndex: fileAutocomplete.startIndex,
513
+ query: file.path + "/"
514
+ });
515
+ setFileSelectedIndex(0);
516
+ } else {
517
+ setFileAutocomplete(null);
518
+ }
519
+ };
252
520
  const handleSubmit = (input) => {
253
521
  if (disabled || !input.trim()) return;
254
- if (shouldShowAutocomplete && filteredCommands.length > 0) {
522
+ if (fileAutocomplete?.active && filteredFiles.length > 0) {
523
+ const selectedFile = filteredFiles[fileSelectedIndex];
524
+ if (selectedFile) {
525
+ insertSelectedFile(selectedFile);
526
+ }
527
+ return;
528
+ }
529
+ if (shouldShowCommandAutocomplete && filteredCommands.length > 0) {
255
530
  const selectedCommand = filteredCommands[selectedIndex];
256
531
  const commandText = `/${selectedCommand.name}`;
257
532
  if (selectedCommand.args) {
@@ -268,6 +543,7 @@ function InputPrompt({ onSubmit, disabled = false, history = [] }) {
268
543
  onSubmit(input);
269
544
  setValue("");
270
545
  setHistoryIndex(-1);
546
+ setFileAutocomplete(null);
271
547
  };
272
548
  const handleChange = (newValue) => {
273
549
  setValue(newValue);
@@ -275,30 +551,40 @@ function InputPrompt({ onSubmit, disabled = false, history = [] }) {
275
551
  setHistoryIndex(-1);
276
552
  setTempInput("");
277
553
  }
554
+ const atTrigger = findAtTrigger(newValue);
555
+ if (atTrigger) {
556
+ setFileAutocomplete({
557
+ active: true,
558
+ startIndex: atTrigger.startIndex,
559
+ query: atTrigger.query
560
+ });
561
+ } else {
562
+ setFileAutocomplete(null);
563
+ }
278
564
  };
279
- return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Box3, null, /* @__PURE__ */ React3.createElement(Text3, { bold: true, color: "cyan" }, "> "), /* @__PURE__ */ React3.createElement(
565
+ return /* @__PURE__ */ React4.createElement(Box4, { flexDirection: "column" }, /* @__PURE__ */ React4.createElement(Box4, null, /* @__PURE__ */ React4.createElement(Text4, { bold: true, color: "cyan" }, "> "), /* @__PURE__ */ React4.createElement(
280
566
  TextInput,
281
567
  {
282
568
  key: inputKey,
283
569
  value,
284
570
  onChange: handleChange,
285
571
  onSubmit: handleSubmit,
286
- placeholder: disabled ? "Thinking..." : "Type your message or /help for commands",
572
+ placeholder: disabled ? "Thinking..." : "Type your message, /help for commands, or @file to reference",
287
573
  showCursor: !disabled
288
574
  }
289
- )), shouldShowAutocomplete && /* @__PURE__ */ React3.createElement(CommandAutocomplete, { commands: filteredCommands, selectedIndex }));
575
+ )), shouldShowCommandAutocomplete && /* @__PURE__ */ React4.createElement(CommandAutocomplete, { commands: filteredCommands, selectedIndex }), fileAutocomplete?.active && /* @__PURE__ */ React4.createElement(FileAutocomplete, { files: filteredFiles, selectedIndex: fileSelectedIndex, query: fileAutocomplete.query }));
290
576
  }
291
577
 
292
578
  // src/components/AgentThinking.tsx
293
- import React5 from "react";
294
- import { Box as Box5 } from "ink";
579
+ import React6 from "react";
580
+ import { Box as Box6 } from "ink";
295
581
 
296
582
  // src/components/ThoughtStream.tsx
297
- import React4 from "react";
298
- import { Box as Box4, Text as Text4 } from "ink";
583
+ import React5 from "react";
584
+ import { Box as Box5, Text as Text5 } from "ink";
299
585
  import Spinner from "ink-spinner";
300
- var ThoughtStream = React4.memo(function ThoughtStream2({ steps }) {
301
- return /* @__PURE__ */ React4.createElement(Box4, { flexDirection: "column", gap: 1 }, steps.map((step, index) => /* @__PURE__ */ React4.createElement(Box4, { key: index, flexDirection: "column" }, step.type === "thought" && /* @__PURE__ */ React4.createElement(Box4, null, /* @__PURE__ */ React4.createElement(Text4, { color: "magenta" }, "\u{1F914} Thought: "), /* @__PURE__ */ React4.createElement(Text4, null, step.content)), step.type === "action" && /* @__PURE__ */ React4.createElement(Box4, { flexDirection: "column" }, /* @__PURE__ */ React4.createElement(Box4, null, /* @__PURE__ */ React4.createElement(Text4, { color: "yellow" }, "\u26A1 Action: "), /* @__PURE__ */ React4.createElement(Text4, { bold: true }, step.metadata?.toolName || "unknown")), step.metadata?.toolInput && /* @__PURE__ */ React4.createElement(Box4, { paddingLeft: 2 }, /* @__PURE__ */ React4.createElement(Text4, { dimColor: true }, JSON.stringify(step.metadata.toolInput, null, 2)))), step.type === "observation" && /* @__PURE__ */ React4.createElement(Box4, { flexDirection: "column" }, /* @__PURE__ */ React4.createElement(Box4, null, /* @__PURE__ */ React4.createElement(Text4, { color: "blue" }, "\u{1F4CA} Observation: ")), /* @__PURE__ */ React4.createElement(Box4, { paddingLeft: 2 }, /* @__PURE__ */ React4.createElement(Text4, null, step.content))), step.type === "final_answer" && /* @__PURE__ */ React4.createElement(Box4, { flexDirection: "column" }, /* @__PURE__ */ React4.createElement(Box4, null, /* @__PURE__ */ React4.createElement(Text4, { color: "green", bold: true }, "\u2705 Final Answer:", " ")), /* @__PURE__ */ React4.createElement(Box4, { paddingLeft: 2 }, /* @__PURE__ */ React4.createElement(Text4, null, step.content)), step.metadata?.tokenUsage && /* @__PURE__ */ React4.createElement(Box4, { paddingLeft: 2 }, /* @__PURE__ */ React4.createElement(Text4, { dimColor: true }, "(", step.metadata.tokenUsage.total, " tokens)"))))), !steps.some((s) => s.type === "final_answer") && /* @__PURE__ */ React4.createElement(Box4, null, /* @__PURE__ */ React4.createElement(Text4, { color: "yellow" }, /* @__PURE__ */ React4.createElement(Spinner, { type: "dots" })), /* @__PURE__ */ React4.createElement(Text4, null, " ", steps.length === 0 ? "Thinking..." : "Processing...")));
586
+ var ThoughtStream = React5.memo(function ThoughtStream2({ steps }) {
587
+ 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...")));
302
588
  });
303
589
 
304
590
  // src/store/index.ts
@@ -324,32 +610,32 @@ var useCliStore = create((set) => ({
324
610
  }));
325
611
 
326
612
  // src/components/AgentThinking.tsx
327
- var AgentThinking = React5.memo(function AgentThinking2() {
613
+ var AgentThinking = React6.memo(function AgentThinking2() {
328
614
  const isThinking = useCliStore((state) => state.isThinking);
329
615
  const agentSteps = useCliStore((state) => state.agentSteps);
330
616
  if (!isThinking) {
331
617
  return null;
332
618
  }
333
- return /* @__PURE__ */ React5.createElement(Box5, { borderStyle: "single", borderColor: "yellow", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React5.createElement(ThoughtStream, { steps: agentSteps }));
619
+ return /* @__PURE__ */ React6.createElement(Box6, { borderStyle: "single", borderColor: "yellow", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React6.createElement(ThoughtStream, { steps: agentSteps }));
334
620
  });
335
621
 
336
622
  // src/components/PermissionPrompt.tsx
337
- import React6 from "react";
338
- import { Box as Box6, Text as Text5 } from "ink";
623
+ import React7 from "react";
624
+ import { Box as Box7, Text as Text6 } from "ink";
339
625
  import SelectInput from "ink-select-input";
340
626
  function renderDiffPreview(preview) {
341
627
  const lines = preview.split("\n");
342
628
  return lines.map((line, index) => {
343
629
  if (line.startsWith("+")) {
344
- return /* @__PURE__ */ React6.createElement(Text5, { key: index, color: "green" }, line);
630
+ return /* @__PURE__ */ React7.createElement(Text6, { key: index, color: "green" }, line);
345
631
  }
346
632
  if (line.startsWith("-")) {
347
- return /* @__PURE__ */ React6.createElement(Text5, { key: index, color: "red" }, line);
633
+ return /* @__PURE__ */ React7.createElement(Text6, { key: index, color: "red" }, line);
348
634
  }
349
635
  if (line.startsWith("@@")) {
350
- return /* @__PURE__ */ React6.createElement(Text5, { key: index, color: "cyan" }, line);
636
+ return /* @__PURE__ */ React7.createElement(Text6, { key: index, color: "cyan" }, line);
351
637
  }
352
- return /* @__PURE__ */ React6.createElement(Text5, { key: index, dimColor: true }, line);
638
+ return /* @__PURE__ */ React7.createElement(Text6, { key: index, dimColor: true }, line);
353
639
  });
354
640
  }
355
641
  function PermissionPrompt({
@@ -369,7 +655,121 @@ function PermissionPrompt({
369
655
  { label: "\u2717 Deny", value: "deny" }
370
656
  ];
371
657
  const argsString = typeof args === "string" ? args : JSON.stringify(args, null, 2);
372
- return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column", borderStyle: "bold", borderColor: "yellow", padding: 1, marginY: 1 }, /* @__PURE__ */ React6.createElement(Box6, null, /* @__PURE__ */ React6.createElement(Text5, { bold: true, color: "yellow" }, "\u26A0\uFE0F Permission Required")), /* @__PURE__ */ React6.createElement(Box6, { marginTop: 1 }, /* @__PURE__ */ React6.createElement(Text5, { dimColor: true }, "Tool: "), /* @__PURE__ */ React6.createElement(Text5, { bold: true, color: "cyan" }, toolName)), toolDescription && /* @__PURE__ */ React6.createElement(Box6, null, /* @__PURE__ */ React6.createElement(Text5, { dimColor: true }, "Action: "), /* @__PURE__ */ React6.createElement(Text5, null, toolDescription)), /* @__PURE__ */ React6.createElement(Box6, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Text5, { bold: true }, "Arguments:"), /* @__PURE__ */ React6.createElement(Box6, { paddingLeft: 2, flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Text5, { dimColor: true }, argsString))), preview && /* @__PURE__ */ React6.createElement(Box6, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Text5, { bold: true }, "Preview:"), /* @__PURE__ */ React6.createElement(Box6, { borderStyle: "single", borderColor: "gray", paddingX: 1, flexDirection: "column" }, renderDiffPreview(preview))), !canBeTrusted && /* @__PURE__ */ React6.createElement(Box6, { marginTop: 1 }, /* @__PURE__ */ React6.createElement(Text5, { color: "red", dimColor: true }, "Note: This tool cannot be trusted due to its dangerous nature.")), /* @__PURE__ */ React6.createElement(Box6, { marginTop: 1 }, /* @__PURE__ */ React6.createElement(SelectInput, { items, onSelect: (item) => onResponse(item.value) })));
658
+ 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) })));
659
+ }
660
+
661
+ // src/utils/processFileReferences.ts
662
+ import * as fs2 from "fs";
663
+ import * as path2 from "path";
664
+
665
+ // src/utils/constants.ts
666
+ var NAME_SUFFIXES = ["jr", "sr", "ii", "iii", "iv", "v", "phd", "md", "esq"];
667
+ function isNameSuffix(value) {
668
+ return NAME_SUFFIXES.includes(value);
669
+ }
670
+
671
+ // src/utils/processFileReferences.ts
672
+ var FILE_REFERENCE_REGEX = /(?:^|\s)@([^\s@]+)/g;
673
+ function looksLikeFilePath(ref) {
674
+ if (ref.includes("/") || ref.includes(path2.sep)) {
675
+ return true;
676
+ }
677
+ const extensionMatch = /\.(\w+)$/.exec(ref);
678
+ if (extensionMatch) {
679
+ const ext = extensionMatch[1].toLowerCase();
680
+ if (isNameSuffix(ext)) {
681
+ return false;
682
+ }
683
+ if (ext.length > 10) {
684
+ return false;
685
+ }
686
+ return true;
687
+ }
688
+ return false;
689
+ }
690
+ function extractFileReferences(message) {
691
+ const references = [];
692
+ const regex = /(?:^|\s)@([^\s@]+)/g;
693
+ let match;
694
+ while ((match = regex.exec(message)) !== null) {
695
+ const ref = match[1];
696
+ if (looksLikeFilePath(ref)) {
697
+ references.push(ref);
698
+ }
699
+ }
700
+ return references;
701
+ }
702
+ function readFileContents(filePath) {
703
+ const cwd = process.cwd();
704
+ const absolutePath = path2.resolve(cwd, filePath);
705
+ if (!isPathWithinCwd(filePath)) {
706
+ return { error: `Security: Path "${filePath}" is outside the current working directory` };
707
+ }
708
+ if (!fs2.existsSync(absolutePath)) {
709
+ return { error: `File not found: "${filePath}"` };
710
+ }
711
+ const stats = fs2.statSync(absolutePath);
712
+ if (stats.isDirectory()) {
713
+ try {
714
+ const entries = fs2.readdirSync(absolutePath);
715
+ const fileCount = entries.length;
716
+ return {
717
+ content: `(Directory with ${fileCount} items. Use file tools to explore if needed.)`,
718
+ size: 0
719
+ };
720
+ } catch (err) {
721
+ return { error: `Cannot read directory "${filePath}": ${err instanceof Error ? err.message : "Unknown error"}` };
722
+ }
723
+ }
724
+ if (stats.size > MAX_FILE_SIZE) {
725
+ return {
726
+ error: `File too large: "${filePath}" is ${formatFileSize(stats.size)} (max ${formatFileSize(MAX_FILE_SIZE)})`
727
+ };
728
+ }
729
+ if (isBinaryFile(filePath)) {
730
+ return { error: `Binary file: "${filePath}" cannot be included as text content` };
731
+ }
732
+ try {
733
+ const content = fs2.readFileSync(absolutePath, "utf-8");
734
+ return { content, size: stats.size };
735
+ } catch (err) {
736
+ return { error: `Cannot read file "${filePath}": ${err instanceof Error ? err.message : "Unknown error"}` };
737
+ }
738
+ }
739
+ function formatFileBlock(filePath, content, size, isDirectory) {
740
+ if (isDirectory) {
741
+ return `
742
+ --- Directory Reference: ${filePath} ---
743
+ ${content}
744
+ --- End of ${filePath} ---`;
745
+ }
746
+ return `
747
+ --- Referenced File: ${filePath} (${formatFileSize(size)}) ---
748
+ ${content}
749
+ --- End of ${filePath} ---`;
750
+ }
751
+ async function processFileReferences(message) {
752
+ const references = extractFileReferences(message);
753
+ const errors = [];
754
+ const fileBlocks = [];
755
+ for (const ref of references) {
756
+ const result = readFileContents(ref);
757
+ if ("error" in result) {
758
+ errors.push(result.error);
759
+ continue;
760
+ }
761
+ const isDirectory = result.size === 0 && result.content.startsWith("(Directory");
762
+ fileBlocks.push(formatFileBlock(ref, result.content, result.size, isDirectory));
763
+ }
764
+ if (fileBlocks.length === 0) {
765
+ return { content: message, errors };
766
+ }
767
+ const processedContent = message + "\n" + fileBlocks.join("\n");
768
+ return { content: processedContent, errors };
769
+ }
770
+ function hasFileReferences(message) {
771
+ FILE_REFERENCE_REGEX.lastIndex = 0;
772
+ return FILE_REFERENCE_REGEX.test(message);
373
773
  }
374
774
 
375
775
  // src/components/App.tsx
@@ -382,7 +782,7 @@ function App({ onMessage, onCommand, onPermissionResponse, commandHistory = [] }
382
782
  const permissionPrompt = useCliStore((state) => state.permissionPrompt);
383
783
  const exitRequested = useCliStore((state) => state.exitRequested);
384
784
  const setIsThinking = useCliStore((state) => state.setIsThinking);
385
- const handleSubmit = React7.useCallback(
785
+ const handleSubmit = React8.useCallback(
386
786
  async (input) => {
387
787
  const trimmed = input.trim();
388
788
  if (!trimmed) return;
@@ -393,14 +793,25 @@ function App({ onMessage, onCommand, onPermissionResponse, commandHistory = [] }
393
793
  }
394
794
  setIsThinking(true);
395
795
  try {
396
- await onMessage(trimmed);
796
+ let messageToSend = trimmed;
797
+ if (hasFileReferences(trimmed)) {
798
+ const processed = await processFileReferences(trimmed);
799
+ messageToSend = processed.content;
800
+ if (processed.errors.length > 0) {
801
+ const errorBlock = processed.errors.map((e) => `[Warning: ${e}]`).join("\n");
802
+ messageToSend = `${messageToSend}
803
+
804
+ ${errorBlock}`;
805
+ }
806
+ }
807
+ await onMessage(messageToSend);
397
808
  } finally {
398
809
  setIsThinking(false);
399
810
  }
400
811
  },
401
812
  [onMessage, onCommand, setIsThinking]
402
813
  );
403
- return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column" }, /* @__PURE__ */ React7.createElement(StatusBar, { sessionName, model: currentModel, tokenUsage: totalTokens }), permissionPrompt ? /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React7.createElement(
814
+ return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column" }, /* @__PURE__ */ React8.createElement(StatusBar, { sessionName, model: currentModel, tokenUsage: totalTokens }), permissionPrompt ? /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React8.createElement(
404
815
  PermissionPrompt,
405
816
  {
406
817
  toolName: permissionPrompt.toolName,
@@ -409,39 +820,39 @@ function App({ onMessage, onCommand, onPermissionResponse, commandHistory = [] }
409
820
  canBeTrusted: permissionPrompt.canBeTrusted,
410
821
  onResponse: onPermissionResponse
411
822
  }
412
- )) : /* @__PURE__ */ React7.createElement(React7.Fragment, null, /* @__PURE__ */ React7.createElement(Static, { items: messages }, (message, index) => /* @__PURE__ */ React7.createElement(Box7, { key: index, flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React7.createElement(MessageItem, { message }))), /* @__PURE__ */ React7.createElement(AgentThinking, null), exitRequested && /* @__PURE__ */ React7.createElement(Box7, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React7.createElement(Text6, { color: "yellow", bold: true }, "\u26A0\uFE0F Press Ctrl+C again to exit")), /* @__PURE__ */ React7.createElement(Box7, { borderStyle: "single", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React7.createElement(InputPrompt, { onSubmit: handleSubmit, disabled: isThinking, history: commandHistory }))));
823
+ )) : /* @__PURE__ */ React8.createElement(React8.Fragment, null, /* @__PURE__ */ React8.createElement(Static, { items: messages }, (message, index) => /* @__PURE__ */ React8.createElement(Box8, { key: index, flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React8.createElement(MessageItem, { message }))), /* @__PURE__ */ React8.createElement(AgentThinking, null), exitRequested && /* @__PURE__ */ React8.createElement(Box8, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React8.createElement(Text7, { color: "yellow", bold: true }, "\u26A0\uFE0F Press Ctrl+C again to exit")), /* @__PURE__ */ React8.createElement(Box8, { borderStyle: "single", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React8.createElement(InputPrompt, { onSubmit: handleSubmit, disabled: isThinking, history: commandHistory }))));
413
824
  }
414
825
  function MessageItem({ message }) {
415
- return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React7.createElement(Box7, null, /* @__PURE__ */ React7.createElement(Text6, { bold: true, color: message.role === "user" ? "cyan" : "green" }, message.role === "user" ? "\u{1F464} You" : "\u{1F916} Assistant"), /* @__PURE__ */ React7.createElement(Text6, { dimColor: true }, " \u2022 ", new Date(message.timestamp).toLocaleTimeString())), /* @__PURE__ */ React7.createElement(Box7, { paddingLeft: 2 }, message.metadata?.permissionDenied ? /* @__PURE__ */ React7.createElement(Text6, { color: "yellow" }, "\u26A0\uFE0F ", message.content) : /* @__PURE__ */ React7.createElement(Text6, null, message.content)), message.metadata?.steps && message.metadata.steps.length > 0 && /* @__PURE__ */ React7.createElement(Box7, { paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React7.createElement(Text6, { 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__ */ React7.createElement(Text6, { dimColor: true }, "Step types: ", message.metadata.steps.map((s) => s.type).join(", ")), message.metadata.steps.map((step, idx) => {
826
+ return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React8.createElement(Box8, null, /* @__PURE__ */ React8.createElement(Text7, { bold: true, color: message.role === "user" ? "cyan" : "green" }, message.role === "user" ? "\u{1F464} You" : "\u{1F916} Assistant"), /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, " \u2022 ", new Date(message.timestamp).toLocaleTimeString())), /* @__PURE__ */ React8.createElement(Box8, { paddingLeft: 2 }, message.metadata?.permissionDenied ? /* @__PURE__ */ React8.createElement(Text7, { color: "yellow" }, "\u26A0\uFE0F ", message.content) : /* @__PURE__ */ React8.createElement(Text7, null, message.content)), message.metadata?.steps && message.metadata.steps.length > 0 && /* @__PURE__ */ React8.createElement(Box8, { paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React8.createElement(Text7, { 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__ */ React8.createElement(Text7, { dimColor: true }, "Step types: ", message.metadata.steps.map((s) => s.type).join(", ")), message.metadata.steps.map((step, idx) => {
416
827
  if (step.type === "thought") {
417
- return /* @__PURE__ */ React7.createElement(Box7, { key: idx, paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React7.createElement(Text6, { color: "blue" }, "\u{1F4AD} Thought:"), /* @__PURE__ */ React7.createElement(Text6, { dimColor: true }, ` ${step.content.slice(0, 200)}${step.content.length > 200 ? "..." : ""}`));
828
+ return /* @__PURE__ */ React8.createElement(Box8, { key: idx, paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React8.createElement(Text7, { color: "blue" }, "\u{1F4AD} Thought:"), /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, ` ${step.content.slice(0, 200)}${step.content.length > 200 ? "..." : ""}`));
418
829
  }
419
830
  if (step.type === "action") {
420
831
  const toolName = step.metadata?.toolName || "unknown";
421
832
  const toolInput = step.metadata?.toolInput;
422
833
  const observationStep = message.metadata.steps[idx + 1];
423
834
  const result = observationStep?.type === "observation" ? observationStep.content : null;
424
- return /* @__PURE__ */ React7.createElement(Box7, { key: idx, paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React7.createElement(Text6, { color: "yellow" }, "\u{1F527} Action: ", toolName), toolInput && /* @__PURE__ */ React7.createElement(Text6, { dimColor: true }, ` Input: ${typeof toolInput === "string" ? toolInput : JSON.stringify(toolInput).slice(0, 100)}`), result && /* @__PURE__ */ React7.createElement(Text6, { 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 ? "..." : ""}`));
835
+ return /* @__PURE__ */ React8.createElement(Box8, { key: idx, paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React8.createElement(Text7, { color: "yellow" }, "\u{1F527} Action: ", toolName), toolInput && /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, ` Input: ${typeof toolInput === "string" ? toolInput : JSON.stringify(toolInput).slice(0, 100)}`), result && /* @__PURE__ */ React8.createElement(Text7, { 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 ? "..." : ""}`));
425
836
  }
426
837
  return null;
427
- }).filter(Boolean)), message.metadata?.tokenUsage && (!message.metadata.steps || message.metadata.steps.length === 0) && /* @__PURE__ */ React7.createElement(Box7, { paddingLeft: 2 }, /* @__PURE__ */ React7.createElement(Text6, { dimColor: true }, `${message.metadata.tokenUsage.total} tokens`)));
838
+ }).filter(Boolean)), message.metadata?.tokenUsage && (!message.metadata.steps || message.metadata.steps.length === 0) && /* @__PURE__ */ React8.createElement(Box8, { paddingLeft: 2 }, /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, `${message.metadata.tokenUsage.total} tokens`)));
428
839
  }
429
840
 
430
841
  // src/components/MessageList.tsx
431
- import React8 from "react";
432
- import { Box as Box8, Text as Text7 } from "ink";
842
+ import React9 from "react";
843
+ import { Box as Box9, Text as Text8 } from "ink";
433
844
  function stripThinkingTags(content) {
434
845
  return content.replace(/<think>[\s\S]*?<\/think>/g, "").trim();
435
846
  }
436
- var MessageList = React8.memo(
847
+ var MessageList = React9.memo(
437
848
  function MessageList2({ messages }) {
438
849
  if (messages.length === 0) {
439
- return /* @__PURE__ */ React8.createElement(Box8, { paddingY: 1 }, /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, "No messages yet. Type a message to start!"));
850
+ return /* @__PURE__ */ React9.createElement(Box9, { paddingY: 1 }, /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, "No messages yet. Type a message to start!"));
440
851
  }
441
- return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", gap: 1, paddingY: 1 }, messages.map((message, index) => /* @__PURE__ */ React8.createElement(Box8, { key: index, flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React8.createElement(Box8, null, /* @__PURE__ */ React8.createElement(Text7, { bold: true, color: message.role === "user" ? "cyan" : "green" }, message.role === "user" ? "\u{1F464} You" : "\u{1F916} Assistant"), /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, " \u2022 ", new Date(message.timestamp).toLocaleTimeString())), /* @__PURE__ */ React8.createElement(Box8, { paddingLeft: 2 }, message.metadata?.permissionDenied ? /* @__PURE__ */ React8.createElement(Text7, { color: "yellow" }, "\u26A0\uFE0F ", stripThinkingTags(message.content)) : /* @__PURE__ */ React8.createElement(Text7, null, stripThinkingTags(message.content))), message.metadata?.steps && message.metadata.steps.length > 0 && /* @__PURE__ */ React8.createElement(Box8, { paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React8.createElement(Text7, { 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__ */ React8.createElement(Text7, { dimColor: true }, "Step types: ", message.metadata.steps.map((s) => s.type).join(", ")), message.metadata.steps.map((step, idx) => {
852
+ return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", gap: 1, paddingY: 1 }, messages.map((message, index) => /* @__PURE__ */ React9.createElement(Box9, { key: index, flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React9.createElement(Box9, null, /* @__PURE__ */ React9.createElement(Text8, { bold: true, color: message.role === "user" ? "cyan" : "green" }, message.role === "user" ? "\u{1F464} You" : "\u{1F916} Assistant"), /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, " \u2022 ", new Date(message.timestamp).toLocaleTimeString())), /* @__PURE__ */ React9.createElement(Box9, { paddingLeft: 2 }, message.metadata?.permissionDenied ? /* @__PURE__ */ React9.createElement(Text8, { color: "yellow" }, "\u26A0\uFE0F ", stripThinkingTags(message.content)) : /* @__PURE__ */ React9.createElement(Text8, null, stripThinkingTags(message.content))), message.metadata?.steps && message.metadata.steps.length > 0 && /* @__PURE__ */ React9.createElement(Box9, { paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React9.createElement(Text8, { dimColor: true, bold: true }, "\u{1F527} Agent Reasoning Trace (", message.metadata.steps.filter((s) => s.type === "action").length, " tools used,", " ", message.metadata.steps.length, " total steps)", message.metadata.tokenUsage && ` \u2022 ${message.metadata.tokenUsage.total} tokens`), /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, "Step types: ", message.metadata.steps.map((s) => s.type).join(", ")), message.metadata.steps.map((step, idx) => {
442
853
  if (step.type === "thought") {
443
- return /* @__PURE__ */ React8.createElement(Box8, { key: idx, paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React8.createElement(Text7, { color: "blue" }, "\u{1F4AD} Thought:"), /* @__PURE__ */ React8.createElement(
444
- Text7,
854
+ 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(
855
+ Text8,
445
856
  {
446
857
  dimColor: true
447
858
  },
@@ -453,10 +864,10 @@ var MessageList = React8.memo(
453
864
  const toolInput = step.metadata?.toolInput;
454
865
  const observationStep = message.metadata.steps[idx + 1];
455
866
  const result = observationStep?.type === "observation" ? observationStep.content : null;
456
- return /* @__PURE__ */ React8.createElement(Box8, { key: idx, paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React8.createElement(Text7, { color: "yellow" }, "\u{1F527} Action: ", toolName), toolInput && /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, ` Input: ${typeof toolInput === "string" ? toolInput : JSON.stringify(toolInput).slice(0, 100)}`), result && /* @__PURE__ */ React8.createElement(Text7, { 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 ? "..." : ""}`));
867
+ 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 ? "..." : ""}`));
457
868
  }
458
869
  return null;
459
- }).filter(Boolean)), message.metadata?.tokenUsage && (!message.metadata.steps || message.metadata.steps.length === 0) && /* @__PURE__ */ React8.createElement(Box8, { paddingLeft: 2 }, /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, `${message.metadata.tokenUsage.total} tokens`)))));
870
+ }).filter(Boolean)), message.metadata?.tokenUsage && (!message.metadata.steps || message.metadata.steps.length === 0) && /* @__PURE__ */ React9.createElement(Box9, { paddingLeft: 2 }, /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, `${message.metadata.tokenUsage.total} tokens`)))));
460
871
  },
461
872
  (prevProps, nextProps) => {
462
873
  if (prevProps.messages.length !== nextProps.messages.length) {
@@ -467,8 +878,8 @@ var MessageList = React8.memo(
467
878
  );
468
879
 
469
880
  // src/components/LoginFlow.tsx
470
- import React9, { useState as useState2, useEffect as useEffect2 } from "react";
471
- import { Box as Box9, Text as Text8 } from "ink";
881
+ import React10, { useState as useState2, useEffect as useEffect2 } from "react";
882
+ import { Box as Box10, Text as Text9 } from "ink";
472
883
  import Spinner2 from "ink-spinner";
473
884
  import jwt from "jsonwebtoken";
474
885
  import open from "open";
@@ -578,7 +989,7 @@ var OAuthClient = class {
578
989
  * Sleep for specified milliseconds
579
990
  */
580
991
  sleep(ms) {
581
- return new Promise((resolve) => setTimeout(resolve, ms));
992
+ return new Promise((resolve3) => setTimeout(resolve3, ms));
582
993
  }
583
994
  };
584
995
 
@@ -631,31 +1042,31 @@ function LoginFlow({ apiUrl = "http://localhost:3000", configStore, onSuccess, o
631
1042
  }
632
1043
  }, [deviceFlow, status]);
633
1044
  if (status === "initiating") {
634
- return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React9.createElement(Box9, null, /* @__PURE__ */ React9.createElement(Text8, { color: "cyan" }, /* @__PURE__ */ React9.createElement(Spinner2, { type: "dots" }), " Initiating device authorization...")));
1045
+ return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Text9, { color: "cyan" }, /* @__PURE__ */ React10.createElement(Spinner2, { type: "dots" }), " Initiating device authorization...")));
635
1046
  }
636
1047
  if (status === "error") {
637
- return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React9.createElement(Box9, { marginBottom: 1 }, /* @__PURE__ */ React9.createElement(Text8, { color: "red", bold: true }, "\u2716 Authentication Failed")), /* @__PURE__ */ React9.createElement(Box9, null, /* @__PURE__ */ React9.createElement(Text8, { color: "red" }, error)));
1048
+ return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React10.createElement(Box10, { marginBottom: 1 }, /* @__PURE__ */ React10.createElement(Text9, { color: "red", bold: true }, "\u2716 Authentication Failed")), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Text9, { color: "red" }, error)));
638
1049
  }
639
1050
  if (status === "success") {
640
- return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React9.createElement(Box9, { marginBottom: 1 }, /* @__PURE__ */ React9.createElement(Text8, { color: "green", bold: true }, "\u2714 Successfully authenticated!")), /* @__PURE__ */ React9.createElement(Box9, null, /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, "You can now use B4M CLI with your account.")));
1051
+ return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React10.createElement(Box10, { marginBottom: 1 }, /* @__PURE__ */ React10.createElement(Text9, { color: "green", bold: true }, "\u2714 Successfully authenticated!")), /* @__PURE__ */ React10.createElement(Box10, null, /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, "You can now use B4M CLI with your account.")));
641
1052
  }
642
- return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", padding: 1, borderStyle: "round", borderColor: "cyan" }, /* @__PURE__ */ React9.createElement(Box9, { marginBottom: 1 }, /* @__PURE__ */ React9.createElement(Text8, { color: "cyan", bold: true }, "\u{1F510} Device Authorization")), /* @__PURE__ */ React9.createElement(Box9, { marginBottom: 1 }, /* @__PURE__ */ React9.createElement(Text8, null, "Opening browser automatically... If it doesn't open, please visit:")), /* @__PURE__ */ React9.createElement(Box9, { marginBottom: 1, paddingLeft: 2 }, /* @__PURE__ */ React9.createElement(Text8, { color: "blue", bold: true }, deviceFlow?.verification_uri)), /* @__PURE__ */ React9.createElement(Box9, { marginBottom: 1 }, /* @__PURE__ */ React9.createElement(Text8, null, "And enter this code when prompted:")), /* @__PURE__ */ React9.createElement(Box9, { marginBottom: 1, paddingLeft: 2 }, /* @__PURE__ */ React9.createElement(Text8, { color: "yellow", bold: true }, deviceFlow?.user_code)), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text8, { color: "cyan" }, /* @__PURE__ */ React9.createElement(Spinner2, { type: "dots" }), " ", statusMessage)), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, "Expires in ", deviceFlow ? Math.floor(deviceFlow.expires_in / 60) : 0, " minutes")));
1053
+ return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", padding: 1, borderStyle: "round", borderColor: "cyan" }, /* @__PURE__ */ React10.createElement(Box10, { marginBottom: 1 }, /* @__PURE__ */ React10.createElement(Text9, { color: "cyan", bold: true }, "\u{1F510} Device Authorization")), /* @__PURE__ */ React10.createElement(Box10, { marginBottom: 1 }, /* @__PURE__ */ React10.createElement(Text9, null, "Opening browser automatically... If it doesn't open, please visit:")), /* @__PURE__ */ React10.createElement(Box10, { marginBottom: 1, paddingLeft: 2 }, /* @__PURE__ */ React10.createElement(Text9, { color: "blue", bold: true }, deviceFlow?.verification_uri)), /* @__PURE__ */ React10.createElement(Box10, { marginBottom: 1 }, /* @__PURE__ */ React10.createElement(Text9, null, "And enter this code when prompted:")), /* @__PURE__ */ React10.createElement(Box10, { marginBottom: 1, paddingLeft: 2 }, /* @__PURE__ */ React10.createElement(Text9, { color: "yellow", bold: true }, deviceFlow?.user_code)), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text9, { color: "cyan" }, /* @__PURE__ */ React10.createElement(Spinner2, { type: "dots" }), " ", statusMessage)), /* @__PURE__ */ React10.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, "Expires in ", deviceFlow ? Math.floor(deviceFlow.expires_in / 60) : 0, " minutes")));
643
1054
  }
644
1055
 
645
1056
  // src/storage/SessionStore.ts
646
- import { promises as fs } from "fs";
647
- import path from "path";
1057
+ import { promises as fs3 } from "fs";
1058
+ import path3 from "path";
648
1059
  import { homedir } from "os";
649
1060
  var SessionStore = class {
650
1061
  constructor(basePath) {
651
- this.basePath = basePath || path.join(homedir(), ".bike4mind", "sessions");
1062
+ this.basePath = basePath || path3.join(homedir(), ".bike4mind", "sessions");
652
1063
  }
653
1064
  /**
654
1065
  * Initialize storage directory
655
1066
  */
656
1067
  async init() {
657
1068
  try {
658
- await fs.mkdir(this.basePath, { recursive: true });
1069
+ await fs3.mkdir(this.basePath, { recursive: true });
659
1070
  } catch (error) {
660
1071
  console.error("Failed to initialize session storage:", error);
661
1072
  throw error;
@@ -666,9 +1077,9 @@ var SessionStore = class {
666
1077
  */
667
1078
  async save(session) {
668
1079
  await this.init();
669
- const filePath = path.join(this.basePath, `${session.id}.json`);
1080
+ const filePath = path3.join(this.basePath, `${session.id}.json`);
670
1081
  try {
671
- await fs.writeFile(filePath, JSON.stringify(session, null, 2), "utf-8");
1082
+ await fs3.writeFile(filePath, JSON.stringify(session, null, 2), "utf-8");
672
1083
  } catch (error) {
673
1084
  console.error("Failed to save session:", error);
674
1085
  throw error;
@@ -678,9 +1089,9 @@ var SessionStore = class {
678
1089
  * Load a session from disk by ID
679
1090
  */
680
1091
  async load(id) {
681
- const filePath = path.join(this.basePath, `${id}.json`);
1092
+ const filePath = path3.join(this.basePath, `${id}.json`);
682
1093
  try {
683
- const data = await fs.readFile(filePath, "utf-8");
1094
+ const data = await fs3.readFile(filePath, "utf-8");
684
1095
  return JSON.parse(data);
685
1096
  } catch (error) {
686
1097
  if (error.code === "ENOENT") {
@@ -704,12 +1115,12 @@ var SessionStore = class {
704
1115
  async list() {
705
1116
  await this.init();
706
1117
  try {
707
- const files = await fs.readdir(this.basePath);
1118
+ const files = await fs3.readdir(this.basePath);
708
1119
  const jsonFiles = files.filter((f) => f.endsWith(".json"));
709
1120
  const sessions = await Promise.all(
710
1121
  jsonFiles.map(async (file) => {
711
- const filePath = path.join(this.basePath, file);
712
- const data = await fs.readFile(filePath, "utf-8");
1122
+ const filePath = path3.join(this.basePath, file);
1123
+ const data = await fs3.readFile(filePath, "utf-8");
713
1124
  return JSON.parse(data);
714
1125
  })
715
1126
  );
@@ -723,9 +1134,9 @@ var SessionStore = class {
723
1134
  * Delete a session
724
1135
  */
725
1136
  async delete(id) {
726
- const filePath = path.join(this.basePath, `${id}.json`);
1137
+ const filePath = path3.join(this.basePath, `${id}.json`);
727
1138
  try {
728
- await fs.unlink(filePath);
1139
+ await fs3.unlink(filePath);
729
1140
  return true;
730
1141
  } catch (error) {
731
1142
  if (error.code === "ENOENT") {
@@ -761,8 +1172,8 @@ var SessionStore = class {
761
1172
  };
762
1173
 
763
1174
  // src/storage/ConfigStore.ts
764
- import { promises as fs2 } from "fs";
765
- import path2 from "path";
1175
+ import { promises as fs4 } from "fs";
1176
+ import path4 from "path";
766
1177
  import { homedir as homedir2 } from "os";
767
1178
  import { v4 as uuidv4 } from "uuid";
768
1179
  import { z } from "zod";
@@ -836,15 +1247,15 @@ var DEFAULT_CONFIG = {
836
1247
  var ConfigStore = class {
837
1248
  constructor(configPath) {
838
1249
  this.config = null;
839
- this.configPath = configPath || path2.join(homedir2(), ".bike4mind", "config.json");
1250
+ this.configPath = configPath || path4.join(homedir2(), ".bike4mind", "config.json");
840
1251
  }
841
1252
  /**
842
1253
  * Initialize config directory
843
1254
  */
844
1255
  async init() {
845
- const dir = path2.dirname(this.configPath);
1256
+ const dir = path4.dirname(this.configPath);
846
1257
  try {
847
- await fs2.mkdir(dir, { recursive: true });
1258
+ await fs4.mkdir(dir, { recursive: true });
848
1259
  } catch (error) {
849
1260
  console.error("Failed to initialize config directory:", error);
850
1261
  throw error;
@@ -859,15 +1270,15 @@ var ConfigStore = class {
859
1270
  }
860
1271
  try {
861
1272
  try {
862
- const stats = await fs2.stat(this.configPath);
1273
+ const stats = await fs4.stat(this.configPath);
863
1274
  const mode = stats.mode & 511;
864
1275
  if (mode !== 384) {
865
1276
  console.warn(`\u26A0\uFE0F Config file has insecure permissions (${mode.toString(8)}). Setting to 0600...`);
866
- await fs2.chmod(this.configPath, 384);
1277
+ await fs4.chmod(this.configPath, 384);
867
1278
  }
868
1279
  } catch (statError) {
869
1280
  }
870
- const data = await fs2.readFile(this.configPath, "utf-8");
1281
+ const data = await fs4.readFile(this.configPath, "utf-8");
871
1282
  const rawConfig = JSON.parse(data);
872
1283
  if (rawConfig.apiConfig && "environment" in rawConfig.apiConfig) {
873
1284
  const oldApiConfig = rawConfig.apiConfig;
@@ -940,8 +1351,8 @@ var ConfigStore = class {
940
1351
  throw new Error("No configuration to save");
941
1352
  }
942
1353
  try {
943
- await fs2.writeFile(this.configPath, JSON.stringify(this.config, null, 2), "utf-8");
944
- await fs2.chmod(this.configPath, 384);
1354
+ await fs4.writeFile(this.configPath, JSON.stringify(this.config, null, 2), "utf-8");
1355
+ await fs4.chmod(this.configPath, 384);
945
1356
  } catch (error) {
946
1357
  console.error("Failed to save config:", error);
947
1358
  throw error;
@@ -1088,22 +1499,22 @@ var ConfigStore = class {
1088
1499
  };
1089
1500
 
1090
1501
  // src/storage/CommandHistoryStore.ts
1091
- import { promises as fs3 } from "fs";
1092
- import path3 from "path";
1502
+ import { promises as fs5 } from "fs";
1503
+ import path5 from "path";
1093
1504
  import { homedir as homedir3 } from "os";
1094
1505
  var MAX_HISTORY_ENTRIES = 1e3;
1095
1506
  var CommandHistoryStore = class {
1096
1507
  constructor(historyPath) {
1097
1508
  this.history = null;
1098
- this.historyPath = historyPath || path3.join(homedir3(), ".bike4mind", "history.jsonl");
1509
+ this.historyPath = historyPath || path5.join(homedir3(), ".bike4mind", "history.jsonl");
1099
1510
  }
1100
1511
  /**
1101
1512
  * Initialize history directory
1102
1513
  */
1103
1514
  async init() {
1104
- const dir = path3.dirname(this.historyPath);
1515
+ const dir = path5.dirname(this.historyPath);
1105
1516
  try {
1106
- await fs3.mkdir(dir, { recursive: true });
1517
+ await fs5.mkdir(dir, { recursive: true });
1107
1518
  } catch (error) {
1108
1519
  console.error("Failed to initialize history directory:", error);
1109
1520
  throw error;
@@ -1118,7 +1529,7 @@ var CommandHistoryStore = class {
1118
1529
  return this.history;
1119
1530
  }
1120
1531
  try {
1121
- const data = await fs3.readFile(this.historyPath, "utf-8");
1532
+ const data = await fs5.readFile(this.historyPath, "utf-8");
1122
1533
  const lines = data.trim().split("\n").filter((line) => line.length > 0);
1123
1534
  const entries = lines.map((line) => {
1124
1535
  try {
@@ -1155,7 +1566,7 @@ var CommandHistoryStore = class {
1155
1566
  };
1156
1567
  await this.init();
1157
1568
  const line = JSON.stringify(entry) + "\n";
1158
- await fs3.appendFile(this.historyPath, line, "utf-8");
1569
+ await fs5.appendFile(this.historyPath, line, "utf-8");
1159
1570
  this.history = [command, ...this.history || []];
1160
1571
  if (this.history.length > MAX_HISTORY_ENTRIES) {
1161
1572
  await this.trim();
@@ -1178,7 +1589,7 @@ var CommandHistoryStore = class {
1178
1589
  };
1179
1590
  return JSON.stringify(entry);
1180
1591
  }).join("\n");
1181
- await fs3.writeFile(this.historyPath, lines + "\n", "utf-8");
1592
+ await fs5.writeFile(this.historyPath, lines + "\n", "utf-8");
1182
1593
  this.history = trimmedCommands;
1183
1594
  }
1184
1595
  /**
@@ -1186,7 +1597,7 @@ var CommandHistoryStore = class {
1186
1597
  */
1187
1598
  async clear() {
1188
1599
  try {
1189
- await fs3.unlink(this.historyPath);
1600
+ await fs5.unlink(this.historyPath);
1190
1601
  } catch (error) {
1191
1602
  if (error.code !== "ENOENT") {
1192
1603
  throw error;
@@ -1960,7 +2371,7 @@ import { GoogleGenerativeAI } from "@google/generative-ai";
1960
2371
  import OpenAI2 from "openai";
1961
2372
 
1962
2373
  // ../../b4m-core/packages/services/dist/src/importHistoryService/index.js
1963
- import fs4, { unlinkSync } from "fs";
2374
+ import fs6, { unlinkSync } from "fs";
1964
2375
  import yauzl from "yauzl";
1965
2376
  import axios3 from "axios";
1966
2377
 
@@ -3646,8 +4057,8 @@ async function processAndStoreImages(images, context) {
3646
4057
  const buffer = await downloadImage(image);
3647
4058
  const fileType = await fileTypeFromBuffer2(buffer);
3648
4059
  const filename = `${uuidv45()}.${fileType?.ext}`;
3649
- const path11 = await context.imageGenerateStorage.upload(buffer, filename, {});
3650
- return path11;
4060
+ const path13 = await context.imageGenerateStorage.upload(buffer, filename, {});
4061
+ return path13;
3651
4062
  }));
3652
4063
  }
3653
4064
  async function updateQuestAndReturnMarkdown(storedImageUrls, context) {
@@ -4831,8 +5242,8 @@ async function processAndStoreImage(imageUrl, context) {
4831
5242
  const buffer = await downloadImage2(imageUrl);
4832
5243
  const fileType = await fileTypeFromBuffer3(buffer);
4833
5244
  const filename = `${uuidv46()}.${fileType?.ext}`;
4834
- const path11 = await context.imageGenerateStorage.upload(buffer, filename, {});
4835
- return path11;
5245
+ const path13 = await context.imageGenerateStorage.upload(buffer, filename, {});
5246
+ return path13;
4836
5247
  }
4837
5248
  async function updateQuestAndReturnMarkdown2(storedImagePath, context) {
4838
5249
  await context.onFinish?.("edit_image", storedImagePath);
@@ -6669,33 +7080,33 @@ var planetVisibilityTool = {
6669
7080
  };
6670
7081
 
6671
7082
  // ../../b4m-core/packages/services/dist/src/llm/tools/implementation/fileRead/index.js
6672
- import { promises as fs5 } from "fs";
6673
- import { existsSync, statSync } from "fs";
6674
- import path4 from "path";
6675
- var MAX_FILE_SIZE = 10 * 1024 * 1024;
7083
+ import { promises as fs7 } from "fs";
7084
+ import { existsSync as existsSync2, statSync as statSync3 } from "fs";
7085
+ import path6 from "path";
7086
+ var MAX_FILE_SIZE2 = 10 * 1024 * 1024;
6676
7087
  async function readFileContent(params) {
6677
7088
  const { path: filePath, encoding = "utf-8", maxLines } = params;
6678
- const normalizedPath = path4.normalize(filePath);
6679
- const resolvedPath = path4.resolve(process.cwd(), normalizedPath);
6680
- const cwd = path4.resolve(process.cwd());
7089
+ const normalizedPath = path6.normalize(filePath);
7090
+ const resolvedPath = path6.resolve(process.cwd(), normalizedPath);
7091
+ const cwd = path6.resolve(process.cwd());
6681
7092
  if (!resolvedPath.startsWith(cwd)) {
6682
7093
  throw new Error(`Access denied: Cannot read files outside of current working directory`);
6683
7094
  }
6684
- if (!existsSync(resolvedPath)) {
7095
+ if (!existsSync2(resolvedPath)) {
6685
7096
  throw new Error(`File not found: ${filePath}`);
6686
7097
  }
6687
- const stats = statSync(resolvedPath);
7098
+ const stats = statSync3(resolvedPath);
6688
7099
  if (stats.isDirectory()) {
6689
7100
  throw new Error(`Path is a directory, not a file: ${filePath}`);
6690
7101
  }
6691
- if (stats.size > MAX_FILE_SIZE) {
6692
- throw new Error(`File too large: ${(stats.size / 1024 / 1024).toFixed(2)}MB (max ${MAX_FILE_SIZE / 1024 / 1024}MB)`);
7102
+ if (stats.size > MAX_FILE_SIZE2) {
7103
+ throw new Error(`File too large: ${(stats.size / 1024 / 1024).toFixed(2)}MB (max ${MAX_FILE_SIZE2 / 1024 / 1024}MB)`);
6693
7104
  }
6694
7105
  const isBinary = await checkIfBinary(resolvedPath);
6695
7106
  if (isBinary && encoding === "utf-8") {
6696
7107
  throw new Error(`File appears to be binary. Use encoding 'base64' to read binary files, or specify a different encoding.`);
6697
7108
  }
6698
- const content = await fs5.readFile(resolvedPath, encoding);
7109
+ const content = await fs7.readFile(resolvedPath, encoding);
6699
7110
  if (maxLines && typeof content === "string") {
6700
7111
  const lines = content.split("\n");
6701
7112
  if (lines.length > maxLines) {
@@ -6710,7 +7121,7 @@ ${content}`;
6710
7121
  }
6711
7122
  async function checkIfBinary(filePath) {
6712
7123
  const buffer = Buffer.alloc(8192);
6713
- const fd = await fs5.open(filePath, "r");
7124
+ const fd = await fs7.open(filePath, "r");
6714
7125
  try {
6715
7126
  const { bytesRead } = await fd.read(buffer, 0, 8192, 0);
6716
7127
  const chunk = buffer.slice(0, bytesRead);
@@ -6727,7 +7138,7 @@ var fileReadTool = {
6727
7138
  context.logger.info("\u{1F4C4} FileRead: Reading file", { path: params.path });
6728
7139
  try {
6729
7140
  const content = await readFileContent(params);
6730
- const stats = statSync(path4.resolve(process.cwd(), path4.normalize(params.path)));
7141
+ const stats = statSync3(path6.resolve(process.cwd(), path6.normalize(params.path)));
6731
7142
  context.logger.info("\u2705 FileRead: Success", {
6732
7143
  path: params.path,
6733
7144
  size: stats.size,
@@ -6766,25 +7177,25 @@ var fileReadTool = {
6766
7177
  };
6767
7178
 
6768
7179
  // ../../b4m-core/packages/services/dist/src/llm/tools/implementation/createFile/index.js
6769
- import { promises as fs6 } from "fs";
6770
- import { existsSync as existsSync2 } from "fs";
6771
- import path5 from "path";
7180
+ import { promises as fs8 } from "fs";
7181
+ import { existsSync as existsSync3 } from "fs";
7182
+ import path7 from "path";
6772
7183
  async function createFile(params) {
6773
7184
  const { path: filePath, content, createDirectories = true } = params;
6774
- const normalizedPath = path5.normalize(filePath);
6775
- const resolvedPath = path5.resolve(process.cwd(), normalizedPath);
6776
- const cwd = path5.resolve(process.cwd());
7185
+ const normalizedPath = path7.normalize(filePath);
7186
+ const resolvedPath = path7.resolve(process.cwd(), normalizedPath);
7187
+ const cwd = path7.resolve(process.cwd());
6777
7188
  if (!resolvedPath.startsWith(cwd)) {
6778
7189
  throw new Error(`Access denied: Cannot create files outside of current working directory`);
6779
7190
  }
6780
- const fileExists = existsSync2(resolvedPath);
7191
+ const fileExists = existsSync3(resolvedPath);
6781
7192
  const action = fileExists ? "overwritten" : "created";
6782
7193
  if (createDirectories) {
6783
- const dir = path5.dirname(resolvedPath);
6784
- await fs6.mkdir(dir, { recursive: true });
7194
+ const dir = path7.dirname(resolvedPath);
7195
+ await fs8.mkdir(dir, { recursive: true });
6785
7196
  }
6786
- await fs6.writeFile(resolvedPath, content, "utf-8");
6787
- const stats = await fs6.stat(resolvedPath);
7197
+ await fs8.writeFile(resolvedPath, content, "utf-8");
7198
+ const stats = await fs8.stat(resolvedPath);
6788
7199
  const lines = content.split("\n").length;
6789
7200
  return `File ${action} successfully: ${filePath}
6790
7201
  Size: ${stats.size} bytes
@@ -6795,7 +7206,7 @@ var createFileTool = {
6795
7206
  implementation: (context) => ({
6796
7207
  toolFn: async (value) => {
6797
7208
  const params = value;
6798
- const fileExists = existsSync2(path5.resolve(process.cwd(), path5.normalize(params.path)));
7209
+ const fileExists = existsSync3(path7.resolve(process.cwd(), path7.normalize(params.path)));
6799
7210
  context.logger.info(`\u{1F4DD} CreateFile: ${fileExists ? "Overwriting" : "Creating"} file`, {
6800
7211
  path: params.path,
6801
7212
  size: params.content.length
@@ -6836,8 +7247,8 @@ var createFileTool = {
6836
7247
 
6837
7248
  // ../../b4m-core/packages/services/dist/src/llm/tools/implementation/globFiles/index.js
6838
7249
  import { readdir } from "fs/promises";
6839
- import { statSync as statSync2 } from "fs";
6840
- import path6 from "path";
7250
+ import { statSync as statSync4 } from "fs";
7251
+ import path8 from "path";
6841
7252
  function matchGlob(filePath, pattern) {
6842
7253
  let regexPattern = pattern.replace(/\./g, "\\.").replace(/\*\*/g, "{{GLOBSTAR}}").replace(/\*/g, "[^/]*").replace(/\?/g, ".").replace(/\{([^}]+)\}/g, (_, options) => `(${options.split(",").join("|")})`).replace(/\[([^\]]+)\]/g, "[$1]");
6843
7254
  regexPattern = regexPattern.replace(/\{\{GLOBSTAR\}\}\//g, "(.*/)?").replace(/\/\{\{GLOBSTAR\}\}/g, "(/.*)?").replace(/\{\{GLOBSTAR\}\}/g, ".*");
@@ -6855,8 +7266,8 @@ async function walkDir(dir, pattern, includeHidden, maxResults, basePath = "") {
6855
7266
  if (!includeHidden && entry.name.startsWith(".")) {
6856
7267
  continue;
6857
7268
  }
6858
- const relativePath = basePath ? path6.join(basePath, entry.name) : entry.name;
6859
- const fullPath = path6.join(dir, entry.name);
7269
+ const relativePath = basePath ? path8.join(basePath, entry.name) : entry.name;
7270
+ const fullPath = path8.join(dir, entry.name);
6860
7271
  if (matchGlob(relativePath, pattern)) {
6861
7272
  matches.push(relativePath);
6862
7273
  }
@@ -6872,7 +7283,7 @@ async function walkDir(dir, pattern, includeHidden, maxResults, basePath = "") {
6872
7283
  async function listFiles(params) {
6873
7284
  const { pattern, cwd: relativeCwd, includeHidden = false, maxResults = 1e3 } = params;
6874
7285
  const baseCwd = process.cwd();
6875
- const targetCwd = relativeCwd ? path6.resolve(baseCwd, path6.normalize(relativeCwd)) : baseCwd;
7286
+ const targetCwd = relativeCwd ? path8.resolve(baseCwd, path8.normalize(relativeCwd)) : baseCwd;
6876
7287
  if (!targetCwd.startsWith(baseCwd)) {
6877
7288
  throw new Error(`Access denied: Cannot list files outside of current working directory`);
6878
7289
  }
@@ -6883,8 +7294,8 @@ async function listFiles(params) {
6883
7294
  const filesInfo = [];
6884
7295
  for (const match of matches) {
6885
7296
  try {
6886
- const fullPath = path6.join(targetCwd, match);
6887
- const stats = statSync2(fullPath);
7297
+ const fullPath = path8.join(targetCwd, match);
7298
+ const stats = statSync4(fullPath);
6888
7299
  filesInfo.push({
6889
7300
  path: match,
6890
7301
  size: stats.size,
@@ -6965,9 +7376,9 @@ var globFilesTool = {
6965
7376
 
6966
7377
  // ../../b4m-core/packages/services/dist/src/llm/tools/implementation/grepSearch/index.js
6967
7378
  import { readdir as readdir2 } from "fs/promises";
6968
- import { readFileSync, statSync as statSync3 } from "fs";
6969
- import path7 from "path";
6970
- var MAX_FILE_SIZE2 = 10 * 1024 * 1024;
7379
+ import { readFileSync as readFileSync2, statSync as statSync5 } from "fs";
7380
+ import path9 from "path";
7381
+ var MAX_FILE_SIZE3 = 10 * 1024 * 1024;
6971
7382
  function matchGlob2(filePath, pattern) {
6972
7383
  const regexPattern = pattern.replace(/\./g, "\\.").replace(/\*\*/g, "{{GLOBSTAR}}").replace(/\*/g, "[^/]*").replace(/\{\{GLOBSTAR\}\}/g, ".*").replace(/\?/g, ".").replace(/\{([^}]+)\}/g, (_, options) => `(${options.split(",").join("|")})`).replace(/\[([^\]]+)\]/g, "[$1]");
6973
7384
  const regex = new RegExp(`^${regexPattern}$`);
@@ -6984,8 +7395,8 @@ async function walkDir2(dir, pattern, maxResults, basePath = "") {
6984
7395
  if (entry.name.startsWith(".")) {
6985
7396
  continue;
6986
7397
  }
6987
- const relativePath = basePath ? path7.join(basePath, entry.name) : entry.name;
6988
- const fullPath = path7.join(dir, entry.name);
7398
+ const relativePath = basePath ? path9.join(basePath, entry.name) : entry.name;
7399
+ const fullPath = path9.join(dir, entry.name);
6989
7400
  if (matchGlob2(relativePath, pattern)) {
6990
7401
  matches.push(relativePath);
6991
7402
  }
@@ -6998,10 +7409,10 @@ async function walkDir2(dir, pattern, maxResults, basePath = "") {
6998
7409
  }
6999
7410
  return matches;
7000
7411
  }
7001
- async function searchFiles(params) {
7412
+ async function searchFiles2(params) {
7002
7413
  const { pattern, filePattern = "**/*", cwd: relativeCwd, caseSensitive = false, maxResults = 100, contextLines = 0 } = params;
7003
7414
  const baseCwd = process.cwd();
7004
- const targetCwd = relativeCwd ? path7.resolve(baseCwd, path7.normalize(relativeCwd)) : baseCwd;
7415
+ const targetCwd = relativeCwd ? path9.resolve(baseCwd, path9.normalize(relativeCwd)) : baseCwd;
7005
7416
  if (!targetCwd.startsWith(baseCwd)) {
7006
7417
  throw new Error(`Access denied: Cannot search files outside of current working directory`);
7007
7418
  }
@@ -7015,13 +7426,13 @@ async function searchFiles(params) {
7015
7426
  const filesToSearch = await walkDir2(targetCwd, filePattern, 1e4);
7016
7427
  const filteredFiles = [];
7017
7428
  for (const match of filesToSearch) {
7018
- const fullPath = path7.join(targetCwd, match);
7429
+ const fullPath = path9.join(targetCwd, match);
7019
7430
  try {
7020
- const stats = statSync3(fullPath);
7021
- if (stats.isDirectory() || stats.size > MAX_FILE_SIZE2) {
7431
+ const stats = statSync5(fullPath);
7432
+ if (stats.isDirectory() || stats.size > MAX_FILE_SIZE3) {
7022
7433
  continue;
7023
7434
  }
7024
- if (isBinaryFile(fullPath)) {
7435
+ if (isBinaryFile2(fullPath)) {
7025
7436
  continue;
7026
7437
  }
7027
7438
  filteredFiles.push(match);
@@ -7039,9 +7450,9 @@ async function searchFiles(params) {
7039
7450
  break;
7040
7451
  }
7041
7452
  filesSearched++;
7042
- const fullPath = path7.join(targetCwd, file);
7453
+ const fullPath = path9.join(targetCwd, file);
7043
7454
  try {
7044
- const content = readFileSync(fullPath, "utf-8");
7455
+ const content = readFileSync2(fullPath, "utf-8");
7045
7456
  const lines = content.split("\n");
7046
7457
  for (let i = 0; i < lines.length; i++) {
7047
7458
  if (matches.length >= maxResults) {
@@ -7105,7 +7516,7 @@ ${match.context.after.map((l) => ` ${l}`).join("\n")}`;
7105
7516
  }).join("\n");
7106
7517
  return `${summary}${patternInfo}${cwdInfo}${matchesList}`;
7107
7518
  }
7108
- function isBinaryFile(filePath) {
7519
+ function isBinaryFile2(filePath) {
7109
7520
  try {
7110
7521
  const buffer = Buffer.alloc(8192);
7111
7522
  const fd = __require("fs").openSync(filePath, "r");
@@ -7128,7 +7539,7 @@ var grepSearchTool = {
7128
7539
  cwd: params.cwd || "."
7129
7540
  });
7130
7541
  try {
7131
- const result = await searchFiles(params);
7542
+ const result = await searchFiles2(params);
7132
7543
  context.logger.info("\u2705 GrepSearch: Success");
7133
7544
  return result;
7134
7545
  } catch (error) {
@@ -7174,31 +7585,31 @@ var grepSearchTool = {
7174
7585
  };
7175
7586
 
7176
7587
  // ../../b4m-core/packages/services/dist/src/llm/tools/implementation/deleteFile/index.js
7177
- import { promises as fs7 } from "fs";
7178
- import { existsSync as existsSync3, statSync as statSync4 } from "fs";
7179
- import path8 from "path";
7588
+ import { promises as fs9 } from "fs";
7589
+ import { existsSync as existsSync4, statSync as statSync6 } from "fs";
7590
+ import path10 from "path";
7180
7591
  async function deleteFile(params) {
7181
7592
  const { path: filePath, recursive = false } = params;
7182
- const normalizedPath = path8.normalize(filePath);
7183
- const resolvedPath = path8.resolve(process.cwd(), normalizedPath);
7184
- const cwd = path8.resolve(process.cwd());
7593
+ const normalizedPath = path10.normalize(filePath);
7594
+ const resolvedPath = path10.resolve(process.cwd(), normalizedPath);
7595
+ const cwd = path10.resolve(process.cwd());
7185
7596
  if (!resolvedPath.startsWith(cwd)) {
7186
7597
  throw new Error(`Access denied: Cannot delete files outside of current working directory`);
7187
7598
  }
7188
- if (!existsSync3(resolvedPath)) {
7599
+ if (!existsSync4(resolvedPath)) {
7189
7600
  throw new Error(`File or directory not found: ${filePath}`);
7190
7601
  }
7191
- const stats = statSync4(resolvedPath);
7602
+ const stats = statSync6(resolvedPath);
7192
7603
  const isDirectory = stats.isDirectory();
7193
7604
  const size = stats.size;
7194
7605
  if (isDirectory && !recursive) {
7195
7606
  throw new Error(`Path is a directory: ${filePath}. Use recursive=true to delete directories and their contents.`);
7196
7607
  }
7197
7608
  if (isDirectory) {
7198
- await fs7.rm(resolvedPath, { recursive: true, force: true });
7609
+ await fs9.rm(resolvedPath, { recursive: true, force: true });
7199
7610
  return `Directory deleted successfully: ${filePath}`;
7200
7611
  } else {
7201
- await fs7.unlink(resolvedPath);
7612
+ await fs9.unlink(resolvedPath);
7202
7613
  return `File deleted successfully: ${filePath}
7203
7614
  Size: ${size} bytes`;
7204
7615
  }
@@ -7208,8 +7619,8 @@ var deleteFileTool = {
7208
7619
  implementation: (context) => ({
7209
7620
  toolFn: async (value) => {
7210
7621
  const params = value;
7211
- const resolvedPath = path8.resolve(process.cwd(), path8.normalize(params.path));
7212
- const isDirectory = existsSync3(resolvedPath) && statSync4(resolvedPath).isDirectory();
7622
+ const resolvedPath = path10.resolve(process.cwd(), path10.normalize(params.path));
7623
+ const isDirectory = existsSync4(resolvedPath) && statSync6(resolvedPath).isDirectory();
7213
7624
  context.logger.info(`\u{1F5D1}\uFE0F DeleteFile: Deleting ${isDirectory ? "directory" : "file"}`, {
7214
7625
  path: params.path,
7215
7626
  recursive: params.recursive
@@ -7499,10 +7910,10 @@ import jwt2 from "jsonwebtoken";
7499
7910
  // src/utils/diffPreview.ts
7500
7911
  import * as Diff from "diff";
7501
7912
  import { readFile } from "fs/promises";
7502
- import { existsSync as existsSync4 } from "fs";
7913
+ import { existsSync as existsSync5 } from "fs";
7503
7914
  async function generateFileDiffPreview(args) {
7504
7915
  try {
7505
- if (!existsSync4(args.path)) {
7916
+ if (!existsSync5(args.path)) {
7506
7917
  const lines2 = args.content.split("\n");
7507
7918
  const preview = lines2.slice(0, 20).join("\n");
7508
7919
  const hasMore = lines2.length > 20;
@@ -7532,10 +7943,10 @@ ${preview}${hasMore ? `
7532
7943
  }
7533
7944
  async function generateFileDeletePreview(args) {
7534
7945
  try {
7535
- if (!existsSync4(args.path)) {
7946
+ if (!existsSync5(args.path)) {
7536
7947
  return `[File does not exist: ${args.path}]`;
7537
7948
  }
7538
- const stats = await import("fs/promises").then((fs9) => fs9.stat(args.path));
7949
+ const stats = await import("fs/promises").then((fs11) => fs11.stat(args.path));
7539
7950
  return `[File will be deleted]
7540
7951
 
7541
7952
  Path: ${args.path}
@@ -7551,21 +7962,21 @@ var NoOpStorage = class extends BaseStorage {
7551
7962
  async upload(input, destination, options) {
7552
7963
  return `/tmp/${destination}`;
7553
7964
  }
7554
- async download(path11) {
7965
+ async download(path13) {
7555
7966
  throw new Error("Download not supported in CLI");
7556
7967
  }
7557
- async delete(path11) {
7968
+ async delete(path13) {
7558
7969
  }
7559
- async getSignedUrl(path11) {
7560
- return `/tmp/${path11}`;
7970
+ async getSignedUrl(path13) {
7971
+ return `/tmp/${path13}`;
7561
7972
  }
7562
- getPublicUrl(path11) {
7563
- return `/tmp/${path11}`;
7973
+ getPublicUrl(path13) {
7974
+ return `/tmp/${path13}`;
7564
7975
  }
7565
- async getPreview(path11) {
7566
- return `/tmp/${path11}`;
7976
+ async getPreview(path13) {
7977
+ return `/tmp/${path13}`;
7567
7978
  }
7568
- async getMetadata(path11) {
7979
+ async getMetadata(path13) {
7569
7980
  return { size: 0, contentType: "application/octet-stream" };
7570
7981
  }
7571
7982
  };
@@ -7891,8 +8302,8 @@ function getEnvironmentName(configApiConfig) {
7891
8302
  }
7892
8303
 
7893
8304
  // src/utils/Logger.ts
7894
- import fs8 from "fs/promises";
7895
- import path9 from "path";
8305
+ import fs10 from "fs/promises";
8306
+ import path11 from "path";
7896
8307
  import os from "os";
7897
8308
  var Logger2 = class _Logger {
7898
8309
  constructor() {
@@ -7915,9 +8326,9 @@ var Logger2 = class _Logger {
7915
8326
  */
7916
8327
  async initialize(sessionId) {
7917
8328
  this.sessionId = sessionId;
7918
- const debugDir = path9.join(os.homedir(), ".bike4mind", "debug");
7919
- await fs8.mkdir(debugDir, { recursive: true });
7920
- this.logFilePath = path9.join(debugDir, `${sessionId}.txt`);
8329
+ const debugDir = path11.join(os.homedir(), ".bike4mind", "debug");
8330
+ await fs10.mkdir(debugDir, { recursive: true });
8331
+ this.logFilePath = path11.join(debugDir, `${sessionId}.txt`);
7921
8332
  await this.writeToFile("INFO", "=== CLI SESSION START ===");
7922
8333
  }
7923
8334
  /**
@@ -7981,7 +8392,7 @@ var Logger2 = class _Logger {
7981
8392
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").substring(0, 19);
7982
8393
  const logEntry = `[${timestamp}] [${level}] ${message}
7983
8394
  `;
7984
- await fs8.appendFile(this.logFilePath, logEntry, "utf-8");
8395
+ await fs10.appendFile(this.logFilePath, logEntry, "utf-8");
7985
8396
  } catch (error) {
7986
8397
  console.error("File logging failed:", error);
7987
8398
  }
@@ -8127,15 +8538,15 @@ var Logger2 = class _Logger {
8127
8538
  async cleanupOldLogs() {
8128
8539
  if (!this.fileLoggingEnabled) return;
8129
8540
  try {
8130
- const debugDir = path9.join(os.homedir(), ".bike4mind", "debug");
8131
- const files = await fs8.readdir(debugDir);
8541
+ const debugDir = path11.join(os.homedir(), ".bike4mind", "debug");
8542
+ const files = await fs10.readdir(debugDir);
8132
8543
  const now = Date.now();
8133
8544
  const thirtyDaysAgo = now - 30 * 24 * 60 * 60 * 1e3;
8134
8545
  for (const file of files) {
8135
- const filePath = path9.join(debugDir, file);
8136
- const stats = await fs8.stat(filePath);
8546
+ const filePath = path11.join(debugDir, file);
8547
+ const stats = await fs10.stat(filePath);
8137
8548
  if (stats.mtime.getTime() < thirtyDaysAgo) {
8138
- await fs8.unlink(filePath);
8549
+ await fs10.unlink(filePath);
8139
8550
  }
8140
8551
  }
8141
8552
  } catch (error) {
@@ -8148,8 +8559,8 @@ var logger = Logger2.getInstance();
8148
8559
  // ../../b4m-core/packages/mcp/dist/src/client.js
8149
8560
  import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
8150
8561
  import { Client as Client2 } from "@modelcontextprotocol/sdk/client/index.js";
8151
- import path10 from "path";
8152
- import { existsSync as existsSync5, readdirSync } from "fs";
8562
+ import path12 from "path";
8563
+ import { existsSync as existsSync6, readdirSync as readdirSync3 } from "fs";
8153
8564
  var MCPClient = class {
8154
8565
  // Note: This class handles MCP server communication with repository filtering
8155
8566
  mcp;
@@ -8174,20 +8585,20 @@ var MCPClient = class {
8174
8585
  const root = process.env.INIT_CWD || process.cwd();
8175
8586
  const candidatePaths = [
8176
8587
  // When running from SST Lambda with node_modules structure (copyFiles)
8177
- path10.join(root, `node_modules/@bike4mind/mcp/dist/src/${this.serverName}/index.js`),
8588
+ path12.join(root, `node_modules/@bike4mind/mcp/dist/src/${this.serverName}/index.js`),
8178
8589
  // When running from SST Lambda deployed environment (/var/task)
8179
- path10.join(root, `b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
8590
+ path12.join(root, `b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
8180
8591
  // When running from SST Lambda (.sst/artifacts/mcpHandler-dev), navigate to monorepo root (3 levels up)
8181
- path10.join(root, `../../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
8592
+ path12.join(root, `../../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
8182
8593
  // When running from packages/client (Next.js app), navigate to monorepo root (2 levels up)
8183
- path10.join(root, `../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
8594
+ path12.join(root, `../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
8184
8595
  // Original paths (backward compatibility)
8185
- path10.join(root, `/b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
8186
- path10.join(root, "core", "mcp", "servers", this.serverName, "dist", "index.js")
8596
+ path12.join(root, `/b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
8597
+ path12.join(root, "core", "mcp", "servers", this.serverName, "dist", "index.js")
8187
8598
  ];
8188
- const serverScriptPath = candidatePaths.find((p) => existsSync5(p));
8599
+ const serverScriptPath = candidatePaths.find((p) => existsSync6(p));
8189
8600
  if (!serverScriptPath) {
8190
- const getDirectories = (source) => readdirSync(source, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
8601
+ const getDirectories = (source) => readdirSync3(source, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
8191
8602
  console.error(`[MCP] Server script not found. Tried paths:`, candidatePaths);
8192
8603
  console.error(`[MCP] Available directories in ${root}:`, getDirectories(root));
8193
8604
  throw new Error(`MCP Server script path not found for ${this.serverName}. Root: ${root}, Available dirs: ${getDirectories(root).join(", ")}`);
@@ -8216,7 +8627,7 @@ var MCPClient = class {
8216
8627
  }
8217
8628
  };
8218
8629
  await this.mcp.connect(this.transport);
8219
- await new Promise((resolve) => setTimeout(resolve, 100));
8630
+ await new Promise((resolve3) => setTimeout(resolve3, 100));
8220
8631
  const toolsResult = await this.mcp.listTools();
8221
8632
  this.tools = toolsResult.tools.map((tool) => {
8222
8633
  return {
@@ -8399,7 +8810,7 @@ var ServerLlmBackend = class {
8399
8810
  */
8400
8811
  async complete(model, messages, options, callback) {
8401
8812
  logger.debug(`[ServerLlmBackend] Starting complete() with model: ${model}`);
8402
- return new Promise(async (resolve, reject) => {
8813
+ return new Promise(async (resolve3, reject) => {
8403
8814
  try {
8404
8815
  logger.debug("[ServerLlmBackend] Making streaming request...");
8405
8816
  const response = await this.makeStreamingRequest(model, messages, options);
@@ -8429,15 +8840,15 @@ var ServerLlmBackend = class {
8429
8840
  reject(err);
8430
8841
  }).then(() => {
8431
8842
  logger.debug("[ServerLlmBackend] Callback completed, resolving");
8432
- resolve();
8843
+ resolve3();
8433
8844
  });
8434
8845
  } else if (cleanedText) {
8435
8846
  callback([cleanedText], lastUsageInfo).catch((err) => {
8436
8847
  logger.error("[ServerLlmBackend] Callback error:", err);
8437
8848
  reject(err);
8438
- }).then(() => resolve());
8849
+ }).then(() => resolve3());
8439
8850
  } else {
8440
- resolve();
8851
+ resolve3();
8441
8852
  }
8442
8853
  return;
8443
8854
  }
@@ -8497,7 +8908,7 @@ var ServerLlmBackend = class {
8497
8908
  response.data.on("end", () => {
8498
8909
  if (!receivedDone) {
8499
8910
  logger.debug("[ServerLlmBackend] Stream ended without [DONE], resolving anyway");
8500
- resolve();
8911
+ resolve3();
8501
8912
  } else {
8502
8913
  logger.debug("[ServerLlmBackend] Stream ended, [DONE] handler will resolve");
8503
8914
  }
@@ -8761,10 +9172,13 @@ var ApiClient = class {
8761
9172
  }
8762
9173
  };
8763
9174
 
9175
+ // src/index.tsx
9176
+ import { isAxiosError as isAxiosError2 } from "axios";
9177
+
8764
9178
  // package.json
8765
9179
  var package_default = {
8766
9180
  name: "@bike4mind/cli",
8767
- version: "0.2.1-quest-file-uploads.17007+7890a35e3",
9181
+ version: "0.2.2",
8768
9182
  type: "module",
8769
9183
  description: "Interactive CLI tool for Bike4Mind with ReAct agents",
8770
9184
  license: "UNLICENSED",
@@ -8775,6 +9189,9 @@ var package_default = {
8775
9189
  },
8776
9190
  homepage: "https://github.com/bike4mind/lumina5#readme",
8777
9191
  bugs: "https://github.com/bike4mind/lumina5/issues",
9192
+ publishConfig: {
9193
+ access: "public"
9194
+ },
8778
9195
  keywords: [
8779
9196
  "cli",
8780
9197
  "ai",
@@ -8795,6 +9212,8 @@ var package_default = {
8795
9212
  dev: "tsx src/index.tsx",
8796
9213
  build: "tsup",
8797
9214
  typecheck: "tsc --noEmit",
9215
+ test: "vitest run",
9216
+ "test:watch": "vitest",
8798
9217
  start: "node dist/index.js",
8799
9218
  prepublishOnly: "pnpm build"
8800
9219
  },
@@ -8860,11 +9279,11 @@ var package_default = {
8860
9279
  zustand: "^4.5.4"
8861
9280
  },
8862
9281
  devDependencies: {
8863
- "@bike4mind/agents": "0.1.0",
8864
- "@bike4mind/common": "2.36.1-quest-file-uploads.17007+7890a35e3",
8865
- "@bike4mind/mcp": "1.19.4-quest-file-uploads.17007+7890a35e3",
8866
- "@bike4mind/services": "2.29.1-quest-file-uploads.17007+7890a35e3",
8867
- "@bike4mind/utils": "2.0.3-quest-file-uploads.17007+7890a35e3",
9282
+ "@bike4mind/agents": "workspace:*",
9283
+ "@bike4mind/common": "workspace:*",
9284
+ "@bike4mind/mcp": "workspace:*",
9285
+ "@bike4mind/services": "workspace:*",
9286
+ "@bike4mind/utils": "workspace:*",
8868
9287
  "@types/diff": "^5.0.9",
8869
9288
  "@types/jsonwebtoken": "^9.0.4",
8870
9289
  "@types/node": "^22.9.0",
@@ -8873,11 +9292,16 @@ var package_default = {
8873
9292
  "@types/yargs": "^17.0.32",
8874
9293
  tsup: "^8.5.1",
8875
9294
  tsx: "^4.21.0",
8876
- typescript: "^5.9.3"
8877
- },
8878
- gitHead: "7890a35e398acb5486db66d00e5f4173ded0e74e"
9295
+ typescript: "^5.9.3",
9296
+ vitest: "^3.2.4"
9297
+ }
8879
9298
  };
8880
9299
 
9300
+ // src/config/constants.ts
9301
+ var USAGE_DAYS = 30;
9302
+ var MODEL_NAME_COLUMN_WIDTH = 18;
9303
+ var USAGE_CACHE_TTL = 5 * 60 * 1e3;
9304
+
8881
9305
  // src/index.tsx
8882
9306
  process.removeAllListeners("warning");
8883
9307
  process.on("warning", (warning) => {
@@ -8888,6 +9312,7 @@ process.on("warning", (warning) => {
8888
9312
  });
8889
9313
  var exitTimestamp = null;
8890
9314
  var EXIT_TIMEOUT_MS = 2e3;
9315
+ var usageCache = null;
8891
9316
  function CliApp() {
8892
9317
  const { exit } = useApp();
8893
9318
  const [state, setState] = useState3({
@@ -8927,7 +9352,7 @@ function CliApp() {
8927
9352
  }
8928
9353
  await Promise.race([
8929
9354
  Promise.all(cleanupTasks),
8930
- new Promise((resolve) => setTimeout(resolve, 500))
9355
+ new Promise((resolve3) => setTimeout(resolve3, 500))
8931
9356
  // 500ms timeout
8932
9357
  ]);
8933
9358
  setTimeout(() => {
@@ -9061,9 +9486,9 @@ function CliApp() {
9061
9486
  };
9062
9487
  const permissionManager = new PermissionManager(config.trustedTools || []);
9063
9488
  const promptFn = (toolName, args, preview) => {
9064
- return new Promise((resolve) => {
9489
+ return new Promise((resolve3) => {
9065
9490
  const canBeTrusted = permissionManager.canBeTrusted(toolName);
9066
- const prompt = { toolName, args, preview, canBeTrusted, resolve };
9491
+ const prompt = { toolName, args, preview, canBeTrusted, resolve: resolve3 };
9067
9492
  setState((prev) => ({
9068
9493
  ...prev,
9069
9494
  permissionManager,
@@ -9137,7 +9562,7 @@ Remember: Use context from previous messages to understand follow-up questions.`
9137
9562
  llm,
9138
9563
  model: modelInfo.id,
9139
9564
  tools: allTools,
9140
- maxIterations: 3,
9565
+ maxIterations: 10,
9141
9566
  maxTokens: config.preferences.maxTokens,
9142
9567
  temperature: config.preferences.temperature,
9143
9568
  systemPrompt: cliSystemPrompt
@@ -9252,6 +9677,7 @@ Available commands:
9252
9677
  /login - Authenticate with your B4M account
9253
9678
  /logout - Clear authentication and sign out
9254
9679
  /whoami - Show current authenticated user
9680
+ /usage - Show credit usage and balance
9255
9681
  /save <name> - Save current session
9256
9682
  /sessions - List saved sessions
9257
9683
  /config - Show configuration
@@ -9422,17 +9848,114 @@ Tool Permissions:
9422
9848
  console.log(`Expires: ${new Date(authTokens.expiresAt).toLocaleString()}`);
9423
9849
  console.log("");
9424
9850
  break;
9851
+ case "usage": {
9852
+ const usageAuthTokens = await state.configStore.getAuthTokens();
9853
+ if (!usageAuthTokens || new Date(usageAuthTokens.expiresAt) <= /* @__PURE__ */ new Date()) {
9854
+ console.log("\nNot authenticated. Run /login to authenticate.\n");
9855
+ return;
9856
+ }
9857
+ console.log("\nFetching usage data...");
9858
+ const now = Date.now();
9859
+ let currentCredits;
9860
+ let transactions;
9861
+ if (usageCache && now - usageCache.timestamp < USAGE_CACHE_TTL) {
9862
+ currentCredits = usageCache.data.currentCredits;
9863
+ transactions = usageCache.data.transactions;
9864
+ console.log("(using cached data)\n");
9865
+ } else {
9866
+ try {
9867
+ const config = await state.configStore.get();
9868
+ const apiBaseURL = getApiUrl(config.apiConfig);
9869
+ const apiClient = new ApiClient(apiBaseURL, state.configStore);
9870
+ const [identifyResponse, transactionsResponse] = await Promise.all([
9871
+ apiClient.get("/api/identify"),
9872
+ apiClient.get(`/api/credits/transactions?days=${USAGE_DAYS}`)
9873
+ ]);
9874
+ currentCredits = identifyResponse.user.currentCredits;
9875
+ transactions = transactionsResponse || [];
9876
+ usageCache = {
9877
+ data: { currentCredits, transactions },
9878
+ timestamp: now
9879
+ };
9880
+ } catch (error) {
9881
+ if (isAxiosError2(error)) {
9882
+ if (error.response?.status === 401) {
9883
+ console.log("\n\u274C Authentication failed. Run /login to re-authenticate.\n");
9884
+ } else if (error.response?.status === 403) {
9885
+ console.log("\n\u274C Access denied. You may not have permission to view usage data.\n");
9886
+ } else if (error.response?.status === 404) {
9887
+ console.log("\n\u274C Usage endpoint not available on this server.\n");
9888
+ } else if (error.code === "ECONNREFUSED" || error.code === "ENOTFOUND") {
9889
+ console.log("\n\u274C Cannot connect to server. Check your API configuration with /api-info\n");
9890
+ } else {
9891
+ console.log(`
9892
+ \u274C Error fetching usage data: ${error.message}
9893
+ `);
9894
+ }
9895
+ } else if (error instanceof Error) {
9896
+ console.log(`
9897
+ \u274C Error: ${error.message}
9898
+ `);
9899
+ } else {
9900
+ console.log("\n\u274C Unexpected error fetching usage data. Please try again.\n");
9901
+ }
9902
+ break;
9903
+ }
9904
+ }
9905
+ const deductTransactions = transactions.filter(
9906
+ (t) => CREDIT_DEDUCT_TRANSACTION_TYPES.includes(t.type)
9907
+ );
9908
+ const totalCreditsUsed = deductTransactions.reduce((sum2, t) => sum2 + Math.abs(t.credits), 0);
9909
+ const dailyBurnRate = Math.round(totalCreditsUsed / USAGE_DAYS);
9910
+ let daysRemainingStr;
9911
+ if (dailyBurnRate === 0) {
9912
+ daysRemainingStr = "N/A (no usage)";
9913
+ } else {
9914
+ const daysRemaining = Math.floor(currentCredits / dailyBurnRate);
9915
+ daysRemainingStr = `~${daysRemaining.toLocaleString()} days`;
9916
+ }
9917
+ const usageByModel = {};
9918
+ for (const t of deductTransactions) {
9919
+ const modelName = t.metadata?.modelName || ("model" in t ? t.model : null) || "Unknown";
9920
+ usageByModel[modelName] = (usageByModel[modelName] || 0) + Math.abs(t.credits);
9921
+ }
9922
+ const sortedModels = Object.entries(usageByModel).sort((a, b) => b[1] - a[1]);
9923
+ console.log("\n Credit Usage Summary");
9924
+ console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n");
9925
+ console.log(`Credits Balance: ${currentCredits.toLocaleString()}`);
9926
+ console.log(`Daily Burn Rate: ${dailyBurnRate.toLocaleString()} credits/day`);
9927
+ console.log(`Days Remaining: ${daysRemainingStr}`);
9928
+ if (currentCredits === 0) {
9929
+ console.log("\n\u26A0\uFE0F You have no credits remaining.");
9930
+ console.log("\u{1F4A1} Visit bike4mind.io to purchase more credits.\n");
9931
+ break;
9932
+ }
9933
+ if (sortedModels.length > 0) {
9934
+ console.log(`
9935
+ Usage by Model (Last ${USAGE_DAYS} days):`);
9936
+ for (const [model, credits] of sortedModels) {
9937
+ const percentage = totalCreditsUsed > 0 ? Math.round(credits / totalCreditsUsed * 100) : 0;
9938
+ const paddedModel = model.padEnd(MODEL_NAME_COLUMN_WIDTH);
9939
+ console.log(` ${paddedModel}${credits.toLocaleString()} credits (${percentage}%)`);
9940
+ }
9941
+ } else {
9942
+ console.log(`
9943
+ No usage data available for the last ${USAGE_DAYS} days.`);
9944
+ }
9945
+ console.log("");
9946
+ break;
9947
+ }
9425
9948
  default:
9426
9949
  console.log(`Unknown command: /${command}`);
9427
9950
  console.log("Type /help for available commands");
9428
9951
  }
9429
9952
  };
9430
9953
  if (initError) {
9431
- return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React10.createElement(Text9, { color: "red", bold: true }, "\u274C Initialization Error"), /* @__PURE__ */ React10.createElement(Text9, null, initError), /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, "\n", "Tip: Run /config to set up your API keys"));
9954
+ return /* @__PURE__ */ React11.createElement(Box11, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React11.createElement(Text10, { color: "red", bold: true }, "\u274C Initialization Error"), /* @__PURE__ */ React11.createElement(Text10, null, initError), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, "\n", "Tip: Run /config to set up your API keys"));
9432
9955
  }
9433
9956
  if (state.showLoginFlow) {
9434
9957
  const loginApiUrl = getApiUrl(state.config?.apiConfig);
9435
- return /* @__PURE__ */ React10.createElement(
9958
+ return /* @__PURE__ */ React11.createElement(
9436
9959
  LoginFlow,
9437
9960
  {
9438
9961
  apiUrl: loginApiUrl,
@@ -9455,9 +9978,9 @@ Tool Permissions:
9455
9978
  );
9456
9979
  }
9457
9980
  if (!isInitialized) {
9458
- return /* @__PURE__ */ React10.createElement(Box10, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React10.createElement(Text9, null, "\u{1F680} Initializing..."));
9981
+ return /* @__PURE__ */ React11.createElement(Box11, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React11.createElement(Text10, null, "\u{1F680} Initializing..."));
9459
9982
  }
9460
- return /* @__PURE__ */ React10.createElement(
9983
+ return /* @__PURE__ */ React11.createElement(
9461
9984
  App,
9462
9985
  {
9463
9986
  onMessage: handleMessage,
@@ -9488,6 +10011,6 @@ var isDevMode = import.meta.url.includes("/src/") || process.env.NODE_ENV === "d
9488
10011
  if (isDevMode) {
9489
10012
  console.log("\u{1F527} Running in development mode (using TypeScript source)\n");
9490
10013
  }
9491
- render(/* @__PURE__ */ React10.createElement(CliApp, null), {
10014
+ render(/* @__PURE__ */ React11.createElement(CliApp, null), {
9492
10015
  exitOnCtrlC: false
9493
10016
  });