@bike4mind/cli 0.2.1-feat-cli-file-reference.17023 → 0.2.1-feat-cli-project-scoped-config.16996

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-GZTILMGE.js";
8
- import "./chunk-CJRAEEKV.js";
9
- import "./chunk-5N4PG5EH.js";
7
+ } from "./chunk-QXGU6KYI.js";
8
+ import "./chunk-LZMRYJ3B.js";
9
+ import "./chunk-F3ETXO5N.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-NZADYDFG.js";
18
+ } from "./chunk-U3GPYBTD.js";
19
19
  import {
20
20
  Logger
21
21
  } from "./chunk-AMDXHL6S.js";
@@ -83,8 +83,8 @@ import { render, Box as Box11, Text as Text10, useApp, useInput as useInput2 } f
83
83
  import { v4 as uuidv49 } from "uuid";
84
84
 
85
85
  // src/components/App.tsx
86
- import React8 from "react";
87
- import { Box as Box8, Text as Text7, Static } from "ink";
86
+ import React7 from "react";
87
+ import { Box as Box7, Text as Text6, Static } from "ink";
88
88
 
89
89
  // src/components/StatusBar.tsx
90
90
  import React from "react";
@@ -94,8 +94,8 @@ var StatusBar = React.memo(function StatusBar2({ sessionName, model, tokenUsage
94
94
  });
95
95
 
96
96
  // src/components/InputPrompt.tsx
97
- import React4, { useState, useMemo, useEffect } from "react";
98
- import { Box as Box4, Text as Text4, useInput } from "ink";
97
+ import React3, { useState, useMemo, useEffect } from "react";
98
+ import { Box as Box3, Text as Text3, useInput } from "ink";
99
99
  import TextInput from "ink-text-input";
100
100
 
101
101
  // src/components/CommandAutocomplete.tsx
@@ -112,210 +112,8 @@ function CommandAutocomplete({ commands, selectedIndex }) {
112
112
  }));
113
113
  }
114
114
 
115
- // src/components/FileAutocomplete.tsx
116
- import React3 from "react";
117
- import { Box as Box3, Text as Text3 } from "ink";
118
-
119
- // src/utils/fileSearch.ts
120
- import * as fs from "fs";
121
- import * as path from "path";
122
- import Fuse from "fuse.js";
123
- var DEFAULT_IGNORE_PATTERNS = [
124
- "node_modules",
125
- ".git",
126
- ".next",
127
- ".turbo",
128
- "dist",
129
- "build",
130
- ".cache",
131
- "coverage",
132
- ".DS_Store",
133
- ".env",
134
- ".env.local",
135
- ".env.secrets"
136
- ];
137
- function walkDirectory(basePath = process.cwd(), maxDepth = 5, ignorePatterns = DEFAULT_IGNORE_PATTERNS) {
138
- const results = [];
139
- const normalizedBase = path.resolve(basePath);
140
- function walk(currentPath, depth) {
141
- if (depth > maxDepth) return;
142
- try {
143
- const entries = fs.readdirSync(currentPath, { withFileTypes: true });
144
- for (const entry of entries) {
145
- if (ignorePatterns.some((pattern) => entry.name === pattern || entry.name.startsWith(pattern))) {
146
- continue;
147
- }
148
- const fullPath = path.join(currentPath, entry.name);
149
- const relativePath = path.relative(normalizedBase, fullPath);
150
- if (entry.isDirectory()) {
151
- results.push({
152
- path: relativePath,
153
- isDirectory: true
154
- });
155
- walk(fullPath, depth + 1);
156
- } else if (entry.isFile()) {
157
- try {
158
- const stats = fs.statSync(fullPath);
159
- results.push({
160
- path: relativePath,
161
- isDirectory: false,
162
- size: stats.size
163
- });
164
- } catch {
165
- results.push({
166
- path: relativePath,
167
- isDirectory: false
168
- });
169
- }
170
- }
171
- }
172
- } catch {
173
- }
174
- }
175
- walk(normalizedBase, 0);
176
- return results;
177
- }
178
- function formatFileSize(bytes) {
179
- if (bytes < 1024) return `${bytes} B`;
180
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
181
- if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
182
- return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;
183
- }
184
- var cachedFiles = null;
185
- var cacheTimestamp = 0;
186
- var CACHE_TTL_MS = 3e4;
187
- function getCachedFiles() {
188
- const now = Date.now();
189
- if (!cachedFiles || now - cacheTimestamp > CACHE_TTL_MS) {
190
- cachedFiles = walkDirectory();
191
- cacheTimestamp = now;
192
- }
193
- return cachedFiles;
194
- }
195
- function searchFiles(query) {
196
- const files = getCachedFiles();
197
- if (!query || query.trim() === "") {
198
- return files.filter((f) => !f.path.includes(path.sep)).slice(0, 20);
199
- }
200
- const queryDir = path.dirname(query);
201
- let searchPool = files;
202
- if (queryDir && queryDir !== ".") {
203
- const normalizedDir = queryDir.replace(/\\/g, "/");
204
- searchPool = files.filter((f) => {
205
- const normalizedPath = f.path.replace(/\\/g, "/");
206
- return normalizedPath.startsWith(normalizedDir + "/") || normalizedPath === normalizedDir;
207
- });
208
- if (searchPool.length === 0) {
209
- searchPool = files;
210
- }
211
- }
212
- const fuse2 = new Fuse(searchPool, {
213
- keys: [{ name: "path", weight: 1 }],
214
- threshold: 0.4,
215
- // Allow some fuzzy matching
216
- includeScore: true,
217
- minMatchCharLength: 1,
218
- // Use extended search for better path matching
219
- useExtendedSearch: false
220
- });
221
- const results = fuse2.search(query);
222
- return results.slice(0, 20).map((result) => result.item);
223
- }
224
- function isPathWithinCwd(filePath) {
225
- const cwd = path.resolve(process.cwd());
226
- const absolutePath = path.resolve(cwd, filePath);
227
- let resolvedCwd = cwd;
228
- let resolvedPath = absolutePath;
229
- try {
230
- const realCwd = fs.realpathSync.native(cwd);
231
- if (realCwd) {
232
- resolvedCwd = realCwd;
233
- }
234
- } catch {
235
- }
236
- try {
237
- const realPath = fs.realpathSync.native(absolutePath);
238
- if (realPath) {
239
- resolvedPath = realPath;
240
- }
241
- } catch {
242
- const relativePath2 = path.relative(cwd, absolutePath);
243
- resolvedPath = path.resolve(resolvedCwd, relativePath2);
244
- }
245
- const normalizedCwd = resolvedCwd.toLowerCase();
246
- const normalizedPath = resolvedPath.toLowerCase();
247
- const isWithin = normalizedPath === normalizedCwd || normalizedPath.startsWith(normalizedCwd + path.sep);
248
- if (!isWithin) {
249
- return false;
250
- }
251
- const relativePath = path.relative(resolvedCwd, resolvedPath);
252
- return !relativePath.startsWith("..") && !path.isAbsolute(relativePath);
253
- }
254
- function isBinaryFile(filePath) {
255
- const binaryExtensions = [
256
- ".png",
257
- ".jpg",
258
- ".jpeg",
259
- ".gif",
260
- ".bmp",
261
- ".ico",
262
- ".webp",
263
- // Note: .svg is NOT included because SVG is XML text format that can be safely read
264
- ".pdf",
265
- ".doc",
266
- ".docx",
267
- ".xls",
268
- ".xlsx",
269
- ".ppt",
270
- ".pptx",
271
- ".zip",
272
- ".tar",
273
- ".gz",
274
- ".rar",
275
- ".7z",
276
- ".exe",
277
- ".dll",
278
- ".so",
279
- ".dylib",
280
- ".bin",
281
- ".dat",
282
- ".mp3",
283
- ".mp4",
284
- ".wav",
285
- ".avi",
286
- ".mov",
287
- ".mkv",
288
- ".ttf",
289
- ".otf",
290
- ".woff",
291
- ".woff2",
292
- ".eot",
293
- ".class",
294
- ".pyc",
295
- ".o",
296
- ".obj"
297
- ];
298
- const ext = path.extname(filePath).toLowerCase();
299
- return binaryExtensions.includes(ext);
300
- }
301
- var MAX_FILE_SIZE = 10 * 1024 * 1024;
302
-
303
- // src/components/FileAutocomplete.tsx
304
- function FileAutocomplete({ files, selectedIndex, query }) {
305
- if (files.length === 0) {
306
- return /* @__PURE__ */ React3.createElement(Box3, { marginLeft: 2, marginTop: 1 }, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, "No matching files", query ? ` for "${query}"` : ""));
307
- }
308
- 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) => {
309
- const isSelected = index === selectedIndex;
310
- const icon = file.isDirectory ? "[folder]" : "[file] ";
311
- const sizeDisplay = file.isDirectory ? "" : file.size !== void 0 ? ` (${formatFileSize(file.size)})` : "";
312
- const pathDisplay = file.isDirectory ? `${file.path}/` : file.path;
313
- 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));
314
- }));
315
- }
316
-
317
115
  // src/utils/fuzzySearch.ts
318
- import Fuse2 from "fuse.js";
116
+ import Fuse from "fuse.js";
319
117
 
320
118
  // src/config/commands.ts
321
119
  var COMMANDS = [
@@ -383,7 +181,7 @@ var COMMANDS = [
383
181
  ];
384
182
 
385
183
  // src/utils/fuzzySearch.ts
386
- var fuse = new Fuse2(COMMANDS, {
184
+ var fuse = new Fuse(COMMANDS, {
387
185
  keys: [
388
186
  { name: "name", weight: 0.7 },
389
187
  // Prioritize command name
@@ -404,71 +202,23 @@ function searchCommands(query) {
404
202
  }
405
203
 
406
204
  // src/components/InputPrompt.tsx
407
- function shouldShowFileAutocomplete(_query) {
408
- return true;
409
- }
410
- function findAtTrigger(value) {
411
- for (let i = value.length - 1; i >= 0; i--) {
412
- if (value[i] === "@") {
413
- const isValid = i === 0 || value[i - 1] === " ";
414
- if (isValid) {
415
- const query = value.slice(i + 1);
416
- if (query.includes(" ")) {
417
- return null;
418
- }
419
- if (!shouldShowFileAutocomplete(query)) {
420
- return null;
421
- }
422
- return { startIndex: i, query };
423
- }
424
- }
425
- }
426
- return null;
427
- }
428
205
  function InputPrompt({ onSubmit, disabled = false, history = [] }) {
429
206
  const [value, setValue] = useState("");
430
207
  const [selectedIndex, setSelectedIndex] = useState(0);
431
208
  const [historyIndex, setHistoryIndex] = useState(-1);
432
209
  const [tempInput, setTempInput] = useState("");
433
210
  const [inputKey, setInputKey] = useState(0);
434
- const [fileAutocomplete, setFileAutocomplete] = useState(null);
435
- const [fileSelectedIndex, setFileSelectedIndex] = useState(0);
436
- const shouldShowCommandAutocomplete = value.startsWith("/") && !disabled && !fileAutocomplete?.active;
437
- const commandQuery = shouldShowCommandAutocomplete ? value.slice(1) : "";
211
+ const shouldShowAutocomplete = value.startsWith("/") && !disabled;
212
+ const query = shouldShowAutocomplete ? value.slice(1) : "";
438
213
  const filteredCommands = useMemo(() => {
439
- if (!shouldShowCommandAutocomplete) return [];
440
- return searchCommands(commandQuery);
441
- }, [shouldShowCommandAutocomplete, commandQuery]);
442
- const filteredFiles = useMemo(() => {
443
- if (!fileAutocomplete?.active) return [];
444
- return searchFiles(fileAutocomplete.query);
445
- }, [fileAutocomplete?.active, fileAutocomplete?.query]);
214
+ if (!shouldShowAutocomplete) return [];
215
+ return searchCommands(query);
216
+ }, [shouldShowAutocomplete, query]);
446
217
  useEffect(() => {
447
218
  setSelectedIndex(0);
448
219
  }, [filteredCommands]);
449
- useEffect(() => {
450
- setFileSelectedIndex(0);
451
- }, [filteredFiles]);
452
220
  useInput((input, key) => {
453
- if (fileAutocomplete?.active && filteredFiles.length > 0) {
454
- if (key.upArrow) {
455
- setFileSelectedIndex((prev) => prev > 0 ? prev - 1 : filteredFiles.length - 1);
456
- return;
457
- } else if (key.downArrow) {
458
- setFileSelectedIndex((prev) => prev < filteredFiles.length - 1 ? prev + 1 : 0);
459
- return;
460
- } else if (key.tab) {
461
- const selectedFile = filteredFiles[fileSelectedIndex];
462
- if (selectedFile) {
463
- insertSelectedFile(selectedFile);
464
- }
465
- return;
466
- } else if (key.escape) {
467
- setFileAutocomplete(null);
468
- return;
469
- }
470
- }
471
- if (shouldShowCommandAutocomplete && filteredCommands.length > 0) {
221
+ if (shouldShowAutocomplete && filteredCommands.length > 0) {
472
222
  if (key.upArrow) {
473
223
  setSelectedIndex((prev) => prev > 0 ? prev - 1 : filteredCommands.length - 1);
474
224
  } else if (key.downArrow) {
@@ -476,7 +226,7 @@ function InputPrompt({ onSubmit, disabled = false, history = [] }) {
476
226
  }
477
227
  return;
478
228
  }
479
- if (!shouldShowCommandAutocomplete && !fileAutocomplete?.active && history.length > 0) {
229
+ if (!shouldShowAutocomplete && history.length > 0) {
480
230
  if (key.upArrow) {
481
231
  if (historyIndex === -1) {
482
232
  setTempInput(value);
@@ -499,35 +249,9 @@ function InputPrompt({ onSubmit, disabled = false, history = [] }) {
499
249
  }
500
250
  }
501
251
  });
502
- const insertSelectedFile = (file) => {
503
- if (!fileAutocomplete) return;
504
- const beforeAt = value.slice(0, fileAutocomplete.startIndex);
505
- const afterQuery = value.slice(fileAutocomplete.startIndex + 1 + fileAutocomplete.query.length);
506
- const pathToInsert = file.isDirectory ? `@${file.path}/` : `@${file.path}`;
507
- const newValue = beforeAt + pathToInsert + afterQuery;
508
- setValue(newValue);
509
- setInputKey((prev) => prev + 1);
510
- if (file.isDirectory) {
511
- setFileAutocomplete({
512
- active: true,
513
- startIndex: fileAutocomplete.startIndex,
514
- query: file.path + "/"
515
- });
516
- setFileSelectedIndex(0);
517
- } else {
518
- setFileAutocomplete(null);
519
- }
520
- };
521
252
  const handleSubmit = (input) => {
522
253
  if (disabled || !input.trim()) return;
523
- if (fileAutocomplete?.active && filteredFiles.length > 0) {
524
- const selectedFile = filteredFiles[fileSelectedIndex];
525
- if (selectedFile) {
526
- insertSelectedFile(selectedFile);
527
- }
528
- return;
529
- }
530
- if (shouldShowCommandAutocomplete && filteredCommands.length > 0) {
254
+ if (shouldShowAutocomplete && filteredCommands.length > 0) {
531
255
  const selectedCommand = filteredCommands[selectedIndex];
532
256
  const commandText = `/${selectedCommand.name}`;
533
257
  if (selectedCommand.args) {
@@ -544,7 +268,6 @@ function InputPrompt({ onSubmit, disabled = false, history = [] }) {
544
268
  onSubmit(input);
545
269
  setValue("");
546
270
  setHistoryIndex(-1);
547
- setFileAutocomplete(null);
548
271
  };
549
272
  const handleChange = (newValue) => {
550
273
  setValue(newValue);
@@ -552,40 +275,30 @@ function InputPrompt({ onSubmit, disabled = false, history = [] }) {
552
275
  setHistoryIndex(-1);
553
276
  setTempInput("");
554
277
  }
555
- const atTrigger = findAtTrigger(newValue);
556
- if (atTrigger) {
557
- setFileAutocomplete({
558
- active: true,
559
- startIndex: atTrigger.startIndex,
560
- query: atTrigger.query
561
- });
562
- } else {
563
- setFileAutocomplete(null);
564
- }
565
278
  };
566
- return /* @__PURE__ */ React4.createElement(Box4, { flexDirection: "column" }, /* @__PURE__ */ React4.createElement(Box4, null, /* @__PURE__ */ React4.createElement(Text4, { bold: true, color: "cyan" }, "> "), /* @__PURE__ */ React4.createElement(
279
+ return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Box3, null, /* @__PURE__ */ React3.createElement(Text3, { bold: true, color: "cyan" }, "> "), /* @__PURE__ */ React3.createElement(
567
280
  TextInput,
568
281
  {
569
282
  key: inputKey,
570
283
  value,
571
284
  onChange: handleChange,
572
285
  onSubmit: handleSubmit,
573
- placeholder: disabled ? "Thinking..." : "Type your message, /help for commands, or @file to reference",
286
+ placeholder: disabled ? "Thinking..." : "Type your message or /help for commands",
574
287
  showCursor: !disabled
575
288
  }
576
- )), shouldShowCommandAutocomplete && /* @__PURE__ */ React4.createElement(CommandAutocomplete, { commands: filteredCommands, selectedIndex }), fileAutocomplete?.active && /* @__PURE__ */ React4.createElement(FileAutocomplete, { files: filteredFiles, selectedIndex: fileSelectedIndex, query: fileAutocomplete.query }));
289
+ )), shouldShowAutocomplete && /* @__PURE__ */ React3.createElement(CommandAutocomplete, { commands: filteredCommands, selectedIndex }));
577
290
  }
578
291
 
579
292
  // src/components/AgentThinking.tsx
580
- import React6 from "react";
581
- import { Box as Box6 } from "ink";
293
+ import React5 from "react";
294
+ import { Box as Box5 } from "ink";
582
295
 
583
296
  // src/components/ThoughtStream.tsx
584
- import React5 from "react";
585
- import { Box as Box5, Text as Text5 } from "ink";
297
+ import React4 from "react";
298
+ import { Box as Box4, Text as Text4 } from "ink";
586
299
  import Spinner from "ink-spinner";
587
- var ThoughtStream = React5.memo(function ThoughtStream2({ steps }) {
588
- 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...")));
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...")));
589
302
  });
590
303
 
591
304
  // src/store/index.ts
@@ -611,32 +324,32 @@ var useCliStore = create((set) => ({
611
324
  }));
612
325
 
613
326
  // src/components/AgentThinking.tsx
614
- var AgentThinking = React6.memo(function AgentThinking2() {
327
+ var AgentThinking = React5.memo(function AgentThinking2() {
615
328
  const isThinking = useCliStore((state) => state.isThinking);
616
329
  const agentSteps = useCliStore((state) => state.agentSteps);
617
330
  if (!isThinking) {
618
331
  return null;
619
332
  }
620
- return /* @__PURE__ */ React6.createElement(Box6, { borderStyle: "single", borderColor: "yellow", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React6.createElement(ThoughtStream, { steps: agentSteps }));
333
+ return /* @__PURE__ */ React5.createElement(Box5, { borderStyle: "single", borderColor: "yellow", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React5.createElement(ThoughtStream, { steps: agentSteps }));
621
334
  });
622
335
 
623
336
  // src/components/PermissionPrompt.tsx
624
- import React7 from "react";
625
- import { Box as Box7, Text as Text6 } from "ink";
337
+ import React6 from "react";
338
+ import { Box as Box6, Text as Text5 } from "ink";
626
339
  import SelectInput from "ink-select-input";
627
340
  function renderDiffPreview(preview) {
628
341
  const lines = preview.split("\n");
629
342
  return lines.map((line, index) => {
630
343
  if (line.startsWith("+")) {
631
- return /* @__PURE__ */ React7.createElement(Text6, { key: index, color: "green" }, line);
344
+ return /* @__PURE__ */ React6.createElement(Text5, { key: index, color: "green" }, line);
632
345
  }
633
346
  if (line.startsWith("-")) {
634
- return /* @__PURE__ */ React7.createElement(Text6, { key: index, color: "red" }, line);
347
+ return /* @__PURE__ */ React6.createElement(Text5, { key: index, color: "red" }, line);
635
348
  }
636
349
  if (line.startsWith("@@")) {
637
- return /* @__PURE__ */ React7.createElement(Text6, { key: index, color: "cyan" }, line);
350
+ return /* @__PURE__ */ React6.createElement(Text5, { key: index, color: "cyan" }, line);
638
351
  }
639
- return /* @__PURE__ */ React7.createElement(Text6, { key: index, dimColor: true }, line);
352
+ return /* @__PURE__ */ React6.createElement(Text5, { key: index, dimColor: true }, line);
640
353
  });
641
354
  }
642
355
  function PermissionPrompt({
@@ -656,121 +369,7 @@ function PermissionPrompt({
656
369
  { label: "\u2717 Deny", value: "deny" }
657
370
  ];
658
371
  const argsString = typeof args === "string" ? args : JSON.stringify(args, null, 2);
659
- 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) })));
660
- }
661
-
662
- // src/utils/processFileReferences.ts
663
- import * as fs2 from "fs";
664
- import * as path2 from "path";
665
-
666
- // src/utils/constants.ts
667
- var NAME_SUFFIXES = ["jr", "sr", "ii", "iii", "iv", "v", "phd", "md", "esq"];
668
- function isNameSuffix(value) {
669
- return NAME_SUFFIXES.includes(value);
670
- }
671
-
672
- // src/utils/processFileReferences.ts
673
- var FILE_REFERENCE_REGEX = /(?:^|\s)@([^\s@]+)/g;
674
- function looksLikeFilePath(ref) {
675
- if (ref.includes("/") || ref.includes(path2.sep)) {
676
- return true;
677
- }
678
- const extensionMatch = /\.(\w+)$/.exec(ref);
679
- if (extensionMatch) {
680
- const ext = extensionMatch[1].toLowerCase();
681
- if (isNameSuffix(ext)) {
682
- return false;
683
- }
684
- if (ext.length > 10) {
685
- return false;
686
- }
687
- return true;
688
- }
689
- return false;
690
- }
691
- function extractFileReferences(message) {
692
- const references = [];
693
- const regex = /(?:^|\s)@([^\s@]+)/g;
694
- let match;
695
- while ((match = regex.exec(message)) !== null) {
696
- const ref = match[1];
697
- if (looksLikeFilePath(ref)) {
698
- references.push(ref);
699
- }
700
- }
701
- return references;
702
- }
703
- function readFileContents(filePath) {
704
- const cwd = process.cwd();
705
- const absolutePath = path2.resolve(cwd, filePath);
706
- if (!isPathWithinCwd(filePath)) {
707
- return { error: `Security: Path "${filePath}" is outside the current working directory` };
708
- }
709
- if (!fs2.existsSync(absolutePath)) {
710
- return { error: `File not found: "${filePath}"` };
711
- }
712
- const stats = fs2.statSync(absolutePath);
713
- if (stats.isDirectory()) {
714
- try {
715
- const entries = fs2.readdirSync(absolutePath);
716
- const fileCount = entries.length;
717
- return {
718
- content: `(Directory with ${fileCount} items. Use file tools to explore if needed.)`,
719
- size: 0
720
- };
721
- } catch (err) {
722
- return { error: `Cannot read directory "${filePath}": ${err instanceof Error ? err.message : "Unknown error"}` };
723
- }
724
- }
725
- if (stats.size > MAX_FILE_SIZE) {
726
- return {
727
- error: `File too large: "${filePath}" is ${formatFileSize(stats.size)} (max ${formatFileSize(MAX_FILE_SIZE)})`
728
- };
729
- }
730
- if (isBinaryFile(filePath)) {
731
- return { error: `Binary file: "${filePath}" cannot be included as text content` };
732
- }
733
- try {
734
- const content = fs2.readFileSync(absolutePath, "utf-8");
735
- return { content, size: stats.size };
736
- } catch (err) {
737
- return { error: `Cannot read file "${filePath}": ${err instanceof Error ? err.message : "Unknown error"}` };
738
- }
739
- }
740
- function formatFileBlock(filePath, content, size, isDirectory) {
741
- if (isDirectory) {
742
- return `
743
- --- Directory Reference: ${filePath} ---
744
- ${content}
745
- --- End of ${filePath} ---`;
746
- }
747
- return `
748
- --- Referenced File: ${filePath} (${formatFileSize(size)}) ---
749
- ${content}
750
- --- End of ${filePath} ---`;
751
- }
752
- async function processFileReferences(message) {
753
- const references = extractFileReferences(message);
754
- const errors = [];
755
- const fileBlocks = [];
756
- for (const ref of references) {
757
- const result = readFileContents(ref);
758
- if ("error" in result) {
759
- errors.push(result.error);
760
- continue;
761
- }
762
- const isDirectory = result.size === 0 && result.content.startsWith("(Directory");
763
- fileBlocks.push(formatFileBlock(ref, result.content, result.size, isDirectory));
764
- }
765
- if (fileBlocks.length === 0) {
766
- return { content: message, errors };
767
- }
768
- const processedContent = message + "\n" + fileBlocks.join("\n");
769
- return { content: processedContent, errors };
770
- }
771
- function hasFileReferences(message) {
772
- FILE_REFERENCE_REGEX.lastIndex = 0;
773
- return FILE_REFERENCE_REGEX.test(message);
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) })));
774
373
  }
775
374
 
776
375
  // src/components/App.tsx
@@ -783,7 +382,7 @@ function App({ onMessage, onCommand, onPermissionResponse, commandHistory = [] }
783
382
  const permissionPrompt = useCliStore((state) => state.permissionPrompt);
784
383
  const exitRequested = useCliStore((state) => state.exitRequested);
785
384
  const setIsThinking = useCliStore((state) => state.setIsThinking);
786
- const handleSubmit = React8.useCallback(
385
+ const handleSubmit = React7.useCallback(
787
386
  async (input) => {
788
387
  const trimmed = input.trim();
789
388
  if (!trimmed) return;
@@ -794,25 +393,14 @@ function App({ onMessage, onCommand, onPermissionResponse, commandHistory = [] }
794
393
  }
795
394
  setIsThinking(true);
796
395
  try {
797
- let messageToSend = trimmed;
798
- if (hasFileReferences(trimmed)) {
799
- const processed = await processFileReferences(trimmed);
800
- messageToSend = processed.content;
801
- if (processed.errors.length > 0) {
802
- const errorBlock = processed.errors.map((e) => `[Warning: ${e}]`).join("\n");
803
- messageToSend = `${messageToSend}
804
-
805
- ${errorBlock}`;
806
- }
807
- }
808
- await onMessage(messageToSend);
396
+ await onMessage(trimmed);
809
397
  } finally {
810
398
  setIsThinking(false);
811
399
  }
812
400
  },
813
401
  [onMessage, onCommand, setIsThinking]
814
402
  );
815
- 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(
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(
816
404
  PermissionPrompt,
817
405
  {
818
406
  toolName: permissionPrompt.toolName,
@@ -821,39 +409,39 @@ ${errorBlock}`;
821
409
  canBeTrusted: permissionPrompt.canBeTrusted,
822
410
  onResponse: onPermissionResponse
823
411
  }
824
- )) : /* @__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 }))));
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 }))));
825
413
  }
826
414
  function MessageItem({ message }) {
827
- 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) => {
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) => {
828
416
  if (step.type === "thought") {
829
- 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 ? "..." : ""}`));
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 ? "..." : ""}`));
830
418
  }
831
419
  if (step.type === "action") {
832
420
  const toolName = step.metadata?.toolName || "unknown";
833
421
  const toolInput = step.metadata?.toolInput;
834
422
  const observationStep = message.metadata.steps[idx + 1];
835
423
  const result = observationStep?.type === "observation" ? observationStep.content : null;
836
- 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 ? "..." : ""}`));
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 ? "..." : ""}`));
837
425
  }
838
426
  return null;
839
- }).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`)));
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`)));
840
428
  }
841
429
 
842
430
  // src/components/MessageList.tsx
843
- import React9 from "react";
844
- import { Box as Box9, Text as Text8 } from "ink";
431
+ import React8 from "react";
432
+ import { Box as Box8, Text as Text7 } from "ink";
845
433
  function stripThinkingTags(content) {
846
434
  return content.replace(/<think>[\s\S]*?<\/think>/g, "").trim();
847
435
  }
848
- var MessageList = React9.memo(
436
+ var MessageList = React8.memo(
849
437
  function MessageList2({ messages }) {
850
438
  if (messages.length === 0) {
851
- return /* @__PURE__ */ React9.createElement(Box9, { paddingY: 1 }, /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, "No messages yet. Type a message to start!"));
439
+ return /* @__PURE__ */ React8.createElement(Box8, { paddingY: 1 }, /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, "No messages yet. Type a message to start!"));
852
440
  }
853
- 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) => {
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) => {
854
442
  if (step.type === "thought") {
855
- 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(
856
- Text8,
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,
857
445
  {
858
446
  dimColor: true
859
447
  },
@@ -865,10 +453,10 @@ var MessageList = React9.memo(
865
453
  const toolInput = step.metadata?.toolInput;
866
454
  const observationStep = message.metadata.steps[idx + 1];
867
455
  const result = observationStep?.type === "observation" ? observationStep.content : null;
868
- 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 ? "..." : ""}`));
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 ? "..." : ""}`));
869
457
  }
870
458
  return null;
871
- }).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`)))));
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`)))));
872
460
  },
873
461
  (prevProps, nextProps) => {
874
462
  if (prevProps.messages.length !== nextProps.messages.length) {
@@ -878,6 +466,39 @@ var MessageList = React9.memo(
878
466
  }
879
467
  );
880
468
 
469
+ // src/components/TrustLocationSelector.tsx
470
+ import React9 from "react";
471
+ import { Box as Box9, Text as Text8 } from "ink";
472
+ import SelectInput2 from "ink-select-input";
473
+ function TrustLocationSelector({ inProject, onSelect, onCancel }) {
474
+ const items = [];
475
+ if (inProject) {
476
+ items.push({
477
+ label: "Project settings (local) - Saved in .bike4mind/local.json (not committed)",
478
+ value: "local"
479
+ });
480
+ items.push({
481
+ label: "Project settings (team-wide) - Checked in at .bike4mind/config.json",
482
+ value: "project"
483
+ });
484
+ }
485
+ items.push({
486
+ label: "User settings - Saved at ~/.bike4mind/config.json",
487
+ value: "global"
488
+ });
489
+ const handleSelect = (item) => {
490
+ onSelect(item.value);
491
+ };
492
+ return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React9.createElement(Box9, { marginBottom: 1 }, /* @__PURE__ */ React9.createElement(Text8, { bold: true }, "Where should this rule be saved?")), /* @__PURE__ */ React9.createElement(
493
+ SelectInput2,
494
+ {
495
+ items,
496
+ onSelect: handleSelect,
497
+ itemComponent: ({ isSelected, label }) => /* @__PURE__ */ React9.createElement(Box9, null, /* @__PURE__ */ React9.createElement(Text8, { color: isSelected ? "cyan" : void 0 }, isSelected ? "\u276F " : " ", label))
498
+ }
499
+ ), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, "Use \u2191\u2193 arrows to navigate, Enter to select, Ctrl+C to cancel")));
500
+ }
501
+
881
502
  // src/components/LoginFlow.tsx
882
503
  import React10, { useState as useState2, useEffect as useEffect2 } from "react";
883
504
  import { Box as Box10, Text as Text9 } from "ink";
@@ -990,7 +611,7 @@ var OAuthClient = class {
990
611
  * Sleep for specified milliseconds
991
612
  */
992
613
  sleep(ms) {
993
- return new Promise((resolve3) => setTimeout(resolve3, ms));
614
+ return new Promise((resolve) => setTimeout(resolve, ms));
994
615
  }
995
616
  };
996
617
 
@@ -1055,19 +676,19 @@ function LoginFlow({ apiUrl = "http://localhost:3000", configStore, onSuccess, o
1055
676
  }
1056
677
 
1057
678
  // src/storage/SessionStore.ts
1058
- import { promises as fs3 } from "fs";
1059
- import path3 from "path";
679
+ import { promises as fs } from "fs";
680
+ import path from "path";
1060
681
  import { homedir } from "os";
1061
682
  var SessionStore = class {
1062
683
  constructor(basePath) {
1063
- this.basePath = basePath || path3.join(homedir(), ".bike4mind", "sessions");
684
+ this.basePath = basePath || path.join(homedir(), ".bike4mind", "sessions");
1064
685
  }
1065
686
  /**
1066
687
  * Initialize storage directory
1067
688
  */
1068
689
  async init() {
1069
690
  try {
1070
- await fs3.mkdir(this.basePath, { recursive: true });
691
+ await fs.mkdir(this.basePath, { recursive: true });
1071
692
  } catch (error) {
1072
693
  console.error("Failed to initialize session storage:", error);
1073
694
  throw error;
@@ -1078,9 +699,9 @@ var SessionStore = class {
1078
699
  */
1079
700
  async save(session) {
1080
701
  await this.init();
1081
- const filePath = path3.join(this.basePath, `${session.id}.json`);
702
+ const filePath = path.join(this.basePath, `${session.id}.json`);
1082
703
  try {
1083
- await fs3.writeFile(filePath, JSON.stringify(session, null, 2), "utf-8");
704
+ await fs.writeFile(filePath, JSON.stringify(session, null, 2), "utf-8");
1084
705
  } catch (error) {
1085
706
  console.error("Failed to save session:", error);
1086
707
  throw error;
@@ -1090,9 +711,9 @@ var SessionStore = class {
1090
711
  * Load a session from disk by ID
1091
712
  */
1092
713
  async load(id) {
1093
- const filePath = path3.join(this.basePath, `${id}.json`);
714
+ const filePath = path.join(this.basePath, `${id}.json`);
1094
715
  try {
1095
- const data = await fs3.readFile(filePath, "utf-8");
716
+ const data = await fs.readFile(filePath, "utf-8");
1096
717
  return JSON.parse(data);
1097
718
  } catch (error) {
1098
719
  if (error.code === "ENOENT") {
@@ -1116,12 +737,12 @@ var SessionStore = class {
1116
737
  async list() {
1117
738
  await this.init();
1118
739
  try {
1119
- const files = await fs3.readdir(this.basePath);
740
+ const files = await fs.readdir(this.basePath);
1120
741
  const jsonFiles = files.filter((f) => f.endsWith(".json"));
1121
742
  const sessions = await Promise.all(
1122
743
  jsonFiles.map(async (file) => {
1123
- const filePath = path3.join(this.basePath, file);
1124
- const data = await fs3.readFile(filePath, "utf-8");
744
+ const filePath = path.join(this.basePath, file);
745
+ const data = await fs.readFile(filePath, "utf-8");
1125
746
  return JSON.parse(data);
1126
747
  })
1127
748
  );
@@ -1135,9 +756,9 @@ var SessionStore = class {
1135
756
  * Delete a session
1136
757
  */
1137
758
  async delete(id) {
1138
- const filePath = path3.join(this.basePath, `${id}.json`);
759
+ const filePath = path.join(this.basePath, `${id}.json`);
1139
760
  try {
1140
- await fs3.unlink(filePath);
761
+ await fs.unlink(filePath);
1141
762
  return true;
1142
763
  } catch (error) {
1143
764
  if (error.code === "ENOENT") {
@@ -1173,8 +794,8 @@ var SessionStore = class {
1173
794
  };
1174
795
 
1175
796
  // src/storage/ConfigStore.ts
1176
- import { promises as fs4 } from "fs";
1177
- import path4 from "path";
797
+ import { promises as fs2, existsSync } from "fs";
798
+ import path2 from "path";
1178
799
  import { homedir as homedir2 } from "os";
1179
800
  import { v4 as uuidv4 } from "uuid";
1180
801
  import { z } from "zod";
@@ -1220,6 +841,53 @@ var CliConfigSchema = z.object({
1220
841
  }),
1221
842
  trustedTools: z.array(z.string()).optional().default([])
1222
843
  });
844
+ var ProjectConfigSchema = z.object({
845
+ tools: z.object({
846
+ enabled: z.array(z.string()).optional(),
847
+ denied: z.array(z.string()).optional(),
848
+ config: z.record(z.any()).optional()
849
+ }).optional(),
850
+ defaultModel: z.string().optional(),
851
+ mcpServers: z.array(
852
+ z.object({
853
+ name: z.string(),
854
+ command: z.string(),
855
+ args: z.array(z.string()),
856
+ env: z.record(z.string()),
857
+ enabled: z.boolean()
858
+ })
859
+ ).optional(),
860
+ preferences: z.object({
861
+ maxTokens: z.number().optional(),
862
+ temperature: z.number().optional(),
863
+ autoSave: z.boolean().optional(),
864
+ theme: z.enum(["light", "dark"]).optional(),
865
+ exportFormat: z.enum(["markdown", "json"]).optional()
866
+ }).optional()
867
+ });
868
+ var ProjectLocalConfigSchema = z.object({
869
+ trustedTools: z.array(z.string()).optional(),
870
+ toolApiKeys: z.object({
871
+ openweather: z.string().optional(),
872
+ serper: z.string().optional()
873
+ }).optional(),
874
+ preferences: z.object({
875
+ maxTokens: z.number().optional(),
876
+ temperature: z.number().optional(),
877
+ autoSave: z.boolean().optional(),
878
+ theme: z.enum(["light", "dark"]).optional(),
879
+ exportFormat: z.enum(["markdown", "json"]).optional()
880
+ }).optional(),
881
+ mcpServers: z.array(
882
+ z.object({
883
+ name: z.string(),
884
+ command: z.string(),
885
+ args: z.array(z.string()),
886
+ env: z.record(z.string()),
887
+ enabled: z.boolean()
888
+ })
889
+ ).optional()
890
+ });
1223
891
  var DEFAULT_CONFIG = {
1224
892
  version: "0.1.0",
1225
893
  userId: uuidv4(),
@@ -1245,18 +913,132 @@ var DEFAULT_CONFIG = {
1245
913
  trustedTools: []
1246
914
  // No tools trusted by default
1247
915
  };
916
+ function findProjectConfigDir(startDir = process.cwd()) {
917
+ let currentDir = startDir;
918
+ const { root } = path2.parse(currentDir);
919
+ while (currentDir !== root) {
920
+ const projectConfigPath = path2.join(currentDir, ".bike4mind", "config.json");
921
+ try {
922
+ if (existsSync(projectConfigPath)) {
923
+ return currentDir;
924
+ }
925
+ } catch {
926
+ }
927
+ currentDir = path2.dirname(currentDir);
928
+ }
929
+ return null;
930
+ }
931
+ async function loadProjectConfig(projectDir) {
932
+ const configPath = path2.join(projectDir, ".bike4mind", "config.json");
933
+ try {
934
+ const data = await fs2.readFile(configPath, "utf-8");
935
+ const rawConfig = JSON.parse(data);
936
+ const validated = ProjectConfigSchema.parse(rawConfig);
937
+ return validated;
938
+ } catch (error) {
939
+ if (error.code === "ENOENT") {
940
+ return null;
941
+ }
942
+ if (error instanceof z.ZodError) {
943
+ console.error("Project config validation error:", error.errors);
944
+ return null;
945
+ }
946
+ console.error("Failed to load project config:", error);
947
+ return null;
948
+ }
949
+ }
950
+ async function loadProjectLocalConfig(projectDir) {
951
+ const configPath = path2.join(projectDir, ".bike4mind", "local.json");
952
+ try {
953
+ const data = await fs2.readFile(configPath, "utf-8");
954
+ const rawConfig = JSON.parse(data);
955
+ const validated = ProjectLocalConfigSchema.parse(rawConfig);
956
+ return validated;
957
+ } catch (error) {
958
+ if (error.code === "ENOENT") {
959
+ return null;
960
+ }
961
+ if (error instanceof z.ZodError) {
962
+ console.error("Project local config validation error:", error.errors);
963
+ return null;
964
+ }
965
+ console.error("Failed to load project local config:", error);
966
+ return null;
967
+ }
968
+ }
969
+ function mergeMcpServers(...serverArrays) {
970
+ const serverMap = /* @__PURE__ */ new Map();
971
+ for (const servers of serverArrays) {
972
+ if (servers) {
973
+ for (const server of servers) {
974
+ serverMap.set(server.name, server);
975
+ }
976
+ }
977
+ }
978
+ return Array.from(serverMap.values());
979
+ }
980
+ function mergeConfigs(global, project, local) {
981
+ const merged = { ...global };
982
+ if (project) {
983
+ if (project.defaultModel) {
984
+ merged.defaultModel = project.defaultModel;
985
+ }
986
+ if (project.preferences) {
987
+ merged.preferences = {
988
+ ...merged.preferences,
989
+ ...project.preferences
990
+ };
991
+ }
992
+ if (project.tools) {
993
+ merged.tools = {
994
+ ...merged.tools,
995
+ enabled: project.tools.enabled || merged.tools.enabled,
996
+ disabled: [...merged.tools.disabled, ...project.tools.denied || []],
997
+ config: {
998
+ ...merged.tools.config,
999
+ ...project.tools.config
1000
+ }
1001
+ };
1002
+ }
1003
+ if (project.mcpServers) {
1004
+ merged.mcpServers = mergeMcpServers(merged.mcpServers, project.mcpServers);
1005
+ }
1006
+ }
1007
+ if (local) {
1008
+ if (local.trustedTools) {
1009
+ merged.trustedTools = [...merged.trustedTools || [], ...local.trustedTools];
1010
+ }
1011
+ if (local.toolApiKeys) {
1012
+ merged.toolApiKeys = {
1013
+ ...merged.toolApiKeys,
1014
+ ...local.toolApiKeys
1015
+ };
1016
+ }
1017
+ if (local.preferences) {
1018
+ merged.preferences = {
1019
+ ...merged.preferences,
1020
+ ...local.preferences
1021
+ };
1022
+ }
1023
+ if (local.mcpServers) {
1024
+ merged.mcpServers = mergeMcpServers(merged.mcpServers, local.mcpServers);
1025
+ }
1026
+ }
1027
+ return merged;
1028
+ }
1248
1029
  var ConfigStore = class {
1249
1030
  constructor(configPath) {
1250
1031
  this.config = null;
1251
- this.configPath = configPath || path4.join(homedir2(), ".bike4mind", "config.json");
1032
+ this.projectConfigDir = null;
1033
+ this.configPath = configPath || path2.join(homedir2(), ".bike4mind", "config.json");
1252
1034
  }
1253
1035
  /**
1254
1036
  * Initialize config directory
1255
1037
  */
1256
1038
  async init() {
1257
- const dir = path4.dirname(this.configPath);
1039
+ const dir = path2.dirname(this.configPath);
1258
1040
  try {
1259
- await fs4.mkdir(dir, { recursive: true });
1041
+ await fs2.mkdir(dir, { recursive: true });
1260
1042
  } catch (error) {
1261
1043
  console.error("Failed to initialize config directory:", error);
1262
1044
  throw error;
@@ -1264,51 +1046,76 @@ var ConfigStore = class {
1264
1046
  }
1265
1047
  /**
1266
1048
  * Load configuration from disk with Zod validation
1049
+ * Merges global → project → local configs
1267
1050
  */
1268
1051
  async load() {
1269
1052
  if (this.config) {
1270
1053
  return this.config;
1271
1054
  }
1272
1055
  try {
1056
+ let globalConfig;
1273
1057
  try {
1274
- const stats = await fs4.stat(this.configPath);
1275
- const mode = stats.mode & 511;
1276
- if (mode !== 384) {
1277
- console.warn(`\u26A0\uFE0F Config file has insecure permissions (${mode.toString(8)}). Setting to 0600...`);
1278
- await fs4.chmod(this.configPath, 384);
1058
+ try {
1059
+ const stats = await fs2.stat(this.configPath);
1060
+ const mode = stats.mode & 511;
1061
+ if (mode !== 384) {
1062
+ console.warn(`\u26A0\uFE0F Config file has insecure permissions (${mode.toString(8)}). Setting to 0600...`);
1063
+ await fs2.chmod(this.configPath, 384);
1064
+ }
1065
+ } catch (statError) {
1066
+ }
1067
+ const data = await fs2.readFile(this.configPath, "utf-8");
1068
+ const rawConfig = JSON.parse(data);
1069
+ if (rawConfig.apiConfig && "environment" in rawConfig.apiConfig) {
1070
+ const oldApiConfig = rawConfig.apiConfig;
1071
+ if (oldApiConfig.environment === "custom" && oldApiConfig.customUrl) {
1072
+ rawConfig.apiConfig = { customUrl: oldApiConfig.customUrl };
1073
+ } else {
1074
+ rawConfig.apiConfig = {};
1075
+ }
1279
1076
  }
1280
- } catch (statError) {
1281
- }
1282
- const data = await fs4.readFile(this.configPath, "utf-8");
1283
- const rawConfig = JSON.parse(data);
1284
- if (rawConfig.apiConfig && "environment" in rawConfig.apiConfig) {
1285
- const oldApiConfig = rawConfig.apiConfig;
1286
- if (oldApiConfig.environment === "custom" && oldApiConfig.customUrl) {
1287
- rawConfig.apiConfig = { customUrl: oldApiConfig.customUrl };
1077
+ const validated = CliConfigSchema.parse(rawConfig);
1078
+ globalConfig = {
1079
+ ...DEFAULT_CONFIG,
1080
+ ...validated,
1081
+ auth: validated.auth,
1082
+ // Explicitly preserve auth field
1083
+ preferences: {
1084
+ ...DEFAULT_CONFIG.preferences,
1085
+ ...validated.preferences
1086
+ },
1087
+ tools: {
1088
+ ...DEFAULT_CONFIG.tools,
1089
+ ...validated.tools
1090
+ },
1091
+ toolApiKeys: {
1092
+ ...DEFAULT_CONFIG.toolApiKeys,
1093
+ ...validated.toolApiKeys || {}
1094
+ },
1095
+ trustedTools: validated.trustedTools || []
1096
+ };
1097
+ } catch (error) {
1098
+ if (error.code === "ENOENT") {
1099
+ globalConfig = { ...DEFAULT_CONFIG };
1100
+ } else if (error instanceof z.ZodError) {
1101
+ console.error("Global config validation error:", error.errors);
1102
+ console.error("Using default configuration");
1103
+ globalConfig = { ...DEFAULT_CONFIG };
1288
1104
  } else {
1289
- rawConfig.apiConfig = {};
1105
+ throw error;
1290
1106
  }
1291
1107
  }
1292
- const validated = CliConfigSchema.parse(rawConfig);
1293
- this.config = {
1294
- ...DEFAULT_CONFIG,
1295
- ...validated,
1296
- auth: validated.auth,
1297
- // Explicitly preserve auth field
1298
- preferences: {
1299
- ...DEFAULT_CONFIG.preferences,
1300
- ...validated.preferences
1301
- },
1302
- tools: {
1303
- ...DEFAULT_CONFIG.tools,
1304
- ...validated.tools
1305
- },
1306
- toolApiKeys: {
1307
- ...DEFAULT_CONFIG.toolApiKeys,
1308
- ...validated.toolApiKeys || {}
1309
- },
1310
- trustedTools: validated.trustedTools || []
1311
- };
1108
+ this.projectConfigDir = findProjectConfigDir();
1109
+ let projectConfig = null;
1110
+ let projectLocalConfig = null;
1111
+ if (this.projectConfigDir) {
1112
+ projectConfig = await loadProjectConfig(this.projectConfigDir);
1113
+ projectLocalConfig = await loadProjectLocalConfig(this.projectConfigDir);
1114
+ if (projectConfig) {
1115
+ console.log(`\u{1F4C1} Project config loaded from: ${this.projectConfigDir}/.bike4mind/`);
1116
+ }
1117
+ }
1118
+ this.config = mergeConfigs(globalConfig, projectConfig, projectLocalConfig);
1312
1119
  return this.config;
1313
1120
  } catch (error) {
1314
1121
  if (error.code === "ENOENT") {
@@ -1352,8 +1159,8 @@ var ConfigStore = class {
1352
1159
  throw new Error("No configuration to save");
1353
1160
  }
1354
1161
  try {
1355
- await fs4.writeFile(this.configPath, JSON.stringify(this.config, null, 2), "utf-8");
1356
- await fs4.chmod(this.configPath, 384);
1162
+ await fs2.writeFile(this.configPath, JSON.stringify(this.config, null, 2), "utf-8");
1163
+ await fs2.chmod(this.configPath, 384);
1357
1164
  } catch (error) {
1358
1165
  console.error("Failed to save config:", error);
1359
1166
  throw error;
@@ -1495,27 +1302,126 @@ var ConfigStore = class {
1495
1302
  } else {
1496
1303
  config.apiConfig = { customUrl: url };
1497
1304
  }
1498
- await this.save(config);
1305
+ await this.save(config);
1306
+ }
1307
+ /**
1308
+ * Get project config directory (if any)
1309
+ */
1310
+ getProjectConfigDir() {
1311
+ return this.projectConfigDir;
1312
+ }
1313
+ /**
1314
+ * Initialize project config in current directory
1315
+ * Creates .bike4mind/config.json with default project config
1316
+ * Also ensures .bike4mind/local.json is in .gitignore
1317
+ */
1318
+ async initProjectConfig(projectDir = process.cwd()) {
1319
+ const configDir = path2.join(projectDir, ".bike4mind");
1320
+ const configPath = path2.join(configDir, "config.json");
1321
+ await fs2.mkdir(configDir, { recursive: true });
1322
+ try {
1323
+ await fs2.access(configPath);
1324
+ console.log(`Project config already exists at: ${configPath}`);
1325
+ } catch {
1326
+ const defaultProjectConfig = {
1327
+ tools: {
1328
+ enabled: [],
1329
+ denied: [],
1330
+ config: {}
1331
+ },
1332
+ mcpServers: [],
1333
+ preferences: {}
1334
+ };
1335
+ await fs2.writeFile(configPath, JSON.stringify(defaultProjectConfig, null, 2), "utf-8");
1336
+ console.log(`\u2705 Created project config at: ${configPath}`);
1337
+ }
1338
+ await this.ensureGitignore(projectDir);
1339
+ }
1340
+ /**
1341
+ * Ensure .gitignore includes .bike4mind/local.json
1342
+ */
1343
+ async ensureGitignore(projectDir) {
1344
+ const gitignorePath = path2.join(projectDir, ".gitignore");
1345
+ const entryToAdd = ".bike4mind/local.json";
1346
+ try {
1347
+ let gitignoreContent = "";
1348
+ try {
1349
+ gitignoreContent = await fs2.readFile(gitignorePath, "utf-8");
1350
+ } catch {
1351
+ }
1352
+ if (gitignoreContent.includes(entryToAdd)) {
1353
+ return;
1354
+ }
1355
+ const newContent = gitignoreContent.trim() + (gitignoreContent ? "\n" : "") + `
1356
+ # Bike4Mind local config (developer-specific)
1357
+ ${entryToAdd}
1358
+ `;
1359
+ await fs2.writeFile(gitignorePath, newContent, "utf-8");
1360
+ console.log(`\u2705 Added ${entryToAdd} to .gitignore`);
1361
+ } catch (error) {
1362
+ console.warn(`\u26A0\uFE0F Failed to update .gitignore:`, error);
1363
+ }
1364
+ }
1365
+ /**
1366
+ * Save project config to .bike4mind/config.json
1367
+ */
1368
+ async saveProjectConfig(config, projectDir) {
1369
+ const targetDir = projectDir || this.projectConfigDir || process.cwd();
1370
+ const configPath = path2.join(targetDir, ".bike4mind", "config.json");
1371
+ await fs2.mkdir(path2.dirname(configPath), { recursive: true });
1372
+ const validated = ProjectConfigSchema.parse(config);
1373
+ await fs2.writeFile(configPath, JSON.stringify(validated, null, 2), "utf-8");
1374
+ console.log(`\u2705 Saved project config to: ${configPath}`);
1375
+ }
1376
+ /**
1377
+ * Save project-local config to .bike4mind/local.json
1378
+ */
1379
+ async saveProjectLocalConfig(config, projectDir) {
1380
+ const targetDir = projectDir || this.projectConfigDir || process.cwd();
1381
+ const configPath = path2.join(targetDir, ".bike4mind", "local.json");
1382
+ await fs2.mkdir(path2.dirname(configPath), { recursive: true });
1383
+ const validated = ProjectLocalConfigSchema.parse(config);
1384
+ await fs2.writeFile(configPath, JSON.stringify(validated, null, 2), "utf-8");
1385
+ await fs2.chmod(configPath, 384);
1386
+ console.log(`\u2705 Saved project-local config to: ${configPath}`);
1387
+ }
1388
+ /**
1389
+ * Load raw project config (without merging)
1390
+ */
1391
+ async loadRawProjectConfig() {
1392
+ if (!this.projectConfigDir) {
1393
+ return null;
1394
+ }
1395
+ return loadProjectConfig(this.projectConfigDir);
1396
+ }
1397
+ /**
1398
+ * Load raw project-local config (without merging)
1399
+ */
1400
+ async loadRawProjectLocalConfig() {
1401
+ if (!this.projectConfigDir) {
1402
+ return null;
1403
+ }
1404
+ return loadProjectLocalConfig(this.projectConfigDir);
1499
1405
  }
1500
1406
  };
1501
1407
 
1502
1408
  // src/storage/CommandHistoryStore.ts
1503
- import { promises as fs5 } from "fs";
1504
- import path5 from "path";
1409
+ import { promises as fs3 } from "fs";
1410
+ import path3 from "path";
1505
1411
  import { homedir as homedir3 } from "os";
1506
1412
  var MAX_HISTORY_ENTRIES = 1e3;
1507
1413
  var CommandHistoryStore = class {
1508
1414
  constructor(historyPath) {
1509
1415
  this.history = null;
1510
- this.historyPath = historyPath || path5.join(homedir3(), ".bike4mind", "history.jsonl");
1416
+ this.historyPath = historyPath || path3.join(homedir3(), ".bike4mind", "history.jsonl");
1511
1417
  }
1512
1418
  /**
1513
1419
  * Initialize history directory
1514
1420
  */
1515
1421
  async init() {
1516
- const dir = path5.dirname(this.historyPath);
1422
+ const dir = path3.dirname(this.historyPath);
1517
1423
  try {
1518
- await fs5.mkdir(dir, { recursive: true });
1424
+ await fs3.mkdir(dir, { recursive: true });
1519
1425
  } catch (error) {
1520
1426
  console.error("Failed to initialize history directory:", error);
1521
1427
  throw error;
@@ -1530,7 +1436,7 @@ var CommandHistoryStore = class {
1530
1436
  return this.history;
1531
1437
  }
1532
1438
  try {
1533
- const data = await fs5.readFile(this.historyPath, "utf-8");
1439
+ const data = await fs3.readFile(this.historyPath, "utf-8");
1534
1440
  const lines = data.trim().split("\n").filter((line) => line.length > 0);
1535
1441
  const entries = lines.map((line) => {
1536
1442
  try {
@@ -1567,7 +1473,7 @@ var CommandHistoryStore = class {
1567
1473
  };
1568
1474
  await this.init();
1569
1475
  const line = JSON.stringify(entry) + "\n";
1570
- await fs5.appendFile(this.historyPath, line, "utf-8");
1476
+ await fs3.appendFile(this.historyPath, line, "utf-8");
1571
1477
  this.history = [command, ...this.history || []];
1572
1478
  if (this.history.length > MAX_HISTORY_ENTRIES) {
1573
1479
  await this.trim();
@@ -1590,7 +1496,7 @@ var CommandHistoryStore = class {
1590
1496
  };
1591
1497
  return JSON.stringify(entry);
1592
1498
  }).join("\n");
1593
- await fs5.writeFile(this.historyPath, lines + "\n", "utf-8");
1499
+ await fs3.writeFile(this.historyPath, lines + "\n", "utf-8");
1594
1500
  this.history = trimmedCommands;
1595
1501
  }
1596
1502
  /**
@@ -1598,7 +1504,7 @@ var CommandHistoryStore = class {
1598
1504
  */
1599
1505
  async clear() {
1600
1506
  try {
1601
- await fs5.unlink(this.historyPath);
1507
+ await fs3.unlink(this.historyPath);
1602
1508
  } catch (error) {
1603
1509
  if (error.code !== "ENOENT") {
1604
1510
  throw error;
@@ -2372,7 +2278,7 @@ import { GoogleGenerativeAI } from "@google/generative-ai";
2372
2278
  import OpenAI2 from "openai";
2373
2279
 
2374
2280
  // ../../b4m-core/packages/services/dist/src/importHistoryService/index.js
2375
- import fs6, { unlinkSync } from "fs";
2281
+ import fs4, { unlinkSync } from "fs";
2376
2282
  import yauzl from "yauzl";
2377
2283
  import axios3 from "axios";
2378
2284
 
@@ -2979,196 +2885,190 @@ var listFabFilesBySessionSchema = z90.object({
2979
2885
  sessionId: z90.string()
2980
2886
  });
2981
2887
 
2982
- // ../../b4m-core/packages/services/dist/src/fabFileService/listByQuest.js
2983
- import { z as z91 } from "zod";
2984
- var listFabFilesByQuestSchema = z91.object({
2985
- questId: z91.string()
2986
- });
2987
-
2988
2888
  // ../../b4m-core/packages/services/dist/src/fabFileService/createByUrl.js
2989
- import { z as z92 } from "zod";
2990
- var createFabFileByUrlSchema = z92.object({
2991
- url: z92.string().regex(/^(?!https?:\/\/(drive|docs)\.google\.com\/(?:file\/d\/|open\?id=|uc\?id=|document\/d\/|spreadsheets\/d\/|presentation\/d\/|forms\/d\/|drive\/folders\/)([a-zA-Z0-9_-]{10,})).+/)
2889
+ import { z as z91 } from "zod";
2890
+ var createFabFileByUrlSchema = z91.object({
2891
+ url: z91.string().regex(/^(?!https?:\/\/(drive|docs)\.google\.com\/(?:file\/d\/|open\?id=|uc\?id=|document\/d\/|spreadsheets\/d\/|presentation\/d\/|forms\/d\/|drive\/folders\/)([a-zA-Z0-9_-]{10,})).+/)
2992
2892
  });
2993
2893
 
2994
2894
  // ../../b4m-core/packages/services/dist/src/fabFileService/search.js
2995
- import { z as z93 } from "zod";
2996
- var searchFabFilesSchema = z93.object({
2997
- search: z93.string().optional(),
2998
- filters: z93.object({
2999
- tags: z93.array(z93.string()).optional(),
3000
- type: z93.enum(["text", "pdf", "url", "image", "excel", "word", "json", "csv", "markdown", "code"]).optional(),
3001
- shared: z93.coerce.boolean().optional(),
2895
+ import { z as z92 } from "zod";
2896
+ var searchFabFilesSchema = z92.object({
2897
+ search: z92.string().optional(),
2898
+ filters: z92.object({
2899
+ tags: z92.array(z92.string()).optional(),
2900
+ type: z92.enum(["text", "pdf", "url", "image", "excel", "word", "json", "csv", "markdown", "code"]).optional(),
2901
+ shared: z92.coerce.boolean().optional(),
3002
2902
  // Indicates if the user is searching for shared files
3003
- curated: z93.coerce.boolean().optional(),
2903
+ curated: z92.coerce.boolean().optional(),
3004
2904
  // Indicates if the user is searching for curated notebook files
3005
- projectId: z93.string().optional(),
3006
- ids: z93.array(z93.string()).optional()
2905
+ projectId: z92.string().optional(),
2906
+ ids: z92.array(z92.string()).optional()
3007
2907
  // Add support for filtering by IDs
3008
2908
  }).optional(),
3009
- pagination: z93.object({
3010
- page: z93.coerce.number(),
3011
- limit: z93.coerce.number()
2909
+ pagination: z92.object({
2910
+ page: z92.coerce.number(),
2911
+ limit: z92.coerce.number()
3012
2912
  }).optional(),
3013
- order: z93.object({
3014
- by: z93.enum(["createdAt", "fileName", "fileSize"]),
3015
- direction: z93.enum(["asc", "desc"])
2913
+ order: z92.object({
2914
+ by: z92.enum(["createdAt", "fileName", "fileSize"]),
2915
+ direction: z92.enum(["asc", "desc"])
3016
2916
  }).optional(),
3017
- options: z93.object({
3018
- includeShared: z93.coerce.boolean().optional()
2917
+ options: z92.object({
2918
+ includeShared: z92.coerce.boolean().optional()
3019
2919
  }).optional()
3020
2920
  });
3021
2921
 
3022
2922
  // ../../b4m-core/packages/services/dist/src/fabFileService/addFavorite.js
3023
- import { z as z94 } from "zod";
3024
- var addFavoriteParametersSchema3 = z94.object({
3025
- fileId: z94.string()
2923
+ import { z as z93 } from "zod";
2924
+ var addFavoriteParametersSchema3 = z93.object({
2925
+ fileId: z93.string()
3026
2926
  });
3027
2927
 
3028
2928
  // ../../b4m-core/packages/services/dist/src/fabFileService/deleteFavorite.js
3029
- import { z as z95 } from "zod";
3030
- var deleteFavoriteParametersSchema4 = z95.object({
3031
- fileId: z95.string()
2929
+ import { z as z94 } from "zod";
2930
+ var deleteFavoriteParametersSchema4 = z94.object({
2931
+ fileId: z94.string()
3032
2932
  });
3033
2933
 
3034
2934
  // ../../b4m-core/packages/services/dist/src/fabFileService/toggleTags.js
3035
- import { z as z96 } from "zod";
3036
- var fabFileToggleTagsSchema = z96.object({
3037
- ids: z96.array(z96.string()),
3038
- tags: z96.array(z96.string())
2935
+ import { z as z95 } from "zod";
2936
+ var fabFileToggleTagsSchema = z95.object({
2937
+ ids: z95.array(z95.string()),
2938
+ tags: z95.array(z95.string())
3039
2939
  });
3040
2940
 
3041
2941
  // ../../b4m-core/packages/services/dist/src/fabFileService/edit.js
3042
- import { z as z97 } from "zod";
2942
+ import { z as z96 } from "zod";
3043
2943
  import { diffLines } from "diff";
3044
- var editFabFileSchema = z97.object({
3045
- id: z97.string(),
3046
- instruction: z97.string(),
3047
- selection: z97.object({
3048
- start: z97.number(),
3049
- end: z97.number()
2944
+ var editFabFileSchema = z96.object({
2945
+ id: z96.string(),
2946
+ instruction: z96.string(),
2947
+ selection: z96.object({
2948
+ start: z96.number(),
2949
+ end: z96.number()
3050
2950
  }).optional(),
3051
- preserveFormatting: z97.boolean().optional().default(true),
3052
- applyImmediately: z97.boolean().optional().default(false)
2951
+ preserveFormatting: z96.boolean().optional().default(true),
2952
+ applyImmediately: z96.boolean().optional().default(false)
3053
2953
  });
3054
2954
 
3055
2955
  // ../../b4m-core/packages/services/dist/src/fabFileService/applyEdit.js
3056
2956
  import mime2 from "mime-types";
3057
2957
  import { v4 as uuidv43 } from "uuid";
3058
- import { z as z98 } from "zod";
3059
- var applyEditSchema = z98.object({
3060
- id: z98.string(),
3061
- modifiedContent: z98.string(),
3062
- createBackup: z98.boolean().optional().default(true)
2958
+ import { z as z97 } from "zod";
2959
+ var applyEditSchema = z97.object({
2960
+ id: z97.string(),
2961
+ modifiedContent: z97.string(),
2962
+ createBackup: z97.boolean().optional().default(true)
3063
2963
  });
3064
2964
 
3065
2965
  // ../../b4m-core/packages/services/dist/src/friendshipService/respondToFriendRequest.js
3066
- import { z as z99 } from "zod";
3067
- var respondToFriendRequestSchema = z99.object({
3068
- id: z99.string(),
2966
+ import { z as z98 } from "zod";
2967
+ var respondToFriendRequestSchema = z98.object({
2968
+ id: z98.string(),
3069
2969
  /** The user ID of the recipient of the friend request */
3070
- userId: z99.string(),
3071
- accept: z99.boolean()
2970
+ userId: z98.string(),
2971
+ accept: z98.boolean()
3072
2972
  });
3073
2973
 
3074
2974
  // ../../b4m-core/packages/services/dist/src/friendshipService/unfriend.js
3075
- import { z as z100 } from "zod";
3076
- var unfriendSchema = z100.object({
3077
- friendshipId: z100.string(),
2975
+ import { z as z99 } from "zod";
2976
+ var unfriendSchema = z99.object({
2977
+ friendshipId: z99.string(),
3078
2978
  /** The user ID of the user who wants to unfriend the other user */
3079
- userId: z100.string()
2979
+ userId: z99.string()
3080
2980
  });
3081
2981
 
3082
2982
  // ../../b4m-core/packages/services/dist/src/friendshipService/list.js
3083
- import { z as z101 } from "zod";
3084
- var listFriendsSchema = z101.object({
3085
- userId: z101.string()
2983
+ import { z as z100 } from "zod";
2984
+ var listFriendsSchema = z100.object({
2985
+ userId: z100.string()
3086
2986
  });
3087
- var listPendingFriendRequestsSchema = z101.object({
3088
- userId: z101.string()
2987
+ var listPendingFriendRequestsSchema = z100.object({
2988
+ userId: z100.string()
3089
2989
  });
3090
2990
 
3091
2991
  // ../../b4m-core/packages/services/dist/src/adminService/loginAs.js
3092
- import { z as z102 } from "zod";
3093
- var loginAsSchema = z102.object({
3094
- targetUserId: z102.string()
2992
+ import { z as z101 } from "zod";
2993
+ var loginAsSchema = z101.object({
2994
+ targetUserId: z101.string()
3095
2995
  });
3096
2996
 
3097
2997
  // ../../b4m-core/packages/services/dist/src/cacheService/get.js
3098
- import { z as z103 } from "zod";
3099
- var getParamsSchema = z103.object({
3100
- key: z103.string()
2998
+ import { z as z102 } from "zod";
2999
+ var getParamsSchema = z102.object({
3000
+ key: z102.string()
3101
3001
  });
3102
3002
 
3103
3003
  // ../../b4m-core/packages/services/dist/src/cacheService/set.js
3104
- import { z as z104 } from "zod";
3105
- var setParamsSchema = z104.object({
3106
- key: z104.string(),
3107
- value: z104.any(),
3004
+ import { z as z103 } from "zod";
3005
+ var setParamsSchema = z103.object({
3006
+ key: z103.string(),
3007
+ value: z103.any(),
3108
3008
  /**
3109
3009
  * Time to live in milliseconds
3110
3010
  */
3111
- ttl: z104.number(),
3112
- recache: z104.boolean().optional()
3011
+ ttl: z103.number(),
3012
+ recache: z103.boolean().optional()
3113
3013
  });
3114
3014
 
3115
3015
  // ../../b4m-core/packages/services/dist/src/cacheService/ttl.js
3116
- import { z as z105 } from "zod";
3117
- var ttlParamsSchema = z105.object({
3118
- key: z105.string()
3016
+ import { z as z104 } from "zod";
3017
+ var ttlParamsSchema = z104.object({
3018
+ key: z104.string()
3119
3019
  });
3120
3020
 
3121
3021
  // ../../b4m-core/packages/services/dist/src/cacheService/weeklyReports.js
3122
- import { z as z106 } from "zod";
3022
+ import { z as z105 } from "zod";
3123
3023
  import dayjs3 from "dayjs";
3124
- var weeklyReportSchema = z106.object({
3125
- startDate: z106.string(),
3126
- endDate: z106.string(),
3127
- report: z106.string(),
3128
- aiInsights: z106.string().nullable()
3024
+ var weeklyReportSchema = z105.object({
3025
+ startDate: z105.string(),
3026
+ endDate: z105.string(),
3027
+ report: z105.string(),
3028
+ aiInsights: z105.string().nullable()
3129
3029
  });
3130
3030
 
3131
3031
  // ../../b4m-core/packages/services/dist/src/embeddingCacheService/generateCacheKey.js
3132
3032
  import crypto2 from "crypto";
3133
3033
 
3134
3034
  // ../../b4m-core/packages/services/dist/src/researchAgentService/create.js
3035
+ import { z as z106 } from "zod";
3036
+ var researchAgentCreateSchema = z106.object({
3037
+ name: z106.string().min(1),
3038
+ description: z106.string().min(1)
3039
+ });
3040
+
3041
+ // ../../b4m-core/packages/services/dist/src/researchAgentService/update.js
3135
3042
  import { z as z107 } from "zod";
3136
- var researchAgentCreateSchema = z107.object({
3043
+ var researchAgentUpdateSchema = z107.object({
3044
+ id: z107.string(),
3137
3045
  name: z107.string().min(1),
3138
3046
  description: z107.string().min(1)
3139
3047
  });
3140
3048
 
3141
- // ../../b4m-core/packages/services/dist/src/researchAgentService/update.js
3049
+ // ../../b4m-core/packages/services/dist/src/researchAgentService/remove.js
3142
3050
  import { z as z108 } from "zod";
3143
- var researchAgentUpdateSchema = z108.object({
3144
- id: z108.string(),
3145
- name: z108.string().min(1),
3146
- description: z108.string().min(1)
3051
+ var researchAgentRemoveSchema = z108.object({
3052
+ id: z108.string()
3147
3053
  });
3148
3054
 
3149
- // ../../b4m-core/packages/services/dist/src/researchAgentService/remove.js
3055
+ // ../../b4m-core/packages/services/dist/src/researchAgentService/get.js
3150
3056
  import { z as z109 } from "zod";
3151
- var researchAgentRemoveSchema = z109.object({
3057
+ var researchAgentGetSchema = z109.object({
3152
3058
  id: z109.string()
3153
3059
  });
3154
3060
 
3155
- // ../../b4m-core/packages/services/dist/src/researchAgentService/get.js
3156
- import { z as z110 } from "zod";
3157
- var researchAgentGetSchema = z110.object({
3158
- id: z110.string()
3159
- });
3160
-
3161
3061
  // ../../b4m-core/packages/services/dist/src/researchAgentService/listFiles.js
3162
- import { z as z111 } from "zod";
3163
- var researchAgentListFilesSchema = z111.object({
3062
+ import { z as z110 } from "zod";
3063
+ var researchAgentListFilesSchema = z110.object({
3164
3064
  /**
3165
3065
  * The ID of the research agent
3166
3066
  */
3167
- id: z111.string()
3067
+ id: z110.string()
3168
3068
  });
3169
3069
 
3170
3070
  // ../../b4m-core/packages/services/dist/src/researchTaskService/process.js
3171
- import { z as z112 } from "zod";
3071
+ import { z as z111 } from "zod";
3172
3072
 
3173
3073
  // ../../b4m-core/packages/services/dist/src/lib/turndown.js
3174
3074
  import turndown from "turndown";
@@ -3559,316 +3459,316 @@ var deepResearchTool = {
3559
3459
  };
3560
3460
 
3561
3461
  // ../../b4m-core/packages/services/dist/src/researchTaskService/process.js
3562
- var ResearchTaskProcessSchema = z112.object({
3563
- id: z112.string()
3462
+ var ResearchTaskProcessSchema = z111.object({
3463
+ id: z111.string()
3564
3464
  });
3565
3465
 
3566
3466
  // ../../b4m-core/packages/services/dist/src/researchTaskService/create.js
3567
- import { z as z113 } from "zod";
3568
- var researchTaskCreateSchema = z113.object({
3569
- researchAgentId: z113.string(),
3570
- title: z113.string().max(100),
3571
- description: z113.string().max(500),
3572
- prompt: z113.string().max(500).optional(),
3573
- type: z113.nativeEnum(ResearchTaskType),
3574
- executionType: z113.nativeEnum(ResearchTaskExecutionType).default(ResearchTaskExecutionType.ON_DEMAND),
3575
- fileTagId: z113.string().optional(),
3576
- autoGeneratedTag: z113.object({
3577
- name: z113.string(),
3578
- icon: z113.string(),
3579
- color: z113.string()
3467
+ import { z as z112 } from "zod";
3468
+ var researchTaskCreateSchema = z112.object({
3469
+ researchAgentId: z112.string(),
3470
+ title: z112.string().max(100),
3471
+ description: z112.string().max(500),
3472
+ prompt: z112.string().max(500).optional(),
3473
+ type: z112.nativeEnum(ResearchTaskType),
3474
+ executionType: z112.nativeEnum(ResearchTaskExecutionType).default(ResearchTaskExecutionType.ON_DEMAND),
3475
+ fileTagId: z112.string().optional(),
3476
+ autoGeneratedTag: z112.object({
3477
+ name: z112.string(),
3478
+ icon: z112.string(),
3479
+ color: z112.string()
3580
3480
  }).optional()
3581
3481
  });
3582
3482
  var researchTaskScrapeCreateSchema = researchTaskCreateSchema.extend({
3583
- urls: z113.array(z113.string().url()).min(1),
3584
- canDiscoverLinks: z113.boolean()
3483
+ urls: z112.array(z112.string().url()).min(1),
3484
+ canDiscoverLinks: z112.boolean()
3585
3485
  });
3586
3486
  var researchTaskPeriodicCreateSchema = researchTaskCreateSchema.extend({
3587
- executionPeriodicStartAt: z113.coerce.date(),
3588
- executionPeriodicEndAt: z113.coerce.date(),
3589
- executionPeriodicFrequency: z113.nativeEnum(ResearchTaskPeriodicFrequencyType)
3487
+ executionPeriodicStartAt: z112.coerce.date(),
3488
+ executionPeriodicEndAt: z112.coerce.date(),
3489
+ executionPeriodicFrequency: z112.nativeEnum(ResearchTaskPeriodicFrequencyType)
3590
3490
  });
3591
3491
  var researchTaskScheduledCreateSchema = researchTaskCreateSchema.extend({
3592
- executionScheduledAt: z113.coerce.date()
3492
+ executionScheduledAt: z112.coerce.date()
3593
3493
  });
3594
3494
  var researchTaskDeepResearchCreateSchema = researchTaskCreateSchema.extend({
3595
- maxDepth: z113.number().min(1).max(10).optional()
3495
+ maxDepth: z112.number().min(1).max(10).optional()
3596
3496
  });
3597
3497
 
3598
3498
  // ../../b4m-core/packages/services/dist/src/researchTaskService/search.js
3599
- import { z as z114 } from "zod";
3600
- var searchResearchTasksSchema = z114.object({
3601
- search: z114.string().optional(),
3499
+ import { z as z113 } from "zod";
3500
+ var searchResearchTasksSchema = z113.object({
3501
+ search: z113.string().optional(),
3602
3502
  // ADD FILTERS SCHEMA HERE
3603
3503
  // filters: z
3604
3504
  // .object({
3605
3505
  // userId: z.string().optional(),
3606
3506
  // })
3607
3507
  // .optional(),
3608
- pagination: z114.object({
3609
- page: z114.coerce.number().optional(),
3610
- limit: z114.coerce.number().optional()
3508
+ pagination: z113.object({
3509
+ page: z113.coerce.number().optional(),
3510
+ limit: z113.coerce.number().optional()
3611
3511
  }).optional(),
3612
- orderBy: z114.object({
3613
- by: z114.enum(["createdAt", "updatedAt"]).optional(),
3614
- direction: z114.enum(["asc", "desc"]).optional()
3512
+ orderBy: z113.object({
3513
+ by: z113.enum(["createdAt", "updatedAt"]).optional(),
3514
+ direction: z113.enum(["asc", "desc"]).optional()
3615
3515
  }).optional()
3616
3516
  });
3617
3517
 
3618
3518
  // ../../b4m-core/packages/services/dist/src/researchTaskService/get.js
3619
- import { z as z115 } from "zod";
3620
- var getResearchTaskSchema = z115.object({
3621
- id: z115.string().min(1)
3519
+ import { z as z114 } from "zod";
3520
+ var getResearchTaskSchema = z114.object({
3521
+ id: z114.string().min(1)
3622
3522
  });
3623
3523
 
3624
3524
  // ../../b4m-core/packages/services/dist/src/researchTaskService/update.js
3625
- import { z as z116 } from "zod";
3626
- var updateResearchTaskSchema = z116.object({
3627
- id: z116.string(),
3628
- title: z116.string(),
3629
- description: z116.string(),
3630
- type: z116.nativeEnum(ResearchTaskType)
3525
+ import { z as z115 } from "zod";
3526
+ var updateResearchTaskSchema = z115.object({
3527
+ id: z115.string(),
3528
+ title: z115.string(),
3529
+ description: z115.string(),
3530
+ type: z115.nativeEnum(ResearchTaskType)
3631
3531
  });
3632
3532
  var researchTaskScrapeUpdateSchema = updateResearchTaskSchema.extend({
3633
- urls: z116.array(z116.string().url()).min(1),
3634
- canDiscoverLinks: z116.boolean()
3533
+ urls: z115.array(z115.string().url()).min(1),
3534
+ canDiscoverLinks: z115.boolean()
3635
3535
  });
3636
3536
 
3637
3537
  // ../../b4m-core/packages/services/dist/src/researchTaskService/listByAgentId.js
3638
- import { z as z117 } from "zod";
3639
- var listByAgentIdSchema = z117.object({
3640
- researchAgentId: z117.string()
3538
+ import { z as z116 } from "zod";
3539
+ var listByAgentIdSchema = z116.object({
3540
+ researchAgentId: z116.string()
3641
3541
  });
3642
3542
 
3643
3543
  // ../../b4m-core/packages/services/dist/src/researchTaskService/remove.js
3644
- import { z as z118 } from "zod";
3645
- var researchTaskRemoveSchema = z118.object({
3646
- id: z118.string().min(1)
3544
+ import { z as z117 } from "zod";
3545
+ var researchTaskRemoveSchema = z117.object({
3546
+ id: z117.string().min(1)
3647
3547
  });
3648
3548
 
3649
3549
  // ../../b4m-core/packages/services/dist/src/researchTaskService/retry.js
3650
- import { z as z119 } from "zod";
3651
- var researchTaskRetrySchema = z119.object({
3652
- id: z119.string(),
3653
- userId: z119.string()
3550
+ import { z as z118 } from "zod";
3551
+ var researchTaskRetrySchema = z118.object({
3552
+ id: z118.string(),
3553
+ userId: z118.string()
3654
3554
  });
3655
3555
 
3656
3556
  // ../../b4m-core/packages/services/dist/src/researchTaskService/processDiscoveredLinks.js
3657
3557
  import axios4 from "axios";
3658
- import { z as z120 } from "zod";
3558
+ import { z as z119 } from "zod";
3659
3559
  import plimit from "p-limit";
3660
3560
  import pLimit2 from "p-limit";
3661
- var researchTaskProcessDiscoveredLinksSchema = z120.object({
3662
- id: z120.string()
3561
+ var researchTaskProcessDiscoveredLinksSchema = z119.object({
3562
+ id: z119.string()
3663
3563
  });
3664
3564
 
3665
3565
  // ../../b4m-core/packages/services/dist/src/researchTaskService/downloadRelevantLinks.js
3666
- import { z as z121 } from "zod";
3566
+ import { z as z120 } from "zod";
3667
3567
  import plimit2 from "p-limit";
3668
3568
  import axios5 from "axios";
3669
3569
  import { fileTypeFromBuffer } from "file-type";
3670
- var researchTaskDownloadRelevantLinksSchema = z121.object({
3671
- id: z121.string()
3570
+ var researchTaskDownloadRelevantLinksSchema = z120.object({
3571
+ id: z120.string()
3672
3572
  });
3673
3573
 
3674
3574
  // ../../b4m-core/packages/services/dist/src/researchData/remove.js
3675
- import { z as z122 } from "zod";
3676
- var researchDataRemoveSchema = z122.object({
3677
- id: z122.string(),
3678
- researchAgentId: z122.string()
3575
+ import { z as z121 } from "zod";
3576
+ var researchDataRemoveSchema = z121.object({
3577
+ id: z121.string(),
3578
+ researchAgentId: z121.string()
3679
3579
  });
3680
3580
 
3681
3581
  // ../../b4m-core/packages/services/dist/src/taskSchedulerService/create.js
3682
- import { z as z123 } from "zod";
3683
- var researchTaskPayload = z123.object({
3684
- id: z123.string(),
3685
- userId: z123.string()
3582
+ import { z as z122 } from "zod";
3583
+ var researchTaskPayload = z122.object({
3584
+ id: z122.string(),
3585
+ userId: z122.string()
3686
3586
  });
3687
- var customTaskPayload = z123.object({
3688
- test: z123.string()
3587
+ var customTaskPayload = z122.object({
3588
+ test: z122.string()
3689
3589
  });
3690
- var taskSchedulerCreate = z123.discriminatedUnion("handler", [
3691
- z123.object({
3692
- handler: z123.literal(TaskScheduleHandler.RESEARCH_TASK_PROCESS),
3590
+ var taskSchedulerCreate = z122.discriminatedUnion("handler", [
3591
+ z122.object({
3592
+ handler: z122.literal(TaskScheduleHandler.RESEARCH_TASK_PROCESS),
3693
3593
  payload: researchTaskPayload,
3694
- processDate: z123.date()
3594
+ processDate: z122.date()
3695
3595
  }),
3696
- z123.object({
3697
- handler: z123.literal(TaskScheduleHandler.CUSTOM_TASK_PROCESS),
3596
+ z122.object({
3597
+ handler: z122.literal(TaskScheduleHandler.CUSTOM_TASK_PROCESS),
3698
3598
  payload: customTaskPayload,
3699
- processDate: z123.date()
3599
+ processDate: z122.date()
3700
3600
  })
3701
3601
  ]);
3702
3602
 
3703
3603
  // ../../b4m-core/packages/services/dist/src/tagService/createFileTag.js
3604
+ import { z as z123 } from "zod";
3605
+ var tagCreateFileTagSchema = z123.object({
3606
+ name: z123.string(),
3607
+ icon: z123.string().optional(),
3608
+ color: z123.string().optional(),
3609
+ description: z123.string().optional()
3610
+ });
3611
+
3612
+ // ../../b4m-core/packages/services/dist/src/tagService/create.js
3704
3613
  import { z as z124 } from "zod";
3705
- var tagCreateFileTagSchema = z124.object({
3614
+ var tagCreateSchema = z124.object({
3706
3615
  name: z124.string(),
3707
3616
  icon: z124.string().optional(),
3617
+ description: z124.string().optional(),
3708
3618
  color: z124.string().optional(),
3709
- description: z124.string().optional()
3619
+ type: z124.nativeEnum(TagType)
3710
3620
  });
3711
3621
 
3712
- // ../../b4m-core/packages/services/dist/src/tagService/create.js
3622
+ // ../../b4m-core/packages/services/dist/src/tagService/update.js
3713
3623
  import { z as z125 } from "zod";
3714
- var tagCreateSchema = z125.object({
3715
- name: z125.string(),
3624
+ var tagUpdateSchema = z125.object({
3625
+ id: z125.string(),
3626
+ name: z125.string().optional(),
3716
3627
  icon: z125.string().optional(),
3717
3628
  description: z125.string().optional(),
3718
- color: z125.string().optional(),
3719
- type: z125.nativeEnum(TagType)
3720
- });
3721
-
3722
- // ../../b4m-core/packages/services/dist/src/tagService/update.js
3723
- import { z as z126 } from "zod";
3724
- var tagUpdateSchema = z126.object({
3725
- id: z126.string(),
3726
- name: z126.string().optional(),
3727
- icon: z126.string().optional(),
3728
- description: z126.string().optional(),
3729
- color: z126.string().optional()
3629
+ color: z125.string().optional()
3730
3630
  });
3731
3631
 
3732
3632
  // ../../b4m-core/packages/services/dist/src/tagService/remove.js
3733
- import { z as z127 } from "zod";
3734
- var tagRemoveSchema = z127.object({
3735
- id: z127.string()
3633
+ import { z as z126 } from "zod";
3634
+ var tagRemoveSchema = z126.object({
3635
+ id: z126.string()
3736
3636
  });
3737
3637
 
3738
3638
  // ../../b4m-core/packages/services/dist/src/artifactService/create.js
3739
- import { z as z128 } from "zod";
3740
- var createArtifactSchema = z128.object({
3741
- id: z128.string().optional(),
3639
+ import { z as z127 } from "zod";
3640
+ var createArtifactSchema = z127.object({
3641
+ id: z127.string().optional(),
3742
3642
  // Allow custom ID for AI-generated artifacts
3743
- type: z128.enum(["mermaid", "recharts", "python", "react", "html", "svg", "code", "quest", "file", "questmaster"]),
3744
- title: z128.string().min(1).max(255),
3745
- description: z128.string().max(1e3).optional(),
3746
- content: z128.string().min(1),
3747
- projectId: z128.string().optional(),
3748
- organizationId: z128.string().optional(),
3749
- visibility: z128.enum(["private", "project", "organization", "public"]).default("private"),
3750
- tags: z128.array(z128.string().max(50)).max(20).default([]),
3751
- versionTag: z128.string().max(100).optional(),
3752
- sourceQuestId: z128.string().optional(),
3753
- sessionId: z128.string().optional(),
3754
- parentArtifactId: z128.string().optional(),
3755
- permissions: z128.object({
3756
- canRead: z128.array(z128.string()).default([]),
3757
- canWrite: z128.array(z128.string()).default([]),
3758
- canDelete: z128.array(z128.string()).default([]),
3759
- isPublic: z128.boolean().default(false),
3760
- inheritFromProject: z128.boolean().default(true)
3643
+ type: z127.enum(["mermaid", "recharts", "python", "react", "html", "svg", "code", "quest", "file", "questmaster"]),
3644
+ title: z127.string().min(1).max(255),
3645
+ description: z127.string().max(1e3).optional(),
3646
+ content: z127.string().min(1),
3647
+ projectId: z127.string().optional(),
3648
+ organizationId: z127.string().optional(),
3649
+ visibility: z127.enum(["private", "project", "organization", "public"]).default("private"),
3650
+ tags: z127.array(z127.string().max(50)).max(20).default([]),
3651
+ versionTag: z127.string().max(100).optional(),
3652
+ sourceQuestId: z127.string().optional(),
3653
+ sessionId: z127.string().optional(),
3654
+ parentArtifactId: z127.string().optional(),
3655
+ permissions: z127.object({
3656
+ canRead: z127.array(z127.string()).default([]),
3657
+ canWrite: z127.array(z127.string()).default([]),
3658
+ canDelete: z127.array(z127.string()).default([]),
3659
+ isPublic: z127.boolean().default(false),
3660
+ inheritFromProject: z127.boolean().default(true)
3761
3661
  }).optional(),
3762
- metadata: z128.record(z128.unknown()).default({})
3662
+ metadata: z127.record(z127.unknown()).default({})
3763
3663
  });
3764
3664
 
3765
3665
  // ../../b4m-core/packages/services/dist/src/artifactService/get.js
3766
- import { z as z129 } from "zod";
3767
- var getArtifactSchema = z129.object({
3768
- id: z129.string(),
3769
- includeContent: z129.boolean().default(false),
3770
- includeVersions: z129.boolean().default(false),
3771
- version: z129.number().optional()
3666
+ import { z as z128 } from "zod";
3667
+ var getArtifactSchema = z128.object({
3668
+ id: z128.string(),
3669
+ includeContent: z128.boolean().default(false),
3670
+ includeVersions: z128.boolean().default(false),
3671
+ version: z128.number().optional()
3772
3672
  });
3773
3673
 
3774
3674
  // ../../b4m-core/packages/services/dist/src/artifactService/list.js
3775
- import { z as z130 } from "zod";
3776
- var listArtifactsSchema = z130.object({
3777
- type: z130.string().optional(),
3778
- status: z130.enum(["draft", "review", "published", "archived"]).optional(),
3779
- visibility: z130.enum(["private", "project", "organization", "public"]).optional(),
3780
- projectId: z130.string().optional(),
3781
- sessionId: z130.string().optional(),
3782
- tags: z130.array(z130.string()).optional(),
3783
- search: z130.string().optional(),
3784
- limit: z130.number().min(1).max(100).default(20),
3785
- offset: z130.number().min(0).default(0),
3786
- sortBy: z130.enum(["createdAt", "updatedAt", "title", "type"]).default("updatedAt"),
3787
- sortOrder: z130.enum(["asc", "desc"]).default("desc"),
3788
- includeDeleted: z130.boolean().default(false)
3675
+ import { z as z129 } from "zod";
3676
+ var listArtifactsSchema = z129.object({
3677
+ type: z129.string().optional(),
3678
+ status: z129.enum(["draft", "review", "published", "archived"]).optional(),
3679
+ visibility: z129.enum(["private", "project", "organization", "public"]).optional(),
3680
+ projectId: z129.string().optional(),
3681
+ sessionId: z129.string().optional(),
3682
+ tags: z129.array(z129.string()).optional(),
3683
+ search: z129.string().optional(),
3684
+ limit: z129.number().min(1).max(100).default(20),
3685
+ offset: z129.number().min(0).default(0),
3686
+ sortBy: z129.enum(["createdAt", "updatedAt", "title", "type"]).default("updatedAt"),
3687
+ sortOrder: z129.enum(["asc", "desc"]).default("desc"),
3688
+ includeDeleted: z129.boolean().default(false)
3789
3689
  });
3790
3690
 
3791
3691
  // ../../b4m-core/packages/services/dist/src/artifactService/update.js
3792
- import { z as z131 } from "zod";
3793
- var updateArtifactSchema = z131.object({
3794
- id: z131.string(),
3795
- title: z131.string().min(1).max(255).optional(),
3796
- description: z131.string().max(1e3).optional(),
3797
- content: z131.string().optional(),
3798
- visibility: z131.enum(["private", "project", "organization", "public"]).optional(),
3799
- status: z131.enum(["draft", "review", "published", "archived"]).optional(),
3800
- tags: z131.array(z131.string().max(50)).max(20).optional(),
3801
- versionTag: z131.string().max(100).optional(),
3802
- permissions: z131.object({
3803
- canRead: z131.array(z131.string()).optional(),
3804
- canWrite: z131.array(z131.string()).optional(),
3805
- canDelete: z131.array(z131.string()).optional(),
3806
- isPublic: z131.boolean().optional(),
3807
- inheritFromProject: z131.boolean().optional()
3692
+ import { z as z130 } from "zod";
3693
+ var updateArtifactSchema = z130.object({
3694
+ id: z130.string(),
3695
+ title: z130.string().min(1).max(255).optional(),
3696
+ description: z130.string().max(1e3).optional(),
3697
+ content: z130.string().optional(),
3698
+ visibility: z130.enum(["private", "project", "organization", "public"]).optional(),
3699
+ status: z130.enum(["draft", "review", "published", "archived"]).optional(),
3700
+ tags: z130.array(z130.string().max(50)).max(20).optional(),
3701
+ versionTag: z130.string().max(100).optional(),
3702
+ permissions: z130.object({
3703
+ canRead: z130.array(z130.string()).optional(),
3704
+ canWrite: z130.array(z130.string()).optional(),
3705
+ canDelete: z130.array(z130.string()).optional(),
3706
+ isPublic: z130.boolean().optional(),
3707
+ inheritFromProject: z130.boolean().optional()
3808
3708
  }).optional(),
3809
- metadata: z131.record(z131.unknown()).optional(),
3810
- changes: z131.array(z131.string()).optional(),
3811
- changeDescription: z131.string().max(1e3).optional(),
3812
- createNewVersion: z131.boolean().optional(),
3813
- versionMessage: z131.string().max(500).optional()
3709
+ metadata: z130.record(z130.unknown()).optional(),
3710
+ changes: z130.array(z130.string()).optional(),
3711
+ changeDescription: z130.string().max(1e3).optional(),
3712
+ createNewVersion: z130.boolean().optional(),
3713
+ versionMessage: z130.string().max(500).optional()
3814
3714
  });
3815
3715
 
3816
3716
  // ../../b4m-core/packages/services/dist/src/artifactService/delete.js
3817
- import { z as z132 } from "zod";
3818
- var deleteArtifactSchema = z132.object({
3819
- id: z132.string(),
3820
- hardDelete: z132.boolean().default(false)
3717
+ import { z as z131 } from "zod";
3718
+ var deleteArtifactSchema = z131.object({
3719
+ id: z131.string(),
3720
+ hardDelete: z131.boolean().default(false)
3821
3721
  // For future implementation
3822
3722
  });
3823
3723
 
3824
3724
  // ../../b4m-core/packages/services/dist/src/questMasterService/create.js
3825
- import { z as z133 } from "zod";
3826
- var questSchema = z133.object({
3827
- id: z133.string(),
3828
- title: z133.string().min(1).max(255),
3829
- description: z133.string().max(1e3),
3830
- status: z133.enum(["not_started", "in_progress", "completed", "blocked"]).default("not_started"),
3831
- order: z133.number().min(0),
3832
- dependencies: z133.array(z133.string()).default([]),
3833
- estimatedTime: z133.string().optional()
3834
- });
3835
- var questResourceSchema = z133.object({
3836
- title: z133.string().min(1).max(255),
3837
- url: z133.string().url(),
3838
- type: z133.enum(["documentation", "tutorial", "reference", "example"])
3839
- });
3840
- var createQuestMasterSchema = z133.object({
3841
- title: z133.string().min(1).max(255),
3842
- description: z133.string().max(1e3).optional(),
3843
- goal: z133.string().min(1).max(1e3),
3844
- complexity: z133.enum(["beginner", "intermediate", "advanced", "expert"]),
3845
- estimatedTotalTime: z133.string().optional(),
3846
- prerequisites: z133.array(z133.string().max(200)).default([]),
3847
- quests: z133.array(questSchema).min(1),
3848
- resources: z133.array(questResourceSchema).default([]),
3849
- projectId: z133.string().optional(),
3850
- organizationId: z133.string().optional(),
3851
- visibility: z133.enum(["private", "project", "organization", "public"]).default("private"),
3852
- tags: z133.array(z133.string().max(50)).max(20).default([]),
3853
- permissions: z133.object({
3854
- canRead: z133.array(z133.string()).default([]),
3855
- canWrite: z133.array(z133.string()).default([]),
3856
- canDelete: z133.array(z133.string()).default([]),
3857
- isPublic: z133.boolean().default(false),
3858
- inheritFromProject: z133.boolean().default(true)
3725
+ import { z as z132 } from "zod";
3726
+ var questSchema = z132.object({
3727
+ id: z132.string(),
3728
+ title: z132.string().min(1).max(255),
3729
+ description: z132.string().max(1e3),
3730
+ status: z132.enum(["not_started", "in_progress", "completed", "blocked"]).default("not_started"),
3731
+ order: z132.number().min(0),
3732
+ dependencies: z132.array(z132.string()).default([]),
3733
+ estimatedTime: z132.string().optional()
3734
+ });
3735
+ var questResourceSchema = z132.object({
3736
+ title: z132.string().min(1).max(255),
3737
+ url: z132.string().url(),
3738
+ type: z132.enum(["documentation", "tutorial", "reference", "example"])
3739
+ });
3740
+ var createQuestMasterSchema = z132.object({
3741
+ title: z132.string().min(1).max(255),
3742
+ description: z132.string().max(1e3).optional(),
3743
+ goal: z132.string().min(1).max(1e3),
3744
+ complexity: z132.enum(["beginner", "intermediate", "advanced", "expert"]),
3745
+ estimatedTotalTime: z132.string().optional(),
3746
+ prerequisites: z132.array(z132.string().max(200)).default([]),
3747
+ quests: z132.array(questSchema).min(1),
3748
+ resources: z132.array(questResourceSchema).default([]),
3749
+ projectId: z132.string().optional(),
3750
+ organizationId: z132.string().optional(),
3751
+ visibility: z132.enum(["private", "project", "organization", "public"]).default("private"),
3752
+ tags: z132.array(z132.string().max(50)).max(20).default([]),
3753
+ permissions: z132.object({
3754
+ canRead: z132.array(z132.string()).default([]),
3755
+ canWrite: z132.array(z132.string()).default([]),
3756
+ canDelete: z132.array(z132.string()).default([]),
3757
+ isPublic: z132.boolean().default(false),
3758
+ inheritFromProject: z132.boolean().default(true)
3859
3759
  }).optional(),
3860
- sourceQuestId: z133.string().optional(),
3861
- sessionId: z133.string().optional(),
3862
- metadata: z133.record(z133.unknown()).default({})
3760
+ sourceQuestId: z132.string().optional(),
3761
+ sessionId: z132.string().optional(),
3762
+ metadata: z132.record(z132.unknown()).default({})
3863
3763
  });
3864
3764
 
3865
3765
  // ../../b4m-core/packages/services/dist/src/questMasterService/updateQuestStatus.js
3866
- import { z as z134 } from "zod";
3867
- var updateQuestStatusSchema = z134.object({
3868
- artifactId: z134.string(),
3869
- questId: z134.string(),
3870
- status: z134.enum(["not_started", "in_progress", "completed", "blocked"]),
3871
- completionNote: z134.string().max(500).optional()
3766
+ import { z as z133 } from "zod";
3767
+ var updateQuestStatusSchema = z133.object({
3768
+ artifactId: z133.string(),
3769
+ questId: z133.string(),
3770
+ status: z133.enum(["not_started", "in_progress", "completed", "blocked"]),
3771
+ completionNote: z133.string().max(500).optional()
3872
3772
  });
3873
3773
 
3874
3774
  // ../../b4m-core/packages/services/dist/src/dataLakeService/opensearchClient.js
@@ -3888,63 +3788,63 @@ import { v4 as uuidv44 } from "uuid";
3888
3788
  import { randomUUID as randomUUID5 } from "crypto";
3889
3789
 
3890
3790
  // ../../b4m-core/packages/services/dist/src/emailIngestionService/types.js
3891
- import { z as z135 } from "zod";
3892
- var processIngestedEmailOptionsSchema = z135.object({
3893
- platformDomain: z135.string().optional(),
3894
- isNewsletter: z135.boolean().optional()
3791
+ import { z as z134 } from "zod";
3792
+ var processIngestedEmailOptionsSchema = z134.object({
3793
+ platformDomain: z134.string().optional(),
3794
+ isNewsletter: z134.boolean().optional()
3895
3795
  }).optional();
3896
- var emailAttachmentSchema = z135.object({
3897
- filename: z135.string().optional(),
3898
- contentType: z135.string().optional(),
3899
- contentDisposition: z135.string().optional(),
3900
- size: z135.number().min(0),
3901
- content: z135.instanceof(Buffer),
3902
- related: z135.boolean().optional()
3903
- });
3904
- var parsedEmailObjectSchema = z135.object({
3905
- messageId: z135.string().optional(),
3906
- inReplyTo: z135.string().optional(),
3907
- references: z135.union([z135.string(), z135.array(z135.string())]).optional(),
3908
- from: z135.any().optional(),
3796
+ var emailAttachmentSchema = z134.object({
3797
+ filename: z134.string().optional(),
3798
+ contentType: z134.string().optional(),
3799
+ contentDisposition: z134.string().optional(),
3800
+ size: z134.number().min(0),
3801
+ content: z134.instanceof(Buffer),
3802
+ related: z134.boolean().optional()
3803
+ });
3804
+ var parsedEmailObjectSchema = z134.object({
3805
+ messageId: z134.string().optional(),
3806
+ inReplyTo: z134.string().optional(),
3807
+ references: z134.union([z134.string(), z134.array(z134.string())]).optional(),
3808
+ from: z134.any().optional(),
3909
3809
  // Complex email address object
3910
- to: z135.any().optional(),
3911
- cc: z135.any().optional(),
3912
- bcc: z135.any().optional(),
3913
- subject: z135.string().optional(),
3914
- date: z135.date().optional(),
3915
- text: z135.string().optional(),
3916
- html: z135.string().optional(),
3917
- attachments: z135.array(emailAttachmentSchema).optional()
3918
- });
3919
- var processIngestedEmailSchema = z135.object({
3810
+ to: z134.any().optional(),
3811
+ cc: z134.any().optional(),
3812
+ bcc: z134.any().optional(),
3813
+ subject: z134.string().optional(),
3814
+ date: z134.date().optional(),
3815
+ text: z134.string().optional(),
3816
+ html: z134.string().optional(),
3817
+ attachments: z134.array(emailAttachmentSchema).optional()
3818
+ });
3819
+ var processIngestedEmailSchema = z134.object({
3920
3820
  parsedEmail: parsedEmailObjectSchema,
3921
- rawEmailS3Key: z135.string().min(1, "rawEmailS3Key cannot be empty"),
3821
+ rawEmailS3Key: z134.string().min(1, "rawEmailS3Key cannot be empty"),
3922
3822
  options: processIngestedEmailOptionsSchema
3923
3823
  });
3924
3824
 
3925
3825
  // ../../b4m-core/packages/services/dist/src/emailAnalysisService/types.js
3926
- import { z as z136 } from "zod";
3927
- var llmAnalysisResponseSchema = z136.object({
3928
- summary: z136.string().min(1, "Summary cannot be empty"),
3929
- entities: z136.object({
3930
- companies: z136.array(z136.string()).default([]),
3931
- people: z136.array(z136.string()).default([]),
3932
- products: z136.array(z136.string()).default([]),
3933
- technologies: z136.array(z136.string()).default([])
3826
+ import { z as z135 } from "zod";
3827
+ var llmAnalysisResponseSchema = z135.object({
3828
+ summary: z135.string().min(1, "Summary cannot be empty"),
3829
+ entities: z135.object({
3830
+ companies: z135.array(z135.string()).default([]),
3831
+ people: z135.array(z135.string()).default([]),
3832
+ products: z135.array(z135.string()).default([]),
3833
+ technologies: z135.array(z135.string()).default([])
3934
3834
  }),
3935
- sentiment: z136.enum(["positive", "neutral", "negative", "urgent"]),
3936
- actionItems: z136.array(z136.object({
3937
- description: z136.string(),
3938
- deadline: z136.string().optional()
3835
+ sentiment: z135.enum(["positive", "neutral", "negative", "urgent"]),
3836
+ actionItems: z135.array(z135.object({
3837
+ description: z135.string(),
3838
+ deadline: z135.string().optional()
3939
3839
  // ISO date string from LLM
3940
3840
  })).default([]),
3941
- privacyRecommendation: z136.enum(["public", "team", "private"]),
3942
- embargoDetected: z136.boolean().default(false),
3943
- suggestedTags: z136.array(z136.string()).default([])
3841
+ privacyRecommendation: z135.enum(["public", "team", "private"]),
3842
+ embargoDetected: z135.boolean().default(false),
3843
+ suggestedTags: z135.array(z135.string()).default([])
3944
3844
  });
3945
3845
 
3946
3846
  // ../../b4m-core/packages/services/dist/src/llm/ChatCompletion.js
3947
- import { z as z138 } from "zod";
3847
+ import { z as z137 } from "zod";
3948
3848
 
3949
3849
  // ../../b4m-core/packages/services/dist/src/llm/ChatCompletionInvoke.js
3950
3850
  import { fromZodError } from "zod-validation-error";
@@ -4058,8 +3958,8 @@ async function processAndStoreImages(images, context) {
4058
3958
  const buffer = await downloadImage(image);
4059
3959
  const fileType = await fileTypeFromBuffer2(buffer);
4060
3960
  const filename = `${uuidv45()}.${fileType?.ext}`;
4061
- const path13 = await context.imageGenerateStorage.upload(buffer, filename, {});
4062
- return path13;
3961
+ const path11 = await context.imageGenerateStorage.upload(buffer, filename, {});
3962
+ return path11;
4063
3963
  }));
4064
3964
  }
4065
3965
  async function updateQuestAndReturnMarkdown(storedImageUrls, context) {
@@ -5004,17 +4904,17 @@ var rechartsTool = {
5004
4904
  };
5005
4905
 
5006
4906
  // ../../b4m-core/packages/services/dist/src/llm/tools/implementation/editFile/index.js
5007
- import { z as z137 } from "zod";
4907
+ import { z as z136 } from "zod";
5008
4908
  import { diffLines as diffLines2 } from "diff";
5009
- var editFileSchema = z137.object({
5010
- fileId: z137.string().describe("The ID of the file to edit"),
5011
- instruction: z137.string().describe("Natural language instruction describing the changes to make"),
5012
- selection: z137.object({
5013
- start: z137.number().describe("Starting character position of the selection"),
5014
- end: z137.number().describe("Ending character position of the selection")
4909
+ var editFileSchema = z136.object({
4910
+ fileId: z136.string().describe("The ID of the file to edit"),
4911
+ instruction: z136.string().describe("Natural language instruction describing the changes to make"),
4912
+ selection: z136.object({
4913
+ start: z136.number().describe("Starting character position of the selection"),
4914
+ end: z136.number().describe("Ending character position of the selection")
5015
4915
  }).optional().describe("Optional selection range to edit within the file"),
5016
- preserveFormatting: z137.boolean().optional().default(true).describe("Whether to preserve the original formatting style"),
5017
- returnDiff: z137.boolean().optional().default(true).describe("Whether to return a diff of the changes")
4916
+ preserveFormatting: z136.boolean().optional().default(true).describe("Whether to preserve the original formatting style"),
4917
+ returnDiff: z136.boolean().optional().default(true).describe("Whether to return a diff of the changes")
5018
4918
  });
5019
4919
  function generateSimpleDiff(original, modified) {
5020
4920
  const differences = diffLines2(original, modified);
@@ -5243,8 +5143,8 @@ async function processAndStoreImage(imageUrl, context) {
5243
5143
  const buffer = await downloadImage2(imageUrl);
5244
5144
  const fileType = await fileTypeFromBuffer3(buffer);
5245
5145
  const filename = `${uuidv46()}.${fileType?.ext}`;
5246
- const path13 = await context.imageGenerateStorage.upload(buffer, filename, {});
5247
- return path13;
5146
+ const path11 = await context.imageGenerateStorage.upload(buffer, filename, {});
5147
+ return path11;
5248
5148
  }
5249
5149
  async function updateQuestAndReturnMarkdown2(storedImagePath, context) {
5250
5150
  await context.onFinish?.("edit_image", storedImagePath);
@@ -6773,8 +6673,8 @@ var getHeliocentricCoords = (planet, T) => {
6773
6673
  const sinNode = Math.sin(longNode);
6774
6674
  const x = r * (cosNode * cosOmega - sinNode * sinOmega * cosI);
6775
6675
  const y = r * (sinNode * cosOmega + cosNode * sinOmega * cosI);
6776
- const z144 = r * sinOmega * sinI;
6777
- return { x, y, z: z144, r };
6676
+ const z143 = r * sinOmega * sinI;
6677
+ return { x, y, z: z143, r };
6778
6678
  };
6779
6679
  var getGeocentricEcliptic = (planet, earth) => {
6780
6680
  const dx = planet.x - earth.x;
@@ -7081,33 +6981,33 @@ var planetVisibilityTool = {
7081
6981
  };
7082
6982
 
7083
6983
  // ../../b4m-core/packages/services/dist/src/llm/tools/implementation/fileRead/index.js
7084
- import { promises as fs7 } from "fs";
7085
- import { existsSync as existsSync2, statSync as statSync3 } from "fs";
7086
- import path6 from "path";
7087
- var MAX_FILE_SIZE2 = 10 * 1024 * 1024;
6984
+ import { promises as fs5 } from "fs";
6985
+ import { existsSync as existsSync2, statSync } from "fs";
6986
+ import path4 from "path";
6987
+ var MAX_FILE_SIZE = 10 * 1024 * 1024;
7088
6988
  async function readFileContent(params) {
7089
6989
  const { path: filePath, encoding = "utf-8", maxLines } = params;
7090
- const normalizedPath = path6.normalize(filePath);
7091
- const resolvedPath = path6.resolve(process.cwd(), normalizedPath);
7092
- const cwd = path6.resolve(process.cwd());
6990
+ const normalizedPath = path4.normalize(filePath);
6991
+ const resolvedPath = path4.resolve(process.cwd(), normalizedPath);
6992
+ const cwd = path4.resolve(process.cwd());
7093
6993
  if (!resolvedPath.startsWith(cwd)) {
7094
6994
  throw new Error(`Access denied: Cannot read files outside of current working directory`);
7095
6995
  }
7096
6996
  if (!existsSync2(resolvedPath)) {
7097
6997
  throw new Error(`File not found: ${filePath}`);
7098
6998
  }
7099
- const stats = statSync3(resolvedPath);
6999
+ const stats = statSync(resolvedPath);
7100
7000
  if (stats.isDirectory()) {
7101
7001
  throw new Error(`Path is a directory, not a file: ${filePath}`);
7102
7002
  }
7103
- if (stats.size > MAX_FILE_SIZE2) {
7104
- throw new Error(`File too large: ${(stats.size / 1024 / 1024).toFixed(2)}MB (max ${MAX_FILE_SIZE2 / 1024 / 1024}MB)`);
7003
+ if (stats.size > MAX_FILE_SIZE) {
7004
+ throw new Error(`File too large: ${(stats.size / 1024 / 1024).toFixed(2)}MB (max ${MAX_FILE_SIZE / 1024 / 1024}MB)`);
7105
7005
  }
7106
7006
  const isBinary = await checkIfBinary(resolvedPath);
7107
7007
  if (isBinary && encoding === "utf-8") {
7108
7008
  throw new Error(`File appears to be binary. Use encoding 'base64' to read binary files, or specify a different encoding.`);
7109
7009
  }
7110
- const content = await fs7.readFile(resolvedPath, encoding);
7010
+ const content = await fs5.readFile(resolvedPath, encoding);
7111
7011
  if (maxLines && typeof content === "string") {
7112
7012
  const lines = content.split("\n");
7113
7013
  if (lines.length > maxLines) {
@@ -7122,7 +7022,7 @@ ${content}`;
7122
7022
  }
7123
7023
  async function checkIfBinary(filePath) {
7124
7024
  const buffer = Buffer.alloc(8192);
7125
- const fd = await fs7.open(filePath, "r");
7025
+ const fd = await fs5.open(filePath, "r");
7126
7026
  try {
7127
7027
  const { bytesRead } = await fd.read(buffer, 0, 8192, 0);
7128
7028
  const chunk = buffer.slice(0, bytesRead);
@@ -7139,7 +7039,7 @@ var fileReadTool = {
7139
7039
  context.logger.info("\u{1F4C4} FileRead: Reading file", { path: params.path });
7140
7040
  try {
7141
7041
  const content = await readFileContent(params);
7142
- const stats = statSync3(path6.resolve(process.cwd(), path6.normalize(params.path)));
7042
+ const stats = statSync(path4.resolve(process.cwd(), path4.normalize(params.path)));
7143
7043
  context.logger.info("\u2705 FileRead: Success", {
7144
7044
  path: params.path,
7145
7045
  size: stats.size,
@@ -7178,25 +7078,25 @@ var fileReadTool = {
7178
7078
  };
7179
7079
 
7180
7080
  // ../../b4m-core/packages/services/dist/src/llm/tools/implementation/createFile/index.js
7181
- import { promises as fs8 } from "fs";
7081
+ import { promises as fs6 } from "fs";
7182
7082
  import { existsSync as existsSync3 } from "fs";
7183
- import path7 from "path";
7083
+ import path5 from "path";
7184
7084
  async function createFile(params) {
7185
7085
  const { path: filePath, content, createDirectories = true } = params;
7186
- const normalizedPath = path7.normalize(filePath);
7187
- const resolvedPath = path7.resolve(process.cwd(), normalizedPath);
7188
- const cwd = path7.resolve(process.cwd());
7086
+ const normalizedPath = path5.normalize(filePath);
7087
+ const resolvedPath = path5.resolve(process.cwd(), normalizedPath);
7088
+ const cwd = path5.resolve(process.cwd());
7189
7089
  if (!resolvedPath.startsWith(cwd)) {
7190
7090
  throw new Error(`Access denied: Cannot create files outside of current working directory`);
7191
7091
  }
7192
7092
  const fileExists = existsSync3(resolvedPath);
7193
7093
  const action = fileExists ? "overwritten" : "created";
7194
7094
  if (createDirectories) {
7195
- const dir = path7.dirname(resolvedPath);
7196
- await fs8.mkdir(dir, { recursive: true });
7095
+ const dir = path5.dirname(resolvedPath);
7096
+ await fs6.mkdir(dir, { recursive: true });
7197
7097
  }
7198
- await fs8.writeFile(resolvedPath, content, "utf-8");
7199
- const stats = await fs8.stat(resolvedPath);
7098
+ await fs6.writeFile(resolvedPath, content, "utf-8");
7099
+ const stats = await fs6.stat(resolvedPath);
7200
7100
  const lines = content.split("\n").length;
7201
7101
  return `File ${action} successfully: ${filePath}
7202
7102
  Size: ${stats.size} bytes
@@ -7207,7 +7107,7 @@ var createFileTool = {
7207
7107
  implementation: (context) => ({
7208
7108
  toolFn: async (value) => {
7209
7109
  const params = value;
7210
- const fileExists = existsSync3(path7.resolve(process.cwd(), path7.normalize(params.path)));
7110
+ const fileExists = existsSync3(path5.resolve(process.cwd(), path5.normalize(params.path)));
7211
7111
  context.logger.info(`\u{1F4DD} CreateFile: ${fileExists ? "Overwriting" : "Creating"} file`, {
7212
7112
  path: params.path,
7213
7113
  size: params.content.length
@@ -7248,8 +7148,8 @@ var createFileTool = {
7248
7148
 
7249
7149
  // ../../b4m-core/packages/services/dist/src/llm/tools/implementation/globFiles/index.js
7250
7150
  import { readdir } from "fs/promises";
7251
- import { statSync as statSync4 } from "fs";
7252
- import path8 from "path";
7151
+ import { statSync as statSync2 } from "fs";
7152
+ import path6 from "path";
7253
7153
  function matchGlob(filePath, pattern) {
7254
7154
  let regexPattern = pattern.replace(/\./g, "\\.").replace(/\*\*/g, "{{GLOBSTAR}}").replace(/\*/g, "[^/]*").replace(/\?/g, ".").replace(/\{([^}]+)\}/g, (_, options) => `(${options.split(",").join("|")})`).replace(/\[([^\]]+)\]/g, "[$1]");
7255
7155
  regexPattern = regexPattern.replace(/\{\{GLOBSTAR\}\}\//g, "(.*/)?").replace(/\/\{\{GLOBSTAR\}\}/g, "(/.*)?").replace(/\{\{GLOBSTAR\}\}/g, ".*");
@@ -7267,8 +7167,8 @@ async function walkDir(dir, pattern, includeHidden, maxResults, basePath = "") {
7267
7167
  if (!includeHidden && entry.name.startsWith(".")) {
7268
7168
  continue;
7269
7169
  }
7270
- const relativePath = basePath ? path8.join(basePath, entry.name) : entry.name;
7271
- const fullPath = path8.join(dir, entry.name);
7170
+ const relativePath = basePath ? path6.join(basePath, entry.name) : entry.name;
7171
+ const fullPath = path6.join(dir, entry.name);
7272
7172
  if (matchGlob(relativePath, pattern)) {
7273
7173
  matches.push(relativePath);
7274
7174
  }
@@ -7284,7 +7184,7 @@ async function walkDir(dir, pattern, includeHidden, maxResults, basePath = "") {
7284
7184
  async function listFiles(params) {
7285
7185
  const { pattern, cwd: relativeCwd, includeHidden = false, maxResults = 1e3 } = params;
7286
7186
  const baseCwd = process.cwd();
7287
- const targetCwd = relativeCwd ? path8.resolve(baseCwd, path8.normalize(relativeCwd)) : baseCwd;
7187
+ const targetCwd = relativeCwd ? path6.resolve(baseCwd, path6.normalize(relativeCwd)) : baseCwd;
7288
7188
  if (!targetCwd.startsWith(baseCwd)) {
7289
7189
  throw new Error(`Access denied: Cannot list files outside of current working directory`);
7290
7190
  }
@@ -7295,8 +7195,8 @@ async function listFiles(params) {
7295
7195
  const filesInfo = [];
7296
7196
  for (const match of matches) {
7297
7197
  try {
7298
- const fullPath = path8.join(targetCwd, match);
7299
- const stats = statSync4(fullPath);
7198
+ const fullPath = path6.join(targetCwd, match);
7199
+ const stats = statSync2(fullPath);
7300
7200
  filesInfo.push({
7301
7201
  path: match,
7302
7202
  size: stats.size,
@@ -7377,9 +7277,9 @@ var globFilesTool = {
7377
7277
 
7378
7278
  // ../../b4m-core/packages/services/dist/src/llm/tools/implementation/grepSearch/index.js
7379
7279
  import { readdir as readdir2 } from "fs/promises";
7380
- import { readFileSync as readFileSync2, statSync as statSync5 } from "fs";
7381
- import path9 from "path";
7382
- var MAX_FILE_SIZE3 = 10 * 1024 * 1024;
7280
+ import { readFileSync, statSync as statSync3 } from "fs";
7281
+ import path7 from "path";
7282
+ var MAX_FILE_SIZE2 = 10 * 1024 * 1024;
7383
7283
  function matchGlob2(filePath, pattern) {
7384
7284
  const regexPattern = pattern.replace(/\./g, "\\.").replace(/\*\*/g, "{{GLOBSTAR}}").replace(/\*/g, "[^/]*").replace(/\{\{GLOBSTAR\}\}/g, ".*").replace(/\?/g, ".").replace(/\{([^}]+)\}/g, (_, options) => `(${options.split(",").join("|")})`).replace(/\[([^\]]+)\]/g, "[$1]");
7385
7285
  const regex = new RegExp(`^${regexPattern}$`);
@@ -7396,8 +7296,8 @@ async function walkDir2(dir, pattern, maxResults, basePath = "") {
7396
7296
  if (entry.name.startsWith(".")) {
7397
7297
  continue;
7398
7298
  }
7399
- const relativePath = basePath ? path9.join(basePath, entry.name) : entry.name;
7400
- const fullPath = path9.join(dir, entry.name);
7299
+ const relativePath = basePath ? path7.join(basePath, entry.name) : entry.name;
7300
+ const fullPath = path7.join(dir, entry.name);
7401
7301
  if (matchGlob2(relativePath, pattern)) {
7402
7302
  matches.push(relativePath);
7403
7303
  }
@@ -7410,10 +7310,10 @@ async function walkDir2(dir, pattern, maxResults, basePath = "") {
7410
7310
  }
7411
7311
  return matches;
7412
7312
  }
7413
- async function searchFiles2(params) {
7313
+ async function searchFiles(params) {
7414
7314
  const { pattern, filePattern = "**/*", cwd: relativeCwd, caseSensitive = false, maxResults = 100, contextLines = 0 } = params;
7415
7315
  const baseCwd = process.cwd();
7416
- const targetCwd = relativeCwd ? path9.resolve(baseCwd, path9.normalize(relativeCwd)) : baseCwd;
7316
+ const targetCwd = relativeCwd ? path7.resolve(baseCwd, path7.normalize(relativeCwd)) : baseCwd;
7417
7317
  if (!targetCwd.startsWith(baseCwd)) {
7418
7318
  throw new Error(`Access denied: Cannot search files outside of current working directory`);
7419
7319
  }
@@ -7427,13 +7327,13 @@ async function searchFiles2(params) {
7427
7327
  const filesToSearch = await walkDir2(targetCwd, filePattern, 1e4);
7428
7328
  const filteredFiles = [];
7429
7329
  for (const match of filesToSearch) {
7430
- const fullPath = path9.join(targetCwd, match);
7330
+ const fullPath = path7.join(targetCwd, match);
7431
7331
  try {
7432
- const stats = statSync5(fullPath);
7433
- if (stats.isDirectory() || stats.size > MAX_FILE_SIZE3) {
7332
+ const stats = statSync3(fullPath);
7333
+ if (stats.isDirectory() || stats.size > MAX_FILE_SIZE2) {
7434
7334
  continue;
7435
7335
  }
7436
- if (isBinaryFile2(fullPath)) {
7336
+ if (isBinaryFile(fullPath)) {
7437
7337
  continue;
7438
7338
  }
7439
7339
  filteredFiles.push(match);
@@ -7451,9 +7351,9 @@ async function searchFiles2(params) {
7451
7351
  break;
7452
7352
  }
7453
7353
  filesSearched++;
7454
- const fullPath = path9.join(targetCwd, file);
7354
+ const fullPath = path7.join(targetCwd, file);
7455
7355
  try {
7456
- const content = readFileSync2(fullPath, "utf-8");
7356
+ const content = readFileSync(fullPath, "utf-8");
7457
7357
  const lines = content.split("\n");
7458
7358
  for (let i = 0; i < lines.length; i++) {
7459
7359
  if (matches.length >= maxResults) {
@@ -7517,7 +7417,7 @@ ${match.context.after.map((l) => ` ${l}`).join("\n")}`;
7517
7417
  }).join("\n");
7518
7418
  return `${summary}${patternInfo}${cwdInfo}${matchesList}`;
7519
7419
  }
7520
- function isBinaryFile2(filePath) {
7420
+ function isBinaryFile(filePath) {
7521
7421
  try {
7522
7422
  const buffer = Buffer.alloc(8192);
7523
7423
  const fd = __require("fs").openSync(filePath, "r");
@@ -7540,7 +7440,7 @@ var grepSearchTool = {
7540
7440
  cwd: params.cwd || "."
7541
7441
  });
7542
7442
  try {
7543
- const result = await searchFiles2(params);
7443
+ const result = await searchFiles(params);
7544
7444
  context.logger.info("\u2705 GrepSearch: Success");
7545
7445
  return result;
7546
7446
  } catch (error) {
@@ -7586,31 +7486,31 @@ var grepSearchTool = {
7586
7486
  };
7587
7487
 
7588
7488
  // ../../b4m-core/packages/services/dist/src/llm/tools/implementation/deleteFile/index.js
7589
- import { promises as fs9 } from "fs";
7590
- import { existsSync as existsSync4, statSync as statSync6 } from "fs";
7591
- import path10 from "path";
7489
+ import { promises as fs7 } from "fs";
7490
+ import { existsSync as existsSync4, statSync as statSync4 } from "fs";
7491
+ import path8 from "path";
7592
7492
  async function deleteFile(params) {
7593
7493
  const { path: filePath, recursive = false } = params;
7594
- const normalizedPath = path10.normalize(filePath);
7595
- const resolvedPath = path10.resolve(process.cwd(), normalizedPath);
7596
- const cwd = path10.resolve(process.cwd());
7494
+ const normalizedPath = path8.normalize(filePath);
7495
+ const resolvedPath = path8.resolve(process.cwd(), normalizedPath);
7496
+ const cwd = path8.resolve(process.cwd());
7597
7497
  if (!resolvedPath.startsWith(cwd)) {
7598
7498
  throw new Error(`Access denied: Cannot delete files outside of current working directory`);
7599
7499
  }
7600
7500
  if (!existsSync4(resolvedPath)) {
7601
7501
  throw new Error(`File or directory not found: ${filePath}`);
7602
7502
  }
7603
- const stats = statSync6(resolvedPath);
7503
+ const stats = statSync4(resolvedPath);
7604
7504
  const isDirectory = stats.isDirectory();
7605
7505
  const size = stats.size;
7606
7506
  if (isDirectory && !recursive) {
7607
7507
  throw new Error(`Path is a directory: ${filePath}. Use recursive=true to delete directories and their contents.`);
7608
7508
  }
7609
7509
  if (isDirectory) {
7610
- await fs9.rm(resolvedPath, { recursive: true, force: true });
7510
+ await fs7.rm(resolvedPath, { recursive: true, force: true });
7611
7511
  return `Directory deleted successfully: ${filePath}`;
7612
7512
  } else {
7613
- await fs9.unlink(resolvedPath);
7513
+ await fs7.unlink(resolvedPath);
7614
7514
  return `File deleted successfully: ${filePath}
7615
7515
  Size: ${size} bytes`;
7616
7516
  }
@@ -7620,8 +7520,8 @@ var deleteFileTool = {
7620
7520
  implementation: (context) => ({
7621
7521
  toolFn: async (value) => {
7622
7522
  const params = value;
7623
- const resolvedPath = path10.resolve(process.cwd(), path10.normalize(params.path));
7624
- const isDirectory = existsSync4(resolvedPath) && statSync6(resolvedPath).isDirectory();
7523
+ const resolvedPath = path8.resolve(process.cwd(), path8.normalize(params.path));
7524
+ const isDirectory = existsSync4(resolvedPath) && statSync4(resolvedPath).isDirectory();
7625
7525
  context.logger.info(`\u{1F5D1}\uFE0F DeleteFile: Deleting ${isDirectory ? "directory" : "file"}`, {
7626
7526
  path: params.path,
7627
7527
  recursive: params.recursive
@@ -7799,42 +7699,42 @@ var DISABLE_SERVER_THROTTLING = process.env.DISABLE_SERVER_THROTTLING === "true"
7799
7699
  var questSaveMutex = new Mutex();
7800
7700
 
7801
7701
  // ../../b4m-core/packages/services/dist/src/llm/ChatCompletion.js
7802
- var QuestStartBodySchema = z138.object({
7803
- userId: z138.string(),
7804
- sessionId: z138.string(),
7805
- questId: z138.string(),
7806
- message: z138.string(),
7807
- messageFileIds: z138.array(z138.string()),
7808
- historyCount: z138.number(),
7809
- fabFileIds: z138.array(z138.string()),
7702
+ var QuestStartBodySchema = z137.object({
7703
+ userId: z137.string(),
7704
+ sessionId: z137.string(),
7705
+ questId: z137.string(),
7706
+ message: z137.string(),
7707
+ messageFileIds: z137.array(z137.string()),
7708
+ historyCount: z137.number(),
7709
+ fabFileIds: z137.array(z137.string()),
7810
7710
  params: ChatCompletionCreateInputSchema,
7811
7711
  dashboardParams: DashboardParamsSchema.optional(),
7812
- enableQuestMaster: z138.boolean().optional(),
7813
- enableMementos: z138.boolean().optional(),
7814
- enableArtifacts: z138.boolean().optional(),
7815
- enableAgents: z138.boolean().optional(),
7712
+ enableQuestMaster: z137.boolean().optional(),
7713
+ enableMementos: z137.boolean().optional(),
7714
+ enableArtifacts: z137.boolean().optional(),
7715
+ enableAgents: z137.boolean().optional(),
7816
7716
  promptMeta: PromptMetaZodSchema,
7817
- tools: z138.array(z138.union([b4mLLMTools, z138.string()])).optional(),
7818
- mcpServers: z138.array(z138.string()).optional(),
7819
- projectId: z138.string().optional(),
7820
- organizationId: z138.string().nullable().optional(),
7717
+ tools: z137.array(z137.union([b4mLLMTools, z137.string()])).optional(),
7718
+ mcpServers: z137.array(z137.string()).optional(),
7719
+ projectId: z137.string().optional(),
7720
+ organizationId: z137.string().nullable().optional(),
7821
7721
  questMaster: QuestMasterParamsSchema.optional(),
7822
- toolPromptId: z138.string().optional(),
7722
+ toolPromptId: z137.string().optional(),
7823
7723
  researchMode: ResearchModeParamsSchema.optional(),
7824
- fallbackModel: z138.string().optional(),
7825
- embeddingModel: z138.string().optional(),
7826
- queryComplexity: z138.string(),
7724
+ fallbackModel: z137.string().optional(),
7725
+ embeddingModel: z137.string().optional(),
7726
+ queryComplexity: z137.string(),
7827
7727
  imageConfig: GenerateImageToolCallSchema.optional(),
7828
- deepResearchConfig: z138.object({
7829
- maxDepth: z138.number().optional(),
7830
- duration: z138.number().optional(),
7728
+ deepResearchConfig: z137.object({
7729
+ maxDepth: z137.number().optional(),
7730
+ duration: z137.number().optional(),
7831
7731
  // Note: searchers are passed via ToolContext and not through this API schema
7832
- searchers: z138.array(z138.any()).optional()
7732
+ searchers: z137.array(z137.any()).optional()
7833
7733
  }).optional(),
7834
- extraContextMessages: z138.array(z138.object({
7835
- role: z138.enum(["user", "assistant", "system", "function", "tool"]),
7836
- content: z138.union([z138.string(), z138.array(z138.any())]),
7837
- fabFileIds: z138.array(z138.string()).optional()
7734
+ extraContextMessages: z137.array(z137.object({
7735
+ role: z137.enum(["user", "assistant", "system", "function", "tool"]),
7736
+ content: z137.union([z137.string(), z137.array(z137.any())]),
7737
+ fabFileIds: z137.array(z137.string()).optional()
7838
7738
  })).optional()
7839
7739
  });
7840
7740
 
@@ -7842,9 +7742,30 @@ var QuestStartBodySchema = z138.object({
7842
7742
  import axios8 from "axios";
7843
7743
  import { fileTypeFromBuffer as fileTypeFromBuffer4 } from "file-type";
7844
7744
  import { v4 as uuidv47 } from "uuid";
7845
- import { z as z139 } from "zod";
7745
+ import { z as z138 } from "zod";
7846
7746
  import { fromZodError as fromZodError2 } from "zod-validation-error";
7847
7747
  var ImageGenerationBodySchema = OpenAIImageGenerationInput.extend({
7748
+ sessionId: z138.string(),
7749
+ questId: z138.string(),
7750
+ userId: z138.string(),
7751
+ prompt: z138.string(),
7752
+ safety_tolerance: z138.number().min(BFL_SAFETY_TOLERANCE.MIN).max(BFL_SAFETY_TOLERANCE.MAX).optional().default(BFL_SAFETY_TOLERANCE.DEFAULT),
7753
+ prompt_upsampling: z138.boolean().optional().default(false),
7754
+ seed: z138.number().nullable().optional(),
7755
+ output_format: z138.enum(["jpeg", "png"]).nullable().optional().default("png"),
7756
+ width: z138.number().optional(),
7757
+ height: z138.number().optional(),
7758
+ aspect_ratio: z138.string().optional(),
7759
+ fabFileIds: z138.array(z138.string()).optional()
7760
+ });
7761
+
7762
+ // ../../b4m-core/packages/services/dist/src/llm/ImageEdit.js
7763
+ import axios9 from "axios";
7764
+ import { fileTypeFromBuffer as fileTypeFromBuffer5 } from "file-type";
7765
+ import { v4 as uuidv48 } from "uuid";
7766
+ import { z as z139 } from "zod";
7767
+ import { fromZodError as fromZodError3 } from "zod-validation-error";
7768
+ var ImageEditBodySchema = OpenAIImageGenerationInput.extend({
7848
7769
  sessionId: z139.string(),
7849
7770
  questId: z139.string(),
7850
7771
  userId: z139.string(),
@@ -7852,56 +7773,35 @@ var ImageGenerationBodySchema = OpenAIImageGenerationInput.extend({
7852
7773
  safety_tolerance: z139.number().min(BFL_SAFETY_TOLERANCE.MIN).max(BFL_SAFETY_TOLERANCE.MAX).optional().default(BFL_SAFETY_TOLERANCE.DEFAULT),
7853
7774
  prompt_upsampling: z139.boolean().optional().default(false),
7854
7775
  seed: z139.number().nullable().optional(),
7855
- output_format: z139.enum(["jpeg", "png"]).nullable().optional().default("png"),
7776
+ output_format: z139.enum(["jpeg", "png"]).optional().default("png"),
7856
7777
  width: z139.number().optional(),
7857
7778
  height: z139.number().optional(),
7858
7779
  aspect_ratio: z139.string().optional(),
7859
- fabFileIds: z139.array(z139.string()).optional()
7860
- });
7861
-
7862
- // ../../b4m-core/packages/services/dist/src/llm/ImageEdit.js
7863
- import axios9 from "axios";
7864
- import { fileTypeFromBuffer as fileTypeFromBuffer5 } from "file-type";
7865
- import { v4 as uuidv48 } from "uuid";
7866
- import { z as z140 } from "zod";
7867
- import { fromZodError as fromZodError3 } from "zod-validation-error";
7868
- var ImageEditBodySchema = OpenAIImageGenerationInput.extend({
7869
- sessionId: z140.string(),
7870
- questId: z140.string(),
7871
- userId: z140.string(),
7872
- prompt: z140.string(),
7873
- safety_tolerance: z140.number().min(BFL_SAFETY_TOLERANCE.MIN).max(BFL_SAFETY_TOLERANCE.MAX).optional().default(BFL_SAFETY_TOLERANCE.DEFAULT),
7874
- prompt_upsampling: z140.boolean().optional().default(false),
7875
- seed: z140.number().nullable().optional(),
7876
- output_format: z140.enum(["jpeg", "png"]).optional().default("png"),
7877
- width: z140.number().optional(),
7878
- height: z140.number().optional(),
7879
- aspect_ratio: z140.string().optional(),
7880
- size: z140.string().optional(),
7881
- fabFileIds: z140.array(z140.string()).optional(),
7882
- image: z140.string()
7780
+ size: z139.string().optional(),
7781
+ fabFileIds: z139.array(z139.string()).optional(),
7782
+ image: z139.string()
7883
7783
  });
7884
7784
 
7885
7785
  // ../../b4m-core/packages/services/dist/src/llm/refineText.js
7886
- import { z as z141 } from "zod";
7887
- var refineTextLLMSchema = z141.object({
7888
- text: z141.string(),
7889
- context: z141.string().optional()
7786
+ import { z as z140 } from "zod";
7787
+ var refineTextLLMSchema = z140.object({
7788
+ text: z140.string(),
7789
+ context: z140.string().optional()
7890
7790
  // tone: z.enum(['formal', 'informal', 'neutral']).optional(),
7891
7791
  // style: z.enum(['technical', 'creative', 'academic', 'business', 'narrative']).optional(),
7892
7792
  });
7893
7793
 
7894
7794
  // ../../b4m-core/packages/services/dist/src/llm/MementoEvaluationService.js
7895
- import { z as z142 } from "zod";
7896
- var SingleMementoEvalSchema = z142.object({
7897
- importance: z142.number().min(1).max(10),
7795
+ import { z as z141 } from "zod";
7796
+ var SingleMementoEvalSchema = z141.object({
7797
+ importance: z141.number().min(1).max(10),
7898
7798
  // 1-10 scale for personal info importance
7899
- summary: z142.string(),
7900
- tags: z142.array(z142.string()).optional()
7799
+ summary: z141.string(),
7800
+ tags: z141.array(z141.string()).optional()
7901
7801
  });
7902
- var MementoEvalResponseSchema = z142.object({
7903
- isPersonal: z142.boolean(),
7904
- mementos: z142.array(SingleMementoEvalSchema).optional()
7802
+ var MementoEvalResponseSchema = z141.object({
7803
+ isPersonal: z141.boolean(),
7804
+ mementos: z141.array(SingleMementoEvalSchema).optional()
7905
7805
  // Array of distinct personal information
7906
7806
  });
7907
7807
 
@@ -7947,7 +7847,7 @@ async function generateFileDeletePreview(args) {
7947
7847
  if (!existsSync5(args.path)) {
7948
7848
  return `[File does not exist: ${args.path}]`;
7949
7849
  }
7950
- const stats = await import("fs/promises").then((fs11) => fs11.stat(args.path));
7850
+ const stats = await import("fs/promises").then((fs9) => fs9.stat(args.path));
7951
7851
  return `[File will be deleted]
7952
7852
 
7953
7853
  Path: ${args.path}
@@ -7963,21 +7863,21 @@ var NoOpStorage = class extends BaseStorage {
7963
7863
  async upload(input, destination, options) {
7964
7864
  return `/tmp/${destination}`;
7965
7865
  }
7966
- async download(path13) {
7866
+ async download(path11) {
7967
7867
  throw new Error("Download not supported in CLI");
7968
7868
  }
7969
- async delete(path13) {
7869
+ async delete(path11) {
7970
7870
  }
7971
- async getSignedUrl(path13) {
7972
- return `/tmp/${path13}`;
7871
+ async getSignedUrl(path11) {
7872
+ return `/tmp/${path11}`;
7973
7873
  }
7974
- getPublicUrl(path13) {
7975
- return `/tmp/${path13}`;
7874
+ getPublicUrl(path11) {
7875
+ return `/tmp/${path11}`;
7976
7876
  }
7977
- async getPreview(path13) {
7978
- return `/tmp/${path13}`;
7877
+ async getPreview(path11) {
7878
+ return `/tmp/${path11}`;
7979
7879
  }
7980
- async getMetadata(path13) {
7880
+ async getMetadata(path11) {
7981
7881
  return { size: 0, contentType: "application/octet-stream" };
7982
7882
  }
7983
7883
  };
@@ -7997,7 +7897,7 @@ var CliLogger = class extends Logger {
7997
7897
  log(...args) {
7998
7898
  }
7999
7899
  };
8000
- function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, agentContext) {
7900
+ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, agentContext, configStore) {
8001
7901
  const originalFn = tool.toolFn;
8002
7902
  const toolName = tool.toolSchema.name;
8003
7903
  return {
@@ -8041,7 +7941,25 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
8041
7941
  throw new PermissionDeniedError(toolName, args);
8042
7942
  }
8043
7943
  if (response.action === "allow-always") {
8044
- permissionManager.trustTool(toolName);
7944
+ const canTrust = permissionManager.trustTool(toolName);
7945
+ if (canTrust) {
7946
+ const projectDir = configStore.getProjectConfigDir();
7947
+ if (projectDir) {
7948
+ try {
7949
+ await configStore.initProjectConfig();
7950
+ const existingLocal = await configStore.loadRawProjectLocalConfig() || {};
7951
+ const updatedLocal = {
7952
+ ...existingLocal,
7953
+ trustedTools: [...existingLocal.trustedTools || [], toolName]
7954
+ };
7955
+ await configStore.saveProjectLocalConfig(updatedLocal);
7956
+ } catch (error) {
7957
+ await configStore.trustTool(toolName);
7958
+ }
7959
+ } else {
7960
+ await configStore.trustTool(toolName);
7961
+ }
7962
+ }
8045
7963
  }
8046
7964
  const result = await originalFn(args);
8047
7965
  agentContext.observationQueue.push({ toolName, result });
@@ -8049,7 +7967,7 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
8049
7967
  }
8050
7968
  };
8051
7969
  }
8052
- function generateCliTools(userId, llm, model, permissionManager, showPermissionPrompt, agentContext, toolApiKeys) {
7970
+ function generateCliTools(userId, llm, model, permissionManager, showPermissionPrompt, agentContext, configStore, toolApiKeys) {
8053
7971
  const logger2 = new CliLogger();
8054
7972
  const storage = new NoOpStorage();
8055
7973
  const user = {
@@ -8133,13 +8051,15 @@ function generateCliTools(userId, llm, model, permissionManager, showPermissionP
8133
8051
  toolConfig,
8134
8052
  model
8135
8053
  );
8136
- const tools2 = Object.entries(toolsMap).filter(([key]) => toolConfig[key] !== void 0).map(([_, tool]) => wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, agentContext));
8054
+ const tools2 = Object.entries(toolsMap).filter(([key]) => toolConfig[key] !== void 0).map(
8055
+ ([_, tool]) => wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, agentContext, configStore)
8056
+ );
8137
8057
  return { tools: tools2, agentContext };
8138
8058
  }
8139
8059
 
8140
8060
  // src/config/toolSafety.ts
8141
- import { z as z143 } from "zod";
8142
- var ToolCategorySchema = z143.enum([
8061
+ import { z as z142 } from "zod";
8062
+ var ToolCategorySchema = z142.enum([
8143
8063
  "auto_approve",
8144
8064
  // Safe tools that run automatically without permission
8145
8065
  "prompt_always",
@@ -8147,9 +8067,9 @@ var ToolCategorySchema = z143.enum([
8147
8067
  "prompt_default"
8148
8068
  // Tools that prompt by default but can be trusted
8149
8069
  ]);
8150
- var ToolSafetyConfigSchema = z143.object({
8151
- categories: z143.record(z143.string(), ToolCategorySchema),
8152
- trustedTools: z143.array(z143.string())
8070
+ var ToolSafetyConfigSchema = z142.object({
8071
+ categories: z142.record(z142.string(), ToolCategorySchema),
8072
+ trustedTools: z142.array(z142.string())
8153
8073
  });
8154
8074
  var DEFAULT_TOOL_CATEGORIES = {
8155
8075
  // ===== AUTO APPROVE (Safe tools) =====
@@ -8198,23 +8118,30 @@ function canTrustTool(toolName, customCategories) {
8198
8118
 
8199
8119
  // src/utils/PermissionManager.ts
8200
8120
  var PermissionManager = class {
8201
- constructor(trustedTools = [], customCategories) {
8121
+ constructor(trustedTools = [], customCategories, deniedTools) {
8202
8122
  this.trustedTools = /* @__PURE__ */ new Set();
8123
+ this.deniedTools = /* @__PURE__ */ new Set();
8203
8124
  this.trustedTools = new Set(trustedTools);
8204
8125
  this.customCategories = new Map(Object.entries(customCategories || {}));
8126
+ this.deniedTools = new Set(deniedTools || []);
8205
8127
  }
8206
8128
  /**
8207
8129
  * Check if a tool needs permission before execution
8208
8130
  *
8209
8131
  * A tool needs permission if:
8210
- * 1. It's not in the auto_approve category, AND
8211
- * 2. It's not in the trusted tools set
8132
+ * 1. It's in the denied tools list (from project config), OR
8133
+ * 2. It's not in the auto_approve category, AND
8134
+ * 3. It's not in the trusted tools set
8212
8135
  *
8213
8136
  * Note: prompt_always tools CANNOT be trusted, so they always need permission
8137
+ * Note: denied tools from project config ALWAYS need permission (cannot be overridden locally)
8214
8138
  */
8215
8139
  needsPermission(toolName) {
8216
8140
  const categoryMap = Object.fromEntries(this.customCategories);
8217
8141
  const category = getToolCategory(toolName, categoryMap);
8142
+ if (this.deniedTools.has(toolName)) {
8143
+ return true;
8144
+ }
8218
8145
  if (category === "auto_approve") {
8219
8146
  return false;
8220
8147
  }
@@ -8225,10 +8152,13 @@ var PermissionManager = class {
8225
8152
  }
8226
8153
  /**
8227
8154
  * Add a tool to the trusted list
8228
- * Returns false if the tool cannot be trusted (prompt_always category)
8155
+ * Returns false if the tool cannot be trusted (prompt_always category or denied by project)
8229
8156
  */
8230
8157
  trustTool(toolName) {
8231
8158
  const categoryMap = Object.fromEntries(this.customCategories);
8159
+ if (this.deniedTools.has(toolName)) {
8160
+ return false;
8161
+ }
8232
8162
  if (!canTrustTool(toolName, categoryMap)) {
8233
8163
  return false;
8234
8164
  }
@@ -8261,12 +8191,27 @@ var PermissionManager = class {
8261
8191
  return getToolCategory(toolName, categoryMap);
8262
8192
  }
8263
8193
  /**
8264
- * Check if a tool can be trusted (not in prompt_always category)
8194
+ * Check if a tool can be trusted (not in prompt_always category or denied by project)
8265
8195
  */
8266
8196
  canBeTrusted(toolName) {
8267
8197
  const categoryMap = Object.fromEntries(this.customCategories);
8198
+ if (this.deniedTools.has(toolName)) {
8199
+ return false;
8200
+ }
8268
8201
  return canTrustTool(toolName, categoryMap);
8269
8202
  }
8203
+ /**
8204
+ * Check if a tool is denied by project config
8205
+ */
8206
+ isDenied(toolName) {
8207
+ return this.deniedTools.has(toolName);
8208
+ }
8209
+ /**
8210
+ * Get list of denied tools
8211
+ */
8212
+ getDeniedTools() {
8213
+ return Array.from(this.deniedTools).sort();
8214
+ }
8270
8215
  /**
8271
8216
  * Clear all trusted tools
8272
8217
  */
@@ -8303,8 +8248,8 @@ function getEnvironmentName(configApiConfig) {
8303
8248
  }
8304
8249
 
8305
8250
  // src/utils/Logger.ts
8306
- import fs10 from "fs/promises";
8307
- import path11 from "path";
8251
+ import fs8 from "fs/promises";
8252
+ import path9 from "path";
8308
8253
  import os from "os";
8309
8254
  var Logger2 = class _Logger {
8310
8255
  constructor() {
@@ -8327,9 +8272,9 @@ var Logger2 = class _Logger {
8327
8272
  */
8328
8273
  async initialize(sessionId) {
8329
8274
  this.sessionId = sessionId;
8330
- const debugDir = path11.join(os.homedir(), ".bike4mind", "debug");
8331
- await fs10.mkdir(debugDir, { recursive: true });
8332
- this.logFilePath = path11.join(debugDir, `${sessionId}.txt`);
8275
+ const debugDir = path9.join(os.homedir(), ".bike4mind", "debug");
8276
+ await fs8.mkdir(debugDir, { recursive: true });
8277
+ this.logFilePath = path9.join(debugDir, `${sessionId}.txt`);
8333
8278
  await this.writeToFile("INFO", "=== CLI SESSION START ===");
8334
8279
  }
8335
8280
  /**
@@ -8393,7 +8338,7 @@ var Logger2 = class _Logger {
8393
8338
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").substring(0, 19);
8394
8339
  const logEntry = `[${timestamp}] [${level}] ${message}
8395
8340
  `;
8396
- await fs10.appendFile(this.logFilePath, logEntry, "utf-8");
8341
+ await fs8.appendFile(this.logFilePath, logEntry, "utf-8");
8397
8342
  } catch (error) {
8398
8343
  console.error("File logging failed:", error);
8399
8344
  }
@@ -8539,15 +8484,15 @@ var Logger2 = class _Logger {
8539
8484
  async cleanupOldLogs() {
8540
8485
  if (!this.fileLoggingEnabled) return;
8541
8486
  try {
8542
- const debugDir = path11.join(os.homedir(), ".bike4mind", "debug");
8543
- const files = await fs10.readdir(debugDir);
8487
+ const debugDir = path9.join(os.homedir(), ".bike4mind", "debug");
8488
+ const files = await fs8.readdir(debugDir);
8544
8489
  const now = Date.now();
8545
8490
  const thirtyDaysAgo = now - 30 * 24 * 60 * 60 * 1e3;
8546
8491
  for (const file of files) {
8547
- const filePath = path11.join(debugDir, file);
8548
- const stats = await fs10.stat(filePath);
8492
+ const filePath = path9.join(debugDir, file);
8493
+ const stats = await fs8.stat(filePath);
8549
8494
  if (stats.mtime.getTime() < thirtyDaysAgo) {
8550
- await fs10.unlink(filePath);
8495
+ await fs8.unlink(filePath);
8551
8496
  }
8552
8497
  }
8553
8498
  } catch (error) {
@@ -8560,8 +8505,8 @@ var logger = Logger2.getInstance();
8560
8505
  // ../../b4m-core/packages/mcp/dist/src/client.js
8561
8506
  import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
8562
8507
  import { Client as Client2 } from "@modelcontextprotocol/sdk/client/index.js";
8563
- import path12 from "path";
8564
- import { existsSync as existsSync6, readdirSync as readdirSync3 } from "fs";
8508
+ import path10 from "path";
8509
+ import { existsSync as existsSync6, readdirSync } from "fs";
8565
8510
  var MCPClient = class {
8566
8511
  // Note: This class handles MCP server communication with repository filtering
8567
8512
  mcp;
@@ -8586,20 +8531,20 @@ var MCPClient = class {
8586
8531
  const root = process.env.INIT_CWD || process.cwd();
8587
8532
  const candidatePaths = [
8588
8533
  // When running from SST Lambda with node_modules structure (copyFiles)
8589
- path12.join(root, `node_modules/@bike4mind/mcp/dist/src/${this.serverName}/index.js`),
8534
+ path10.join(root, `node_modules/@bike4mind/mcp/dist/src/${this.serverName}/index.js`),
8590
8535
  // When running from SST Lambda deployed environment (/var/task)
8591
- path12.join(root, `b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
8536
+ path10.join(root, `b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
8592
8537
  // When running from SST Lambda (.sst/artifacts/mcpHandler-dev), navigate to monorepo root (3 levels up)
8593
- path12.join(root, `../../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
8538
+ path10.join(root, `../../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
8594
8539
  // When running from packages/client (Next.js app), navigate to monorepo root (2 levels up)
8595
- path12.join(root, `../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
8540
+ path10.join(root, `../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
8596
8541
  // Original paths (backward compatibility)
8597
- path12.join(root, `/b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
8598
- path12.join(root, "core", "mcp", "servers", this.serverName, "dist", "index.js")
8542
+ path10.join(root, `/b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
8543
+ path10.join(root, "core", "mcp", "servers", this.serverName, "dist", "index.js")
8599
8544
  ];
8600
8545
  const serverScriptPath = candidatePaths.find((p) => existsSync6(p));
8601
8546
  if (!serverScriptPath) {
8602
- const getDirectories = (source) => readdirSync3(source, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
8547
+ const getDirectories = (source) => readdirSync(source, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
8603
8548
  console.error(`[MCP] Server script not found. Tried paths:`, candidatePaths);
8604
8549
  console.error(`[MCP] Available directories in ${root}:`, getDirectories(root));
8605
8550
  throw new Error(`MCP Server script path not found for ${this.serverName}. Root: ${root}, Available dirs: ${getDirectories(root).join(", ")}`);
@@ -8628,7 +8573,7 @@ var MCPClient = class {
8628
8573
  }
8629
8574
  };
8630
8575
  await this.mcp.connect(this.transport);
8631
- await new Promise((resolve3) => setTimeout(resolve3, 100));
8576
+ await new Promise((resolve) => setTimeout(resolve, 100));
8632
8577
  const toolsResult = await this.mcp.listTools();
8633
8578
  this.tools = toolsResult.tools.map((tool) => {
8634
8579
  return {
@@ -8811,7 +8756,7 @@ var ServerLlmBackend = class {
8811
8756
  */
8812
8757
  async complete(model, messages, options, callback) {
8813
8758
  logger.debug(`[ServerLlmBackend] Starting complete() with model: ${model}`);
8814
- return new Promise(async (resolve3, reject) => {
8759
+ return new Promise(async (resolve, reject) => {
8815
8760
  try {
8816
8761
  logger.debug("[ServerLlmBackend] Making streaming request...");
8817
8762
  const response = await this.makeStreamingRequest(model, messages, options);
@@ -8841,15 +8786,15 @@ var ServerLlmBackend = class {
8841
8786
  reject(err);
8842
8787
  }).then(() => {
8843
8788
  logger.debug("[ServerLlmBackend] Callback completed, resolving");
8844
- resolve3();
8789
+ resolve();
8845
8790
  });
8846
8791
  } else if (cleanedText) {
8847
8792
  callback([cleanedText], lastUsageInfo).catch((err) => {
8848
8793
  logger.error("[ServerLlmBackend] Callback error:", err);
8849
8794
  reject(err);
8850
- }).then(() => resolve3());
8795
+ }).then(() => resolve());
8851
8796
  } else {
8852
- resolve3();
8797
+ resolve();
8853
8798
  }
8854
8799
  return;
8855
8800
  }
@@ -8909,7 +8854,7 @@ var ServerLlmBackend = class {
8909
8854
  response.data.on("end", () => {
8910
8855
  if (!receivedDone) {
8911
8856
  logger.debug("[ServerLlmBackend] Stream ended without [DONE], resolving anyway");
8912
- resolve3();
8857
+ resolve();
8913
8858
  } else {
8914
8859
  logger.debug("[ServerLlmBackend] Stream ended, [DONE] handler will resolve");
8915
8860
  }
@@ -9176,7 +9121,7 @@ var ApiClient = class {
9176
9121
  // package.json
9177
9122
  var package_default = {
9178
9123
  name: "@bike4mind/cli",
9179
- version: "0.2.1-feat-cli-file-reference.17023+cf6767ead",
9124
+ version: "0.2.1-feat-cli-project-scoped-config.16996+16c515189",
9180
9125
  type: "module",
9181
9126
  description: "Interactive CLI tool for Bike4Mind with ReAct agents",
9182
9127
  license: "UNLICENSED",
@@ -9187,9 +9132,6 @@ var package_default = {
9187
9132
  },
9188
9133
  homepage: "https://github.com/bike4mind/lumina5#readme",
9189
9134
  bugs: "https://github.com/bike4mind/lumina5/issues",
9190
- publishConfig: {
9191
- access: "public"
9192
- },
9193
9135
  keywords: [
9194
9136
  "cli",
9195
9137
  "ai",
@@ -9210,8 +9152,6 @@ var package_default = {
9210
9152
  dev: "tsx src/index.tsx",
9211
9153
  build: "tsup",
9212
9154
  typecheck: "tsc --noEmit",
9213
- test: "vitest run",
9214
- "test:watch": "vitest",
9215
9155
  start: "node dist/index.js",
9216
9156
  prepublishOnly: "pnpm build"
9217
9157
  },
@@ -9278,10 +9218,10 @@ var package_default = {
9278
9218
  },
9279
9219
  devDependencies: {
9280
9220
  "@bike4mind/agents": "0.1.0",
9281
- "@bike4mind/common": "2.36.1-feat-cli-file-reference.17023+cf6767ead",
9282
- "@bike4mind/mcp": "1.19.4-feat-cli-file-reference.17023+cf6767ead",
9283
- "@bike4mind/services": "2.29.1-feat-cli-file-reference.17023+cf6767ead",
9284
- "@bike4mind/utils": "2.0.3-feat-cli-file-reference.17023+cf6767ead",
9221
+ "@bike4mind/common": "2.36.1-feat-cli-project-scoped-config.16996+16c515189",
9222
+ "@bike4mind/mcp": "1.19.4-feat-cli-project-scoped-config.16996+16c515189",
9223
+ "@bike4mind/services": "2.29.1-feat-cli-project-scoped-config.16996+16c515189",
9224
+ "@bike4mind/utils": "2.0.3-feat-cli-project-scoped-config.16996+16c515189",
9285
9225
  "@types/diff": "^5.0.9",
9286
9226
  "@types/jsonwebtoken": "^9.0.4",
9287
9227
  "@types/node": "^22.9.0",
@@ -9290,10 +9230,9 @@ var package_default = {
9290
9230
  "@types/yargs": "^17.0.32",
9291
9231
  tsup: "^8.5.1",
9292
9232
  tsx: "^4.21.0",
9293
- typescript: "^5.9.3",
9294
- vitest: "^3.2.4"
9233
+ typescript: "^5.9.3"
9295
9234
  },
9296
- gitHead: "cf6767ead9e1a222e56d4b8114dfe9f9a8c2229b"
9235
+ gitHead: "16c515189f0b9a7e3ccea2c9874866dd2e8fe084"
9297
9236
  };
9298
9237
 
9299
9238
  // src/index.tsx
@@ -9316,7 +9255,8 @@ function CliApp() {
9316
9255
  agent: null,
9317
9256
  mcpManager: null,
9318
9257
  permissionManager: null,
9319
- permissionPrompt: null
9258
+ permissionPrompt: null,
9259
+ trustLocationSelector: null
9320
9260
  });
9321
9261
  const [isInitialized, setIsInitialized] = useState3(false);
9322
9262
  const [initError, setInitError] = useState3(null);
@@ -9345,7 +9285,7 @@ function CliApp() {
9345
9285
  }
9346
9286
  await Promise.race([
9347
9287
  Promise.all(cleanupTasks),
9348
- new Promise((resolve3) => setTimeout(resolve3, 500))
9288
+ new Promise((resolve) => setTimeout(resolve, 500))
9349
9289
  // 500ms timeout
9350
9290
  ]);
9351
9291
  setTimeout(() => {
@@ -9477,11 +9417,17 @@ function CliApp() {
9477
9417
  debug: () => {
9478
9418
  }
9479
9419
  };
9480
- const permissionManager = new PermissionManager(config.trustedTools || []);
9420
+ const permissionManager = new PermissionManager(
9421
+ config.trustedTools || [],
9422
+ void 0,
9423
+ // customCategories (not used yet)
9424
+ config.tools.disabled || []
9425
+ // denied tools from project config
9426
+ );
9481
9427
  const promptFn = (toolName, args, preview) => {
9482
- return new Promise((resolve3) => {
9428
+ return new Promise((resolve) => {
9483
9429
  const canBeTrusted = permissionManager.canBeTrusted(toolName);
9484
- const prompt = { toolName, args, preview, canBeTrusted, resolve: resolve3 };
9430
+ const prompt = { toolName, args, preview, canBeTrusted, resolve };
9485
9431
  setState((prev) => ({
9486
9432
  ...prev,
9487
9433
  permissionManager,
@@ -9505,6 +9451,7 @@ function CliApp() {
9505
9451
  permissionManager,
9506
9452
  promptFn,
9507
9453
  agentContext,
9454
+ state.configStore,
9508
9455
  config.toolApiKeys
9509
9456
  );
9510
9457
  console.log(`\u{1F6E0}\uFE0F Loaded ${b4mTools.length} B4M tool(s)`);
@@ -9683,6 +9630,9 @@ Tool Permissions:
9683
9630
  /trust <tool-name> - Trust a tool (won't ask permission again)
9684
9631
  /untrust <tool-name> - Remove tool from trusted list
9685
9632
  /trusted - List all trusted tools
9633
+
9634
+ Project Configuration:
9635
+ /project-config - Show merged project configuration
9686
9636
  `);
9687
9637
  break;
9688
9638
  case "exit":
@@ -9774,7 +9724,7 @@ Tool Permissions:
9774
9724
  console.log("");
9775
9725
  break;
9776
9726
  }
9777
- case "trust":
9727
+ case "trust": {
9778
9728
  if (!state.permissionManager) {
9779
9729
  console.log("Permission manager not initialized");
9780
9730
  return;
@@ -9782,16 +9732,85 @@ Tool Permissions:
9782
9732
  const toolToTrust = args[0];
9783
9733
  if (!toolToTrust) {
9784
9734
  console.log("Usage: /trust <tool-name>");
9735
+ console.log("");
9736
+ console.log("Example:");
9737
+ console.log(" /trust file_read - Opens interactive location selector");
9738
+ console.log("");
9785
9739
  return;
9786
9740
  }
9787
- const trusted = state.permissionManager.trustTool(toolToTrust);
9788
- if (trusted) {
9789
- await state.configStore.trustTool(toolToTrust);
9790
- console.log(`\u2705 Tool '${toolToTrust}' is now trusted and won't require permission`);
9791
- } else {
9792
- console.log(`\u274C Tool '${toolToTrust}' cannot be trusted (it's in the 'prompt_always' category)`);
9741
+ const canTrust = state.permissionManager.trustTool(toolToTrust);
9742
+ if (!canTrust) {
9743
+ if (state.permissionManager.isDenied(toolToTrust)) {
9744
+ console.log(`\u274C Tool '${toolToTrust}' is denied by project configuration and cannot be trusted`);
9745
+ } else {
9746
+ console.log(`\u274C Tool '${toolToTrust}' cannot be trusted (it's in the 'prompt_always' category)`);
9747
+ }
9748
+ return;
9793
9749
  }
9750
+ state.permissionManager.untrustTool(toolToTrust);
9751
+ const handleLocationSelect = async (location) => {
9752
+ setState((prev) => ({ ...prev, trustLocationSelector: null }));
9753
+ if (!location) {
9754
+ console.log("\u274C Trust operation cancelled");
9755
+ return;
9756
+ }
9757
+ const projectDir = state.configStore.getProjectConfigDir();
9758
+ switch (location) {
9759
+ case "local": {
9760
+ if (!projectDir) {
9761
+ console.log('\u274C No project found. Use "global" to save to ~/.bike4mind/config.json');
9762
+ return;
9763
+ }
9764
+ await state.configStore.initProjectConfig();
9765
+ const existingLocal = await state.configStore.loadRawProjectLocalConfig() || {};
9766
+ const updatedLocal = {
9767
+ ...existingLocal,
9768
+ trustedTools: [...existingLocal.trustedTools || [], toolToTrust]
9769
+ };
9770
+ await state.configStore.saveProjectLocalConfig(updatedLocal);
9771
+ state.permissionManager?.trustTool(toolToTrust);
9772
+ console.log(`\u2705 Tool '${toolToTrust}' trusted for this project only`);
9773
+ console.log(` Saved in: ${projectDir}/.bike4mind/local.json`);
9774
+ break;
9775
+ }
9776
+ case "project": {
9777
+ if (!projectDir) {
9778
+ console.log('\u274C No project found. Use "global" to save to ~/.bike4mind/config.json');
9779
+ return;
9780
+ }
9781
+ const existingProject = await state.configStore.loadRawProjectConfig() || {};
9782
+ const updatedProject = {
9783
+ ...existingProject,
9784
+ tools: {
9785
+ ...existingProject.tools,
9786
+ enabled: [...existingProject.tools?.enabled || [], toolToTrust]
9787
+ }
9788
+ };
9789
+ await state.configStore.saveProjectConfig(updatedProject);
9790
+ state.permissionManager?.trustTool(toolToTrust);
9791
+ console.log(`\u2705 Tool '${toolToTrust}' trusted for entire team`);
9792
+ console.log(` Saved in: ${projectDir}/.bike4mind/config.json`);
9793
+ console.log(" \u26A0\uFE0F Remember to commit this file to share with your team!");
9794
+ break;
9795
+ }
9796
+ case "global": {
9797
+ await state.configStore.trustTool(toolToTrust);
9798
+ state.permissionManager?.trustTool(toolToTrust);
9799
+ console.log(`\u2705 Tool '${toolToTrust}' trusted globally (all projects)`);
9800
+ console.log(" Saved in: ~/.bike4mind/config.json");
9801
+ break;
9802
+ }
9803
+ }
9804
+ };
9805
+ setState((prev) => ({
9806
+ ...prev,
9807
+ trustLocationSelector: {
9808
+ toolName: toolToTrust,
9809
+ resolve: handleLocationSelect
9810
+ }
9811
+ }));
9794
9812
  break;
9813
+ }
9795
9814
  case "untrust":
9796
9815
  if (!state.permissionManager) {
9797
9816
  console.log("Permission manager not initialized");
@@ -9840,6 +9859,50 @@ Tool Permissions:
9840
9859
  console.log(`Expires: ${new Date(authTokens.expiresAt).toLocaleString()}`);
9841
9860
  console.log("");
9842
9861
  break;
9862
+ case "project-config": {
9863
+ const projectDir = state.configStore.getProjectConfigDir();
9864
+ const config = await state.configStore.get();
9865
+ console.log("\n\u{1F4C1} Project Configuration:\n");
9866
+ if (projectDir) {
9867
+ console.log(`Project Directory: ${projectDir}/.bike4mind/`);
9868
+ console.log("");
9869
+ const projectConfig = await state.configStore.loadRawProjectConfig();
9870
+ const localConfig = await state.configStore.loadRawProjectLocalConfig();
9871
+ if (projectConfig) {
9872
+ console.log("Team Config (.bike4mind/config.json):");
9873
+ if (projectConfig.defaultModel) {
9874
+ console.log(` Default Model: ${projectConfig.defaultModel}`);
9875
+ }
9876
+ if (projectConfig.tools?.denied && projectConfig.tools.denied.length > 0) {
9877
+ console.log(` Denied Tools: ${projectConfig.tools.denied.join(", ")}`);
9878
+ }
9879
+ if (projectConfig.mcpServers && projectConfig.mcpServers.length > 0) {
9880
+ console.log(` MCP Servers: ${projectConfig.mcpServers.map((s) => s.name).join(", ")}`);
9881
+ }
9882
+ console.log("");
9883
+ }
9884
+ if (localConfig) {
9885
+ console.log("Local Config (.bike4mind/local.json):");
9886
+ if (localConfig.trustedTools && localConfig.trustedTools.length > 0) {
9887
+ console.log(` Trusted Tools: ${localConfig.trustedTools.join(", ")}`);
9888
+ }
9889
+ if (localConfig.mcpServers && localConfig.mcpServers.length > 0) {
9890
+ console.log(` MCP Servers: ${localConfig.mcpServers.map((s) => s.name).join(", ")}`);
9891
+ }
9892
+ console.log("");
9893
+ }
9894
+ console.log("Merged Configuration (what you're using):");
9895
+ console.log(` Default Model: ${config.defaultModel}`);
9896
+ console.log(` Trusted Tools: ${config.trustedTools?.length || 0} tools`);
9897
+ console.log(` Denied Tools: ${config.tools.disabled.length} tools`);
9898
+ console.log(` MCP Servers: ${config.mcpServers.length} servers`);
9899
+ } else {
9900
+ console.log("No project configuration found.");
9901
+ console.log("Tip: Create .bike4mind/config.json in your project root for team-wide settings.");
9902
+ }
9903
+ console.log("");
9904
+ break;
9905
+ }
9843
9906
  default:
9844
9907
  console.log(`Unknown command: /${command}`);
9845
9908
  console.log("Type /help for available commands");
@@ -9848,6 +9911,26 @@ Tool Permissions:
9848
9911
  if (initError) {
9849
9912
  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"));
9850
9913
  }
9914
+ if (state.trustLocationSelector) {
9915
+ const projectDir = state.configStore.getProjectConfigDir();
9916
+ const inProject = projectDir !== null;
9917
+ return /* @__PURE__ */ React11.createElement(
9918
+ TrustLocationSelector,
9919
+ {
9920
+ inProject,
9921
+ onSelect: (location) => {
9922
+ if (state.trustLocationSelector) {
9923
+ state.trustLocationSelector.resolve(location);
9924
+ }
9925
+ },
9926
+ onCancel: () => {
9927
+ if (state.trustLocationSelector) {
9928
+ state.trustLocationSelector.resolve(null);
9929
+ }
9930
+ }
9931
+ }
9932
+ );
9933
+ }
9851
9934
  if (state.showLoginFlow) {
9852
9935
  const loginApiUrl = getApiUrl(state.config?.apiConfig);
9853
9936
  return /* @__PURE__ */ React11.createElement(