@bike4mind/cli 0.2.1-feat-cli-file-reference.17024 → 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,65 +202,23 @@ function searchCommands(query) {
404
202
  }
405
203
 
406
204
  // src/components/InputPrompt.tsx
407
- function findAtTrigger(value) {
408
- for (let i = value.length - 1; i >= 0; i--) {
409
- if (value[i] === "@") {
410
- const isValid = i === 0 || value[i - 1] === " ";
411
- if (isValid) {
412
- const query = value.slice(i + 1);
413
- if (query.includes(" ")) {
414
- return null;
415
- }
416
- return { startIndex: i, query };
417
- }
418
- }
419
- }
420
- return null;
421
- }
422
205
  function InputPrompt({ onSubmit, disabled = false, history = [] }) {
423
206
  const [value, setValue] = useState("");
424
207
  const [selectedIndex, setSelectedIndex] = useState(0);
425
208
  const [historyIndex, setHistoryIndex] = useState(-1);
426
209
  const [tempInput, setTempInput] = useState("");
427
210
  const [inputKey, setInputKey] = useState(0);
428
- const [fileAutocomplete, setFileAutocomplete] = useState(null);
429
- const [fileSelectedIndex, setFileSelectedIndex] = useState(0);
430
- const shouldShowCommandAutocomplete = value.startsWith("/") && !disabled && !fileAutocomplete?.active;
431
- const commandQuery = shouldShowCommandAutocomplete ? value.slice(1) : "";
211
+ const shouldShowAutocomplete = value.startsWith("/") && !disabled;
212
+ const query = shouldShowAutocomplete ? value.slice(1) : "";
432
213
  const filteredCommands = useMemo(() => {
433
- if (!shouldShowCommandAutocomplete) return [];
434
- return searchCommands(commandQuery);
435
- }, [shouldShowCommandAutocomplete, commandQuery]);
436
- const filteredFiles = useMemo(() => {
437
- if (!fileAutocomplete?.active) return [];
438
- return searchFiles(fileAutocomplete.query);
439
- }, [fileAutocomplete?.active, fileAutocomplete?.query]);
214
+ if (!shouldShowAutocomplete) return [];
215
+ return searchCommands(query);
216
+ }, [shouldShowAutocomplete, query]);
440
217
  useEffect(() => {
441
218
  setSelectedIndex(0);
442
219
  }, [filteredCommands]);
443
- useEffect(() => {
444
- setFileSelectedIndex(0);
445
- }, [filteredFiles]);
446
220
  useInput((input, key) => {
447
- if (fileAutocomplete?.active && filteredFiles.length > 0) {
448
- if (key.upArrow) {
449
- setFileSelectedIndex((prev) => prev > 0 ? prev - 1 : filteredFiles.length - 1);
450
- return;
451
- } else if (key.downArrow) {
452
- setFileSelectedIndex((prev) => prev < filteredFiles.length - 1 ? prev + 1 : 0);
453
- return;
454
- } else if (key.tab) {
455
- const selectedFile = filteredFiles[fileSelectedIndex];
456
- if (selectedFile) {
457
- insertSelectedFile(selectedFile);
458
- }
459
- return;
460
- } else if (key.escape) {
461
- setFileAutocomplete(null);
462
- return;
463
- }
464
- }
465
- if (shouldShowCommandAutocomplete && filteredCommands.length > 0) {
221
+ if (shouldShowAutocomplete && filteredCommands.length > 0) {
466
222
  if (key.upArrow) {
467
223
  setSelectedIndex((prev) => prev > 0 ? prev - 1 : filteredCommands.length - 1);
468
224
  } else if (key.downArrow) {
@@ -470,7 +226,7 @@ function InputPrompt({ onSubmit, disabled = false, history = [] }) {
470
226
  }
471
227
  return;
472
228
  }
473
- if (!shouldShowCommandAutocomplete && !fileAutocomplete?.active && history.length > 0) {
229
+ if (!shouldShowAutocomplete && history.length > 0) {
474
230
  if (key.upArrow) {
475
231
  if (historyIndex === -1) {
476
232
  setTempInput(value);
@@ -493,35 +249,9 @@ function InputPrompt({ onSubmit, disabled = false, history = [] }) {
493
249
  }
494
250
  }
495
251
  });
496
- const insertSelectedFile = (file) => {
497
- if (!fileAutocomplete) return;
498
- const beforeAt = value.slice(0, fileAutocomplete.startIndex);
499
- const afterQuery = value.slice(fileAutocomplete.startIndex + 1 + fileAutocomplete.query.length);
500
- const pathToInsert = file.isDirectory ? `@${file.path}/` : `@${file.path}`;
501
- const newValue = beforeAt + pathToInsert + afterQuery;
502
- setValue(newValue);
503
- setInputKey((prev) => prev + 1);
504
- if (file.isDirectory) {
505
- setFileAutocomplete({
506
- active: true,
507
- startIndex: fileAutocomplete.startIndex,
508
- query: file.path + "/"
509
- });
510
- setFileSelectedIndex(0);
511
- } else {
512
- setFileAutocomplete(null);
513
- }
514
- };
515
252
  const handleSubmit = (input) => {
516
253
  if (disabled || !input.trim()) return;
517
- if (fileAutocomplete?.active && filteredFiles.length > 0) {
518
- const selectedFile = filteredFiles[fileSelectedIndex];
519
- if (selectedFile) {
520
- insertSelectedFile(selectedFile);
521
- }
522
- return;
523
- }
524
- if (shouldShowCommandAutocomplete && filteredCommands.length > 0) {
254
+ if (shouldShowAutocomplete && filteredCommands.length > 0) {
525
255
  const selectedCommand = filteredCommands[selectedIndex];
526
256
  const commandText = `/${selectedCommand.name}`;
527
257
  if (selectedCommand.args) {
@@ -538,7 +268,6 @@ function InputPrompt({ onSubmit, disabled = false, history = [] }) {
538
268
  onSubmit(input);
539
269
  setValue("");
540
270
  setHistoryIndex(-1);
541
- setFileAutocomplete(null);
542
271
  };
543
272
  const handleChange = (newValue) => {
544
273
  setValue(newValue);
@@ -546,40 +275,30 @@ function InputPrompt({ onSubmit, disabled = false, history = [] }) {
546
275
  setHistoryIndex(-1);
547
276
  setTempInput("");
548
277
  }
549
- const atTrigger = findAtTrigger(newValue);
550
- if (atTrigger) {
551
- setFileAutocomplete({
552
- active: true,
553
- startIndex: atTrigger.startIndex,
554
- query: atTrigger.query
555
- });
556
- } else {
557
- setFileAutocomplete(null);
558
- }
559
278
  };
560
- 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(
561
280
  TextInput,
562
281
  {
563
282
  key: inputKey,
564
283
  value,
565
284
  onChange: handleChange,
566
285
  onSubmit: handleSubmit,
567
- placeholder: disabled ? "Thinking..." : "Type your message, /help for commands, or @file to reference",
286
+ placeholder: disabled ? "Thinking..." : "Type your message or /help for commands",
568
287
  showCursor: !disabled
569
288
  }
570
- )), 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 }));
571
290
  }
572
291
 
573
292
  // src/components/AgentThinking.tsx
574
- import React6 from "react";
575
- import { Box as Box6 } from "ink";
293
+ import React5 from "react";
294
+ import { Box as Box5 } from "ink";
576
295
 
577
296
  // src/components/ThoughtStream.tsx
578
- import React5 from "react";
579
- import { Box as Box5, Text as Text5 } from "ink";
297
+ import React4 from "react";
298
+ import { Box as Box4, Text as Text4 } from "ink";
580
299
  import Spinner from "ink-spinner";
581
- var ThoughtStream = React5.memo(function ThoughtStream2({ steps }) {
582
- 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...")));
583
302
  });
584
303
 
585
304
  // src/store/index.ts
@@ -605,32 +324,32 @@ var useCliStore = create((set) => ({
605
324
  }));
606
325
 
607
326
  // src/components/AgentThinking.tsx
608
- var AgentThinking = React6.memo(function AgentThinking2() {
327
+ var AgentThinking = React5.memo(function AgentThinking2() {
609
328
  const isThinking = useCliStore((state) => state.isThinking);
610
329
  const agentSteps = useCliStore((state) => state.agentSteps);
611
330
  if (!isThinking) {
612
331
  return null;
613
332
  }
614
- 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 }));
615
334
  });
616
335
 
617
336
  // src/components/PermissionPrompt.tsx
618
- import React7 from "react";
619
- import { Box as Box7, Text as Text6 } from "ink";
337
+ import React6 from "react";
338
+ import { Box as Box6, Text as Text5 } from "ink";
620
339
  import SelectInput from "ink-select-input";
621
340
  function renderDiffPreview(preview) {
622
341
  const lines = preview.split("\n");
623
342
  return lines.map((line, index) => {
624
343
  if (line.startsWith("+")) {
625
- return /* @__PURE__ */ React7.createElement(Text6, { key: index, color: "green" }, line);
344
+ return /* @__PURE__ */ React6.createElement(Text5, { key: index, color: "green" }, line);
626
345
  }
627
346
  if (line.startsWith("-")) {
628
- return /* @__PURE__ */ React7.createElement(Text6, { key: index, color: "red" }, line);
347
+ return /* @__PURE__ */ React6.createElement(Text5, { key: index, color: "red" }, line);
629
348
  }
630
349
  if (line.startsWith("@@")) {
631
- return /* @__PURE__ */ React7.createElement(Text6, { key: index, color: "cyan" }, line);
350
+ return /* @__PURE__ */ React6.createElement(Text5, { key: index, color: "cyan" }, line);
632
351
  }
633
- return /* @__PURE__ */ React7.createElement(Text6, { key: index, dimColor: true }, line);
352
+ return /* @__PURE__ */ React6.createElement(Text5, { key: index, dimColor: true }, line);
634
353
  });
635
354
  }
636
355
  function PermissionPrompt({
@@ -650,121 +369,7 @@ function PermissionPrompt({
650
369
  { label: "\u2717 Deny", value: "deny" }
651
370
  ];
652
371
  const argsString = typeof args === "string" ? args : JSON.stringify(args, null, 2);
653
- 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) })));
654
- }
655
-
656
- // src/utils/processFileReferences.ts
657
- import * as fs2 from "fs";
658
- import * as path2 from "path";
659
-
660
- // src/utils/constants.ts
661
- var NAME_SUFFIXES = ["jr", "sr", "ii", "iii", "iv", "v", "phd", "md", "esq"];
662
- function isNameSuffix(value) {
663
- return NAME_SUFFIXES.includes(value);
664
- }
665
-
666
- // src/utils/processFileReferences.ts
667
- var FILE_REFERENCE_REGEX = /(?:^|\s)@([^\s@]+)/g;
668
- function looksLikeFilePath(ref) {
669
- if (ref.includes("/") || ref.includes(path2.sep)) {
670
- return true;
671
- }
672
- const extensionMatch = /\.(\w+)$/.exec(ref);
673
- if (extensionMatch) {
674
- const ext = extensionMatch[1].toLowerCase();
675
- if (isNameSuffix(ext)) {
676
- return false;
677
- }
678
- if (ext.length > 10) {
679
- return false;
680
- }
681
- return true;
682
- }
683
- return false;
684
- }
685
- function extractFileReferences(message) {
686
- const references = [];
687
- const regex = /(?:^|\s)@([^\s@]+)/g;
688
- let match;
689
- while ((match = regex.exec(message)) !== null) {
690
- const ref = match[1];
691
- if (looksLikeFilePath(ref)) {
692
- references.push(ref);
693
- }
694
- }
695
- return references;
696
- }
697
- function readFileContents(filePath) {
698
- const cwd = process.cwd();
699
- const absolutePath = path2.resolve(cwd, filePath);
700
- if (!isPathWithinCwd(filePath)) {
701
- return { error: `Security: Path "${filePath}" is outside the current working directory` };
702
- }
703
- if (!fs2.existsSync(absolutePath)) {
704
- return { error: `File not found: "${filePath}"` };
705
- }
706
- const stats = fs2.statSync(absolutePath);
707
- if (stats.isDirectory()) {
708
- try {
709
- const entries = fs2.readdirSync(absolutePath);
710
- const fileCount = entries.length;
711
- return {
712
- content: `(Directory with ${fileCount} items. Use file tools to explore if needed.)`,
713
- size: 0
714
- };
715
- } catch (err) {
716
- return { error: `Cannot read directory "${filePath}": ${err instanceof Error ? err.message : "Unknown error"}` };
717
- }
718
- }
719
- if (stats.size > MAX_FILE_SIZE) {
720
- return {
721
- error: `File too large: "${filePath}" is ${formatFileSize(stats.size)} (max ${formatFileSize(MAX_FILE_SIZE)})`
722
- };
723
- }
724
- if (isBinaryFile(filePath)) {
725
- return { error: `Binary file: "${filePath}" cannot be included as text content` };
726
- }
727
- try {
728
- const content = fs2.readFileSync(absolutePath, "utf-8");
729
- return { content, size: stats.size };
730
- } catch (err) {
731
- return { error: `Cannot read file "${filePath}": ${err instanceof Error ? err.message : "Unknown error"}` };
732
- }
733
- }
734
- function formatFileBlock(filePath, content, size, isDirectory) {
735
- if (isDirectory) {
736
- return `
737
- --- Directory Reference: ${filePath} ---
738
- ${content}
739
- --- End of ${filePath} ---`;
740
- }
741
- return `
742
- --- Referenced File: ${filePath} (${formatFileSize(size)}) ---
743
- ${content}
744
- --- End of ${filePath} ---`;
745
- }
746
- async function processFileReferences(message) {
747
- const references = extractFileReferences(message);
748
- const errors = [];
749
- const fileBlocks = [];
750
- for (const ref of references) {
751
- const result = readFileContents(ref);
752
- if ("error" in result) {
753
- errors.push(result.error);
754
- continue;
755
- }
756
- const isDirectory = result.size === 0 && result.content.startsWith("(Directory");
757
- fileBlocks.push(formatFileBlock(ref, result.content, result.size, isDirectory));
758
- }
759
- if (fileBlocks.length === 0) {
760
- return { content: message, errors };
761
- }
762
- const processedContent = message + "\n" + fileBlocks.join("\n");
763
- return { content: processedContent, errors };
764
- }
765
- function hasFileReferences(message) {
766
- FILE_REFERENCE_REGEX.lastIndex = 0;
767
- 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) })));
768
373
  }
769
374
 
770
375
  // src/components/App.tsx
@@ -777,7 +382,7 @@ function App({ onMessage, onCommand, onPermissionResponse, commandHistory = [] }
777
382
  const permissionPrompt = useCliStore((state) => state.permissionPrompt);
778
383
  const exitRequested = useCliStore((state) => state.exitRequested);
779
384
  const setIsThinking = useCliStore((state) => state.setIsThinking);
780
- const handleSubmit = React8.useCallback(
385
+ const handleSubmit = React7.useCallback(
781
386
  async (input) => {
782
387
  const trimmed = input.trim();
783
388
  if (!trimmed) return;
@@ -788,25 +393,14 @@ function App({ onMessage, onCommand, onPermissionResponse, commandHistory = [] }
788
393
  }
789
394
  setIsThinking(true);
790
395
  try {
791
- let messageToSend = trimmed;
792
- if (hasFileReferences(trimmed)) {
793
- const processed = await processFileReferences(trimmed);
794
- messageToSend = processed.content;
795
- if (processed.errors.length > 0) {
796
- const errorBlock = processed.errors.map((e) => `[Warning: ${e}]`).join("\n");
797
- messageToSend = `${messageToSend}
798
-
799
- ${errorBlock}`;
800
- }
801
- }
802
- await onMessage(messageToSend);
396
+ await onMessage(trimmed);
803
397
  } finally {
804
398
  setIsThinking(false);
805
399
  }
806
400
  },
807
401
  [onMessage, onCommand, setIsThinking]
808
402
  );
809
- 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(
810
404
  PermissionPrompt,
811
405
  {
812
406
  toolName: permissionPrompt.toolName,
@@ -815,39 +409,39 @@ ${errorBlock}`;
815
409
  canBeTrusted: permissionPrompt.canBeTrusted,
816
410
  onResponse: onPermissionResponse
817
411
  }
818
- )) : /* @__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 }))));
819
413
  }
820
414
  function MessageItem({ message }) {
821
- 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) => {
822
416
  if (step.type === "thought") {
823
- 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 ? "..." : ""}`));
824
418
  }
825
419
  if (step.type === "action") {
826
420
  const toolName = step.metadata?.toolName || "unknown";
827
421
  const toolInput = step.metadata?.toolInput;
828
422
  const observationStep = message.metadata.steps[idx + 1];
829
423
  const result = observationStep?.type === "observation" ? observationStep.content : null;
830
- 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 ? "..." : ""}`));
831
425
  }
832
426
  return null;
833
- }).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`)));
834
428
  }
835
429
 
836
430
  // src/components/MessageList.tsx
837
- import React9 from "react";
838
- import { Box as Box9, Text as Text8 } from "ink";
431
+ import React8 from "react";
432
+ import { Box as Box8, Text as Text7 } from "ink";
839
433
  function stripThinkingTags(content) {
840
434
  return content.replace(/<think>[\s\S]*?<\/think>/g, "").trim();
841
435
  }
842
- var MessageList = React9.memo(
436
+ var MessageList = React8.memo(
843
437
  function MessageList2({ messages }) {
844
438
  if (messages.length === 0) {
845
- 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!"));
846
440
  }
847
- 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) => {
848
442
  if (step.type === "thought") {
849
- 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(
850
- 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,
851
445
  {
852
446
  dimColor: true
853
447
  },
@@ -859,10 +453,10 @@ var MessageList = React9.memo(
859
453
  const toolInput = step.metadata?.toolInput;
860
454
  const observationStep = message.metadata.steps[idx + 1];
861
455
  const result = observationStep?.type === "observation" ? observationStep.content : null;
862
- 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 ? "..." : ""}`));
863
457
  }
864
458
  return null;
865
- }).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`)))));
866
460
  },
867
461
  (prevProps, nextProps) => {
868
462
  if (prevProps.messages.length !== nextProps.messages.length) {
@@ -872,6 +466,39 @@ var MessageList = React9.memo(
872
466
  }
873
467
  );
874
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
+
875
502
  // src/components/LoginFlow.tsx
876
503
  import React10, { useState as useState2, useEffect as useEffect2 } from "react";
877
504
  import { Box as Box10, Text as Text9 } from "ink";
@@ -984,7 +611,7 @@ var OAuthClient = class {
984
611
  * Sleep for specified milliseconds
985
612
  */
986
613
  sleep(ms) {
987
- return new Promise((resolve3) => setTimeout(resolve3, ms));
614
+ return new Promise((resolve) => setTimeout(resolve, ms));
988
615
  }
989
616
  };
990
617
 
@@ -1049,19 +676,19 @@ function LoginFlow({ apiUrl = "http://localhost:3000", configStore, onSuccess, o
1049
676
  }
1050
677
 
1051
678
  // src/storage/SessionStore.ts
1052
- import { promises as fs3 } from "fs";
1053
- import path3 from "path";
679
+ import { promises as fs } from "fs";
680
+ import path from "path";
1054
681
  import { homedir } from "os";
1055
682
  var SessionStore = class {
1056
683
  constructor(basePath) {
1057
- this.basePath = basePath || path3.join(homedir(), ".bike4mind", "sessions");
684
+ this.basePath = basePath || path.join(homedir(), ".bike4mind", "sessions");
1058
685
  }
1059
686
  /**
1060
687
  * Initialize storage directory
1061
688
  */
1062
689
  async init() {
1063
690
  try {
1064
- await fs3.mkdir(this.basePath, { recursive: true });
691
+ await fs.mkdir(this.basePath, { recursive: true });
1065
692
  } catch (error) {
1066
693
  console.error("Failed to initialize session storage:", error);
1067
694
  throw error;
@@ -1072,9 +699,9 @@ var SessionStore = class {
1072
699
  */
1073
700
  async save(session) {
1074
701
  await this.init();
1075
- const filePath = path3.join(this.basePath, `${session.id}.json`);
702
+ const filePath = path.join(this.basePath, `${session.id}.json`);
1076
703
  try {
1077
- await fs3.writeFile(filePath, JSON.stringify(session, null, 2), "utf-8");
704
+ await fs.writeFile(filePath, JSON.stringify(session, null, 2), "utf-8");
1078
705
  } catch (error) {
1079
706
  console.error("Failed to save session:", error);
1080
707
  throw error;
@@ -1084,9 +711,9 @@ var SessionStore = class {
1084
711
  * Load a session from disk by ID
1085
712
  */
1086
713
  async load(id) {
1087
- const filePath = path3.join(this.basePath, `${id}.json`);
714
+ const filePath = path.join(this.basePath, `${id}.json`);
1088
715
  try {
1089
- const data = await fs3.readFile(filePath, "utf-8");
716
+ const data = await fs.readFile(filePath, "utf-8");
1090
717
  return JSON.parse(data);
1091
718
  } catch (error) {
1092
719
  if (error.code === "ENOENT") {
@@ -1110,12 +737,12 @@ var SessionStore = class {
1110
737
  async list() {
1111
738
  await this.init();
1112
739
  try {
1113
- const files = await fs3.readdir(this.basePath);
740
+ const files = await fs.readdir(this.basePath);
1114
741
  const jsonFiles = files.filter((f) => f.endsWith(".json"));
1115
742
  const sessions = await Promise.all(
1116
743
  jsonFiles.map(async (file) => {
1117
- const filePath = path3.join(this.basePath, file);
1118
- 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");
1119
746
  return JSON.parse(data);
1120
747
  })
1121
748
  );
@@ -1129,9 +756,9 @@ var SessionStore = class {
1129
756
  * Delete a session
1130
757
  */
1131
758
  async delete(id) {
1132
- const filePath = path3.join(this.basePath, `${id}.json`);
759
+ const filePath = path.join(this.basePath, `${id}.json`);
1133
760
  try {
1134
- await fs3.unlink(filePath);
761
+ await fs.unlink(filePath);
1135
762
  return true;
1136
763
  } catch (error) {
1137
764
  if (error.code === "ENOENT") {
@@ -1167,8 +794,8 @@ var SessionStore = class {
1167
794
  };
1168
795
 
1169
796
  // src/storage/ConfigStore.ts
1170
- import { promises as fs4 } from "fs";
1171
- import path4 from "path";
797
+ import { promises as fs2, existsSync } from "fs";
798
+ import path2 from "path";
1172
799
  import { homedir as homedir2 } from "os";
1173
800
  import { v4 as uuidv4 } from "uuid";
1174
801
  import { z } from "zod";
@@ -1214,6 +841,53 @@ var CliConfigSchema = z.object({
1214
841
  }),
1215
842
  trustedTools: z.array(z.string()).optional().default([])
1216
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
+ });
1217
891
  var DEFAULT_CONFIG = {
1218
892
  version: "0.1.0",
1219
893
  userId: uuidv4(),
@@ -1239,18 +913,132 @@ var DEFAULT_CONFIG = {
1239
913
  trustedTools: []
1240
914
  // No tools trusted by default
1241
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
+ }
1242
1029
  var ConfigStore = class {
1243
1030
  constructor(configPath) {
1244
1031
  this.config = null;
1245
- this.configPath = configPath || path4.join(homedir2(), ".bike4mind", "config.json");
1032
+ this.projectConfigDir = null;
1033
+ this.configPath = configPath || path2.join(homedir2(), ".bike4mind", "config.json");
1246
1034
  }
1247
1035
  /**
1248
1036
  * Initialize config directory
1249
1037
  */
1250
1038
  async init() {
1251
- const dir = path4.dirname(this.configPath);
1039
+ const dir = path2.dirname(this.configPath);
1252
1040
  try {
1253
- await fs4.mkdir(dir, { recursive: true });
1041
+ await fs2.mkdir(dir, { recursive: true });
1254
1042
  } catch (error) {
1255
1043
  console.error("Failed to initialize config directory:", error);
1256
1044
  throw error;
@@ -1258,51 +1046,76 @@ var ConfigStore = class {
1258
1046
  }
1259
1047
  /**
1260
1048
  * Load configuration from disk with Zod validation
1049
+ * Merges global → project → local configs
1261
1050
  */
1262
1051
  async load() {
1263
1052
  if (this.config) {
1264
1053
  return this.config;
1265
1054
  }
1266
1055
  try {
1056
+ let globalConfig;
1267
1057
  try {
1268
- const stats = await fs4.stat(this.configPath);
1269
- const mode = stats.mode & 511;
1270
- if (mode !== 384) {
1271
- console.warn(`\u26A0\uFE0F Config file has insecure permissions (${mode.toString(8)}). Setting to 0600...`);
1272
- 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
+ }
1273
1076
  }
1274
- } catch (statError) {
1275
- }
1276
- const data = await fs4.readFile(this.configPath, "utf-8");
1277
- const rawConfig = JSON.parse(data);
1278
- if (rawConfig.apiConfig && "environment" in rawConfig.apiConfig) {
1279
- const oldApiConfig = rawConfig.apiConfig;
1280
- if (oldApiConfig.environment === "custom" && oldApiConfig.customUrl) {
1281
- 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 };
1282
1104
  } else {
1283
- rawConfig.apiConfig = {};
1105
+ throw error;
1284
1106
  }
1285
1107
  }
1286
- const validated = CliConfigSchema.parse(rawConfig);
1287
- this.config = {
1288
- ...DEFAULT_CONFIG,
1289
- ...validated,
1290
- auth: validated.auth,
1291
- // Explicitly preserve auth field
1292
- preferences: {
1293
- ...DEFAULT_CONFIG.preferences,
1294
- ...validated.preferences
1295
- },
1296
- tools: {
1297
- ...DEFAULT_CONFIG.tools,
1298
- ...validated.tools
1299
- },
1300
- toolApiKeys: {
1301
- ...DEFAULT_CONFIG.toolApiKeys,
1302
- ...validated.toolApiKeys || {}
1303
- },
1304
- trustedTools: validated.trustedTools || []
1305
- };
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);
1306
1119
  return this.config;
1307
1120
  } catch (error) {
1308
1121
  if (error.code === "ENOENT") {
@@ -1346,8 +1159,8 @@ var ConfigStore = class {
1346
1159
  throw new Error("No configuration to save");
1347
1160
  }
1348
1161
  try {
1349
- await fs4.writeFile(this.configPath, JSON.stringify(this.config, null, 2), "utf-8");
1350
- 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);
1351
1164
  } catch (error) {
1352
1165
  console.error("Failed to save config:", error);
1353
1166
  throw error;
@@ -1489,27 +1302,126 @@ var ConfigStore = class {
1489
1302
  } else {
1490
1303
  config.apiConfig = { customUrl: url };
1491
1304
  }
1492
- 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);
1493
1405
  }
1494
1406
  };
1495
1407
 
1496
1408
  // src/storage/CommandHistoryStore.ts
1497
- import { promises as fs5 } from "fs";
1498
- import path5 from "path";
1409
+ import { promises as fs3 } from "fs";
1410
+ import path3 from "path";
1499
1411
  import { homedir as homedir3 } from "os";
1500
1412
  var MAX_HISTORY_ENTRIES = 1e3;
1501
1413
  var CommandHistoryStore = class {
1502
1414
  constructor(historyPath) {
1503
1415
  this.history = null;
1504
- this.historyPath = historyPath || path5.join(homedir3(), ".bike4mind", "history.jsonl");
1416
+ this.historyPath = historyPath || path3.join(homedir3(), ".bike4mind", "history.jsonl");
1505
1417
  }
1506
1418
  /**
1507
1419
  * Initialize history directory
1508
1420
  */
1509
1421
  async init() {
1510
- const dir = path5.dirname(this.historyPath);
1422
+ const dir = path3.dirname(this.historyPath);
1511
1423
  try {
1512
- await fs5.mkdir(dir, { recursive: true });
1424
+ await fs3.mkdir(dir, { recursive: true });
1513
1425
  } catch (error) {
1514
1426
  console.error("Failed to initialize history directory:", error);
1515
1427
  throw error;
@@ -1524,7 +1436,7 @@ var CommandHistoryStore = class {
1524
1436
  return this.history;
1525
1437
  }
1526
1438
  try {
1527
- const data = await fs5.readFile(this.historyPath, "utf-8");
1439
+ const data = await fs3.readFile(this.historyPath, "utf-8");
1528
1440
  const lines = data.trim().split("\n").filter((line) => line.length > 0);
1529
1441
  const entries = lines.map((line) => {
1530
1442
  try {
@@ -1561,7 +1473,7 @@ var CommandHistoryStore = class {
1561
1473
  };
1562
1474
  await this.init();
1563
1475
  const line = JSON.stringify(entry) + "\n";
1564
- await fs5.appendFile(this.historyPath, line, "utf-8");
1476
+ await fs3.appendFile(this.historyPath, line, "utf-8");
1565
1477
  this.history = [command, ...this.history || []];
1566
1478
  if (this.history.length > MAX_HISTORY_ENTRIES) {
1567
1479
  await this.trim();
@@ -1584,7 +1496,7 @@ var CommandHistoryStore = class {
1584
1496
  };
1585
1497
  return JSON.stringify(entry);
1586
1498
  }).join("\n");
1587
- await fs5.writeFile(this.historyPath, lines + "\n", "utf-8");
1499
+ await fs3.writeFile(this.historyPath, lines + "\n", "utf-8");
1588
1500
  this.history = trimmedCommands;
1589
1501
  }
1590
1502
  /**
@@ -1592,7 +1504,7 @@ var CommandHistoryStore = class {
1592
1504
  */
1593
1505
  async clear() {
1594
1506
  try {
1595
- await fs5.unlink(this.historyPath);
1507
+ await fs3.unlink(this.historyPath);
1596
1508
  } catch (error) {
1597
1509
  if (error.code !== "ENOENT") {
1598
1510
  throw error;
@@ -2366,7 +2278,7 @@ import { GoogleGenerativeAI } from "@google/generative-ai";
2366
2278
  import OpenAI2 from "openai";
2367
2279
 
2368
2280
  // ../../b4m-core/packages/services/dist/src/importHistoryService/index.js
2369
- import fs6, { unlinkSync } from "fs";
2281
+ import fs4, { unlinkSync } from "fs";
2370
2282
  import yauzl from "yauzl";
2371
2283
  import axios3 from "axios";
2372
2284
 
@@ -2973,196 +2885,190 @@ var listFabFilesBySessionSchema = z90.object({
2973
2885
  sessionId: z90.string()
2974
2886
  });
2975
2887
 
2976
- // ../../b4m-core/packages/services/dist/src/fabFileService/listByQuest.js
2977
- import { z as z91 } from "zod";
2978
- var listFabFilesByQuestSchema = z91.object({
2979
- questId: z91.string()
2980
- });
2981
-
2982
2888
  // ../../b4m-core/packages/services/dist/src/fabFileService/createByUrl.js
2983
- import { z as z92 } from "zod";
2984
- var createFabFileByUrlSchema = z92.object({
2985
- 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,})).+/)
2986
2892
  });
2987
2893
 
2988
2894
  // ../../b4m-core/packages/services/dist/src/fabFileService/search.js
2989
- import { z as z93 } from "zod";
2990
- var searchFabFilesSchema = z93.object({
2991
- search: z93.string().optional(),
2992
- filters: z93.object({
2993
- tags: z93.array(z93.string()).optional(),
2994
- type: z93.enum(["text", "pdf", "url", "image", "excel", "word", "json", "csv", "markdown", "code"]).optional(),
2995
- 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(),
2996
2902
  // Indicates if the user is searching for shared files
2997
- curated: z93.coerce.boolean().optional(),
2903
+ curated: z92.coerce.boolean().optional(),
2998
2904
  // Indicates if the user is searching for curated notebook files
2999
- projectId: z93.string().optional(),
3000
- ids: z93.array(z93.string()).optional()
2905
+ projectId: z92.string().optional(),
2906
+ ids: z92.array(z92.string()).optional()
3001
2907
  // Add support for filtering by IDs
3002
2908
  }).optional(),
3003
- pagination: z93.object({
3004
- page: z93.coerce.number(),
3005
- limit: z93.coerce.number()
2909
+ pagination: z92.object({
2910
+ page: z92.coerce.number(),
2911
+ limit: z92.coerce.number()
3006
2912
  }).optional(),
3007
- order: z93.object({
3008
- by: z93.enum(["createdAt", "fileName", "fileSize"]),
3009
- direction: z93.enum(["asc", "desc"])
2913
+ order: z92.object({
2914
+ by: z92.enum(["createdAt", "fileName", "fileSize"]),
2915
+ direction: z92.enum(["asc", "desc"])
3010
2916
  }).optional(),
3011
- options: z93.object({
3012
- includeShared: z93.coerce.boolean().optional()
2917
+ options: z92.object({
2918
+ includeShared: z92.coerce.boolean().optional()
3013
2919
  }).optional()
3014
2920
  });
3015
2921
 
3016
2922
  // ../../b4m-core/packages/services/dist/src/fabFileService/addFavorite.js
3017
- import { z as z94 } from "zod";
3018
- var addFavoriteParametersSchema3 = z94.object({
3019
- fileId: z94.string()
2923
+ import { z as z93 } from "zod";
2924
+ var addFavoriteParametersSchema3 = z93.object({
2925
+ fileId: z93.string()
3020
2926
  });
3021
2927
 
3022
2928
  // ../../b4m-core/packages/services/dist/src/fabFileService/deleteFavorite.js
3023
- import { z as z95 } from "zod";
3024
- var deleteFavoriteParametersSchema4 = z95.object({
3025
- fileId: z95.string()
2929
+ import { z as z94 } from "zod";
2930
+ var deleteFavoriteParametersSchema4 = z94.object({
2931
+ fileId: z94.string()
3026
2932
  });
3027
2933
 
3028
2934
  // ../../b4m-core/packages/services/dist/src/fabFileService/toggleTags.js
3029
- import { z as z96 } from "zod";
3030
- var fabFileToggleTagsSchema = z96.object({
3031
- ids: z96.array(z96.string()),
3032
- 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())
3033
2939
  });
3034
2940
 
3035
2941
  // ../../b4m-core/packages/services/dist/src/fabFileService/edit.js
3036
- import { z as z97 } from "zod";
2942
+ import { z as z96 } from "zod";
3037
2943
  import { diffLines } from "diff";
3038
- var editFabFileSchema = z97.object({
3039
- id: z97.string(),
3040
- instruction: z97.string(),
3041
- selection: z97.object({
3042
- start: z97.number(),
3043
- 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()
3044
2950
  }).optional(),
3045
- preserveFormatting: z97.boolean().optional().default(true),
3046
- applyImmediately: z97.boolean().optional().default(false)
2951
+ preserveFormatting: z96.boolean().optional().default(true),
2952
+ applyImmediately: z96.boolean().optional().default(false)
3047
2953
  });
3048
2954
 
3049
2955
  // ../../b4m-core/packages/services/dist/src/fabFileService/applyEdit.js
3050
2956
  import mime2 from "mime-types";
3051
2957
  import { v4 as uuidv43 } from "uuid";
3052
- import { z as z98 } from "zod";
3053
- var applyEditSchema = z98.object({
3054
- id: z98.string(),
3055
- modifiedContent: z98.string(),
3056
- 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)
3057
2963
  });
3058
2964
 
3059
2965
  // ../../b4m-core/packages/services/dist/src/friendshipService/respondToFriendRequest.js
3060
- import { z as z99 } from "zod";
3061
- var respondToFriendRequestSchema = z99.object({
3062
- id: z99.string(),
2966
+ import { z as z98 } from "zod";
2967
+ var respondToFriendRequestSchema = z98.object({
2968
+ id: z98.string(),
3063
2969
  /** The user ID of the recipient of the friend request */
3064
- userId: z99.string(),
3065
- accept: z99.boolean()
2970
+ userId: z98.string(),
2971
+ accept: z98.boolean()
3066
2972
  });
3067
2973
 
3068
2974
  // ../../b4m-core/packages/services/dist/src/friendshipService/unfriend.js
3069
- import { z as z100 } from "zod";
3070
- var unfriendSchema = z100.object({
3071
- friendshipId: z100.string(),
2975
+ import { z as z99 } from "zod";
2976
+ var unfriendSchema = z99.object({
2977
+ friendshipId: z99.string(),
3072
2978
  /** The user ID of the user who wants to unfriend the other user */
3073
- userId: z100.string()
2979
+ userId: z99.string()
3074
2980
  });
3075
2981
 
3076
2982
  // ../../b4m-core/packages/services/dist/src/friendshipService/list.js
3077
- import { z as z101 } from "zod";
3078
- var listFriendsSchema = z101.object({
3079
- userId: z101.string()
2983
+ import { z as z100 } from "zod";
2984
+ var listFriendsSchema = z100.object({
2985
+ userId: z100.string()
3080
2986
  });
3081
- var listPendingFriendRequestsSchema = z101.object({
3082
- userId: z101.string()
2987
+ var listPendingFriendRequestsSchema = z100.object({
2988
+ userId: z100.string()
3083
2989
  });
3084
2990
 
3085
2991
  // ../../b4m-core/packages/services/dist/src/adminService/loginAs.js
3086
- import { z as z102 } from "zod";
3087
- var loginAsSchema = z102.object({
3088
- targetUserId: z102.string()
2992
+ import { z as z101 } from "zod";
2993
+ var loginAsSchema = z101.object({
2994
+ targetUserId: z101.string()
3089
2995
  });
3090
2996
 
3091
2997
  // ../../b4m-core/packages/services/dist/src/cacheService/get.js
3092
- import { z as z103 } from "zod";
3093
- var getParamsSchema = z103.object({
3094
- key: z103.string()
2998
+ import { z as z102 } from "zod";
2999
+ var getParamsSchema = z102.object({
3000
+ key: z102.string()
3095
3001
  });
3096
3002
 
3097
3003
  // ../../b4m-core/packages/services/dist/src/cacheService/set.js
3098
- import { z as z104 } from "zod";
3099
- var setParamsSchema = z104.object({
3100
- key: z104.string(),
3101
- value: z104.any(),
3004
+ import { z as z103 } from "zod";
3005
+ var setParamsSchema = z103.object({
3006
+ key: z103.string(),
3007
+ value: z103.any(),
3102
3008
  /**
3103
3009
  * Time to live in milliseconds
3104
3010
  */
3105
- ttl: z104.number(),
3106
- recache: z104.boolean().optional()
3011
+ ttl: z103.number(),
3012
+ recache: z103.boolean().optional()
3107
3013
  });
3108
3014
 
3109
3015
  // ../../b4m-core/packages/services/dist/src/cacheService/ttl.js
3110
- import { z as z105 } from "zod";
3111
- var ttlParamsSchema = z105.object({
3112
- key: z105.string()
3016
+ import { z as z104 } from "zod";
3017
+ var ttlParamsSchema = z104.object({
3018
+ key: z104.string()
3113
3019
  });
3114
3020
 
3115
3021
  // ../../b4m-core/packages/services/dist/src/cacheService/weeklyReports.js
3116
- import { z as z106 } from "zod";
3022
+ import { z as z105 } from "zod";
3117
3023
  import dayjs3 from "dayjs";
3118
- var weeklyReportSchema = z106.object({
3119
- startDate: z106.string(),
3120
- endDate: z106.string(),
3121
- report: z106.string(),
3122
- 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()
3123
3029
  });
3124
3030
 
3125
3031
  // ../../b4m-core/packages/services/dist/src/embeddingCacheService/generateCacheKey.js
3126
3032
  import crypto2 from "crypto";
3127
3033
 
3128
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
3129
3042
  import { z as z107 } from "zod";
3130
- var researchAgentCreateSchema = z107.object({
3043
+ var researchAgentUpdateSchema = z107.object({
3044
+ id: z107.string(),
3131
3045
  name: z107.string().min(1),
3132
3046
  description: z107.string().min(1)
3133
3047
  });
3134
3048
 
3135
- // ../../b4m-core/packages/services/dist/src/researchAgentService/update.js
3049
+ // ../../b4m-core/packages/services/dist/src/researchAgentService/remove.js
3136
3050
  import { z as z108 } from "zod";
3137
- var researchAgentUpdateSchema = z108.object({
3138
- id: z108.string(),
3139
- name: z108.string().min(1),
3140
- description: z108.string().min(1)
3051
+ var researchAgentRemoveSchema = z108.object({
3052
+ id: z108.string()
3141
3053
  });
3142
3054
 
3143
- // ../../b4m-core/packages/services/dist/src/researchAgentService/remove.js
3055
+ // ../../b4m-core/packages/services/dist/src/researchAgentService/get.js
3144
3056
  import { z as z109 } from "zod";
3145
- var researchAgentRemoveSchema = z109.object({
3057
+ var researchAgentGetSchema = z109.object({
3146
3058
  id: z109.string()
3147
3059
  });
3148
3060
 
3149
- // ../../b4m-core/packages/services/dist/src/researchAgentService/get.js
3150
- import { z as z110 } from "zod";
3151
- var researchAgentGetSchema = z110.object({
3152
- id: z110.string()
3153
- });
3154
-
3155
3061
  // ../../b4m-core/packages/services/dist/src/researchAgentService/listFiles.js
3156
- import { z as z111 } from "zod";
3157
- var researchAgentListFilesSchema = z111.object({
3062
+ import { z as z110 } from "zod";
3063
+ var researchAgentListFilesSchema = z110.object({
3158
3064
  /**
3159
3065
  * The ID of the research agent
3160
3066
  */
3161
- id: z111.string()
3067
+ id: z110.string()
3162
3068
  });
3163
3069
 
3164
3070
  // ../../b4m-core/packages/services/dist/src/researchTaskService/process.js
3165
- import { z as z112 } from "zod";
3071
+ import { z as z111 } from "zod";
3166
3072
 
3167
3073
  // ../../b4m-core/packages/services/dist/src/lib/turndown.js
3168
3074
  import turndown from "turndown";
@@ -3553,316 +3459,316 @@ var deepResearchTool = {
3553
3459
  };
3554
3460
 
3555
3461
  // ../../b4m-core/packages/services/dist/src/researchTaskService/process.js
3556
- var ResearchTaskProcessSchema = z112.object({
3557
- id: z112.string()
3462
+ var ResearchTaskProcessSchema = z111.object({
3463
+ id: z111.string()
3558
3464
  });
3559
3465
 
3560
3466
  // ../../b4m-core/packages/services/dist/src/researchTaskService/create.js
3561
- import { z as z113 } from "zod";
3562
- var researchTaskCreateSchema = z113.object({
3563
- researchAgentId: z113.string(),
3564
- title: z113.string().max(100),
3565
- description: z113.string().max(500),
3566
- prompt: z113.string().max(500).optional(),
3567
- type: z113.nativeEnum(ResearchTaskType),
3568
- executionType: z113.nativeEnum(ResearchTaskExecutionType).default(ResearchTaskExecutionType.ON_DEMAND),
3569
- fileTagId: z113.string().optional(),
3570
- autoGeneratedTag: z113.object({
3571
- name: z113.string(),
3572
- icon: z113.string(),
3573
- 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()
3574
3480
  }).optional()
3575
3481
  });
3576
3482
  var researchTaskScrapeCreateSchema = researchTaskCreateSchema.extend({
3577
- urls: z113.array(z113.string().url()).min(1),
3578
- canDiscoverLinks: z113.boolean()
3483
+ urls: z112.array(z112.string().url()).min(1),
3484
+ canDiscoverLinks: z112.boolean()
3579
3485
  });
3580
3486
  var researchTaskPeriodicCreateSchema = researchTaskCreateSchema.extend({
3581
- executionPeriodicStartAt: z113.coerce.date(),
3582
- executionPeriodicEndAt: z113.coerce.date(),
3583
- executionPeriodicFrequency: z113.nativeEnum(ResearchTaskPeriodicFrequencyType)
3487
+ executionPeriodicStartAt: z112.coerce.date(),
3488
+ executionPeriodicEndAt: z112.coerce.date(),
3489
+ executionPeriodicFrequency: z112.nativeEnum(ResearchTaskPeriodicFrequencyType)
3584
3490
  });
3585
3491
  var researchTaskScheduledCreateSchema = researchTaskCreateSchema.extend({
3586
- executionScheduledAt: z113.coerce.date()
3492
+ executionScheduledAt: z112.coerce.date()
3587
3493
  });
3588
3494
  var researchTaskDeepResearchCreateSchema = researchTaskCreateSchema.extend({
3589
- maxDepth: z113.number().min(1).max(10).optional()
3495
+ maxDepth: z112.number().min(1).max(10).optional()
3590
3496
  });
3591
3497
 
3592
3498
  // ../../b4m-core/packages/services/dist/src/researchTaskService/search.js
3593
- import { z as z114 } from "zod";
3594
- var searchResearchTasksSchema = z114.object({
3595
- search: z114.string().optional(),
3499
+ import { z as z113 } from "zod";
3500
+ var searchResearchTasksSchema = z113.object({
3501
+ search: z113.string().optional(),
3596
3502
  // ADD FILTERS SCHEMA HERE
3597
3503
  // filters: z
3598
3504
  // .object({
3599
3505
  // userId: z.string().optional(),
3600
3506
  // })
3601
3507
  // .optional(),
3602
- pagination: z114.object({
3603
- page: z114.coerce.number().optional(),
3604
- limit: z114.coerce.number().optional()
3508
+ pagination: z113.object({
3509
+ page: z113.coerce.number().optional(),
3510
+ limit: z113.coerce.number().optional()
3605
3511
  }).optional(),
3606
- orderBy: z114.object({
3607
- by: z114.enum(["createdAt", "updatedAt"]).optional(),
3608
- direction: z114.enum(["asc", "desc"]).optional()
3512
+ orderBy: z113.object({
3513
+ by: z113.enum(["createdAt", "updatedAt"]).optional(),
3514
+ direction: z113.enum(["asc", "desc"]).optional()
3609
3515
  }).optional()
3610
3516
  });
3611
3517
 
3612
3518
  // ../../b4m-core/packages/services/dist/src/researchTaskService/get.js
3613
- import { z as z115 } from "zod";
3614
- var getResearchTaskSchema = z115.object({
3615
- id: z115.string().min(1)
3519
+ import { z as z114 } from "zod";
3520
+ var getResearchTaskSchema = z114.object({
3521
+ id: z114.string().min(1)
3616
3522
  });
3617
3523
 
3618
3524
  // ../../b4m-core/packages/services/dist/src/researchTaskService/update.js
3619
- import { z as z116 } from "zod";
3620
- var updateResearchTaskSchema = z116.object({
3621
- id: z116.string(),
3622
- title: z116.string(),
3623
- description: z116.string(),
3624
- 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)
3625
3531
  });
3626
3532
  var researchTaskScrapeUpdateSchema = updateResearchTaskSchema.extend({
3627
- urls: z116.array(z116.string().url()).min(1),
3628
- canDiscoverLinks: z116.boolean()
3533
+ urls: z115.array(z115.string().url()).min(1),
3534
+ canDiscoverLinks: z115.boolean()
3629
3535
  });
3630
3536
 
3631
3537
  // ../../b4m-core/packages/services/dist/src/researchTaskService/listByAgentId.js
3632
- import { z as z117 } from "zod";
3633
- var listByAgentIdSchema = z117.object({
3634
- researchAgentId: z117.string()
3538
+ import { z as z116 } from "zod";
3539
+ var listByAgentIdSchema = z116.object({
3540
+ researchAgentId: z116.string()
3635
3541
  });
3636
3542
 
3637
3543
  // ../../b4m-core/packages/services/dist/src/researchTaskService/remove.js
3638
- import { z as z118 } from "zod";
3639
- var researchTaskRemoveSchema = z118.object({
3640
- id: z118.string().min(1)
3544
+ import { z as z117 } from "zod";
3545
+ var researchTaskRemoveSchema = z117.object({
3546
+ id: z117.string().min(1)
3641
3547
  });
3642
3548
 
3643
3549
  // ../../b4m-core/packages/services/dist/src/researchTaskService/retry.js
3644
- import { z as z119 } from "zod";
3645
- var researchTaskRetrySchema = z119.object({
3646
- id: z119.string(),
3647
- userId: z119.string()
3550
+ import { z as z118 } from "zod";
3551
+ var researchTaskRetrySchema = z118.object({
3552
+ id: z118.string(),
3553
+ userId: z118.string()
3648
3554
  });
3649
3555
 
3650
3556
  // ../../b4m-core/packages/services/dist/src/researchTaskService/processDiscoveredLinks.js
3651
3557
  import axios4 from "axios";
3652
- import { z as z120 } from "zod";
3558
+ import { z as z119 } from "zod";
3653
3559
  import plimit from "p-limit";
3654
3560
  import pLimit2 from "p-limit";
3655
- var researchTaskProcessDiscoveredLinksSchema = z120.object({
3656
- id: z120.string()
3561
+ var researchTaskProcessDiscoveredLinksSchema = z119.object({
3562
+ id: z119.string()
3657
3563
  });
3658
3564
 
3659
3565
  // ../../b4m-core/packages/services/dist/src/researchTaskService/downloadRelevantLinks.js
3660
- import { z as z121 } from "zod";
3566
+ import { z as z120 } from "zod";
3661
3567
  import plimit2 from "p-limit";
3662
3568
  import axios5 from "axios";
3663
3569
  import { fileTypeFromBuffer } from "file-type";
3664
- var researchTaskDownloadRelevantLinksSchema = z121.object({
3665
- id: z121.string()
3570
+ var researchTaskDownloadRelevantLinksSchema = z120.object({
3571
+ id: z120.string()
3666
3572
  });
3667
3573
 
3668
3574
  // ../../b4m-core/packages/services/dist/src/researchData/remove.js
3669
- import { z as z122 } from "zod";
3670
- var researchDataRemoveSchema = z122.object({
3671
- id: z122.string(),
3672
- researchAgentId: z122.string()
3575
+ import { z as z121 } from "zod";
3576
+ var researchDataRemoveSchema = z121.object({
3577
+ id: z121.string(),
3578
+ researchAgentId: z121.string()
3673
3579
  });
3674
3580
 
3675
3581
  // ../../b4m-core/packages/services/dist/src/taskSchedulerService/create.js
3676
- import { z as z123 } from "zod";
3677
- var researchTaskPayload = z123.object({
3678
- id: z123.string(),
3679
- userId: z123.string()
3582
+ import { z as z122 } from "zod";
3583
+ var researchTaskPayload = z122.object({
3584
+ id: z122.string(),
3585
+ userId: z122.string()
3680
3586
  });
3681
- var customTaskPayload = z123.object({
3682
- test: z123.string()
3587
+ var customTaskPayload = z122.object({
3588
+ test: z122.string()
3683
3589
  });
3684
- var taskSchedulerCreate = z123.discriminatedUnion("handler", [
3685
- z123.object({
3686
- handler: z123.literal(TaskScheduleHandler.RESEARCH_TASK_PROCESS),
3590
+ var taskSchedulerCreate = z122.discriminatedUnion("handler", [
3591
+ z122.object({
3592
+ handler: z122.literal(TaskScheduleHandler.RESEARCH_TASK_PROCESS),
3687
3593
  payload: researchTaskPayload,
3688
- processDate: z123.date()
3594
+ processDate: z122.date()
3689
3595
  }),
3690
- z123.object({
3691
- handler: z123.literal(TaskScheduleHandler.CUSTOM_TASK_PROCESS),
3596
+ z122.object({
3597
+ handler: z122.literal(TaskScheduleHandler.CUSTOM_TASK_PROCESS),
3692
3598
  payload: customTaskPayload,
3693
- processDate: z123.date()
3599
+ processDate: z122.date()
3694
3600
  })
3695
3601
  ]);
3696
3602
 
3697
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
3698
3613
  import { z as z124 } from "zod";
3699
- var tagCreateFileTagSchema = z124.object({
3614
+ var tagCreateSchema = z124.object({
3700
3615
  name: z124.string(),
3701
3616
  icon: z124.string().optional(),
3617
+ description: z124.string().optional(),
3702
3618
  color: z124.string().optional(),
3703
- description: z124.string().optional()
3619
+ type: z124.nativeEnum(TagType)
3704
3620
  });
3705
3621
 
3706
- // ../../b4m-core/packages/services/dist/src/tagService/create.js
3622
+ // ../../b4m-core/packages/services/dist/src/tagService/update.js
3707
3623
  import { z as z125 } from "zod";
3708
- var tagCreateSchema = z125.object({
3709
- name: z125.string(),
3624
+ var tagUpdateSchema = z125.object({
3625
+ id: z125.string(),
3626
+ name: z125.string().optional(),
3710
3627
  icon: z125.string().optional(),
3711
3628
  description: z125.string().optional(),
3712
- color: z125.string().optional(),
3713
- type: z125.nativeEnum(TagType)
3714
- });
3715
-
3716
- // ../../b4m-core/packages/services/dist/src/tagService/update.js
3717
- import { z as z126 } from "zod";
3718
- var tagUpdateSchema = z126.object({
3719
- id: z126.string(),
3720
- name: z126.string().optional(),
3721
- icon: z126.string().optional(),
3722
- description: z126.string().optional(),
3723
- color: z126.string().optional()
3629
+ color: z125.string().optional()
3724
3630
  });
3725
3631
 
3726
3632
  // ../../b4m-core/packages/services/dist/src/tagService/remove.js
3727
- import { z as z127 } from "zod";
3728
- var tagRemoveSchema = z127.object({
3729
- id: z127.string()
3633
+ import { z as z126 } from "zod";
3634
+ var tagRemoveSchema = z126.object({
3635
+ id: z126.string()
3730
3636
  });
3731
3637
 
3732
3638
  // ../../b4m-core/packages/services/dist/src/artifactService/create.js
3733
- import { z as z128 } from "zod";
3734
- var createArtifactSchema = z128.object({
3735
- id: z128.string().optional(),
3639
+ import { z as z127 } from "zod";
3640
+ var createArtifactSchema = z127.object({
3641
+ id: z127.string().optional(),
3736
3642
  // Allow custom ID for AI-generated artifacts
3737
- type: z128.enum(["mermaid", "recharts", "python", "react", "html", "svg", "code", "quest", "file", "questmaster"]),
3738
- title: z128.string().min(1).max(255),
3739
- description: z128.string().max(1e3).optional(),
3740
- content: z128.string().min(1),
3741
- projectId: z128.string().optional(),
3742
- organizationId: z128.string().optional(),
3743
- visibility: z128.enum(["private", "project", "organization", "public"]).default("private"),
3744
- tags: z128.array(z128.string().max(50)).max(20).default([]),
3745
- versionTag: z128.string().max(100).optional(),
3746
- sourceQuestId: z128.string().optional(),
3747
- sessionId: z128.string().optional(),
3748
- parentArtifactId: z128.string().optional(),
3749
- permissions: z128.object({
3750
- canRead: z128.array(z128.string()).default([]),
3751
- canWrite: z128.array(z128.string()).default([]),
3752
- canDelete: z128.array(z128.string()).default([]),
3753
- isPublic: z128.boolean().default(false),
3754
- 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)
3755
3661
  }).optional(),
3756
- metadata: z128.record(z128.unknown()).default({})
3662
+ metadata: z127.record(z127.unknown()).default({})
3757
3663
  });
3758
3664
 
3759
3665
  // ../../b4m-core/packages/services/dist/src/artifactService/get.js
3760
- import { z as z129 } from "zod";
3761
- var getArtifactSchema = z129.object({
3762
- id: z129.string(),
3763
- includeContent: z129.boolean().default(false),
3764
- includeVersions: z129.boolean().default(false),
3765
- 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()
3766
3672
  });
3767
3673
 
3768
3674
  // ../../b4m-core/packages/services/dist/src/artifactService/list.js
3769
- import { z as z130 } from "zod";
3770
- var listArtifactsSchema = z130.object({
3771
- type: z130.string().optional(),
3772
- status: z130.enum(["draft", "review", "published", "archived"]).optional(),
3773
- visibility: z130.enum(["private", "project", "organization", "public"]).optional(),
3774
- projectId: z130.string().optional(),
3775
- sessionId: z130.string().optional(),
3776
- tags: z130.array(z130.string()).optional(),
3777
- search: z130.string().optional(),
3778
- limit: z130.number().min(1).max(100).default(20),
3779
- offset: z130.number().min(0).default(0),
3780
- sortBy: z130.enum(["createdAt", "updatedAt", "title", "type"]).default("updatedAt"),
3781
- sortOrder: z130.enum(["asc", "desc"]).default("desc"),
3782
- 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)
3783
3689
  });
3784
3690
 
3785
3691
  // ../../b4m-core/packages/services/dist/src/artifactService/update.js
3786
- import { z as z131 } from "zod";
3787
- var updateArtifactSchema = z131.object({
3788
- id: z131.string(),
3789
- title: z131.string().min(1).max(255).optional(),
3790
- description: z131.string().max(1e3).optional(),
3791
- content: z131.string().optional(),
3792
- visibility: z131.enum(["private", "project", "organization", "public"]).optional(),
3793
- status: z131.enum(["draft", "review", "published", "archived"]).optional(),
3794
- tags: z131.array(z131.string().max(50)).max(20).optional(),
3795
- versionTag: z131.string().max(100).optional(),
3796
- permissions: z131.object({
3797
- canRead: z131.array(z131.string()).optional(),
3798
- canWrite: z131.array(z131.string()).optional(),
3799
- canDelete: z131.array(z131.string()).optional(),
3800
- isPublic: z131.boolean().optional(),
3801
- 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()
3802
3708
  }).optional(),
3803
- metadata: z131.record(z131.unknown()).optional(),
3804
- changes: z131.array(z131.string()).optional(),
3805
- changeDescription: z131.string().max(1e3).optional(),
3806
- createNewVersion: z131.boolean().optional(),
3807
- 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()
3808
3714
  });
3809
3715
 
3810
3716
  // ../../b4m-core/packages/services/dist/src/artifactService/delete.js
3811
- import { z as z132 } from "zod";
3812
- var deleteArtifactSchema = z132.object({
3813
- id: z132.string(),
3814
- 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)
3815
3721
  // For future implementation
3816
3722
  });
3817
3723
 
3818
3724
  // ../../b4m-core/packages/services/dist/src/questMasterService/create.js
3819
- import { z as z133 } from "zod";
3820
- var questSchema = z133.object({
3821
- id: z133.string(),
3822
- title: z133.string().min(1).max(255),
3823
- description: z133.string().max(1e3),
3824
- status: z133.enum(["not_started", "in_progress", "completed", "blocked"]).default("not_started"),
3825
- order: z133.number().min(0),
3826
- dependencies: z133.array(z133.string()).default([]),
3827
- estimatedTime: z133.string().optional()
3828
- });
3829
- var questResourceSchema = z133.object({
3830
- title: z133.string().min(1).max(255),
3831
- url: z133.string().url(),
3832
- type: z133.enum(["documentation", "tutorial", "reference", "example"])
3833
- });
3834
- var createQuestMasterSchema = z133.object({
3835
- title: z133.string().min(1).max(255),
3836
- description: z133.string().max(1e3).optional(),
3837
- goal: z133.string().min(1).max(1e3),
3838
- complexity: z133.enum(["beginner", "intermediate", "advanced", "expert"]),
3839
- estimatedTotalTime: z133.string().optional(),
3840
- prerequisites: z133.array(z133.string().max(200)).default([]),
3841
- quests: z133.array(questSchema).min(1),
3842
- resources: z133.array(questResourceSchema).default([]),
3843
- projectId: z133.string().optional(),
3844
- organizationId: z133.string().optional(),
3845
- visibility: z133.enum(["private", "project", "organization", "public"]).default("private"),
3846
- tags: z133.array(z133.string().max(50)).max(20).default([]),
3847
- permissions: z133.object({
3848
- canRead: z133.array(z133.string()).default([]),
3849
- canWrite: z133.array(z133.string()).default([]),
3850
- canDelete: z133.array(z133.string()).default([]),
3851
- isPublic: z133.boolean().default(false),
3852
- 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)
3853
3759
  }).optional(),
3854
- sourceQuestId: z133.string().optional(),
3855
- sessionId: z133.string().optional(),
3856
- metadata: z133.record(z133.unknown()).default({})
3760
+ sourceQuestId: z132.string().optional(),
3761
+ sessionId: z132.string().optional(),
3762
+ metadata: z132.record(z132.unknown()).default({})
3857
3763
  });
3858
3764
 
3859
3765
  // ../../b4m-core/packages/services/dist/src/questMasterService/updateQuestStatus.js
3860
- import { z as z134 } from "zod";
3861
- var updateQuestStatusSchema = z134.object({
3862
- artifactId: z134.string(),
3863
- questId: z134.string(),
3864
- status: z134.enum(["not_started", "in_progress", "completed", "blocked"]),
3865
- 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()
3866
3772
  });
3867
3773
 
3868
3774
  // ../../b4m-core/packages/services/dist/src/dataLakeService/opensearchClient.js
@@ -3882,63 +3788,63 @@ import { v4 as uuidv44 } from "uuid";
3882
3788
  import { randomUUID as randomUUID5 } from "crypto";
3883
3789
 
3884
3790
  // ../../b4m-core/packages/services/dist/src/emailIngestionService/types.js
3885
- import { z as z135 } from "zod";
3886
- var processIngestedEmailOptionsSchema = z135.object({
3887
- platformDomain: z135.string().optional(),
3888
- 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()
3889
3795
  }).optional();
3890
- var emailAttachmentSchema = z135.object({
3891
- filename: z135.string().optional(),
3892
- contentType: z135.string().optional(),
3893
- contentDisposition: z135.string().optional(),
3894
- size: z135.number().min(0),
3895
- content: z135.instanceof(Buffer),
3896
- related: z135.boolean().optional()
3897
- });
3898
- var parsedEmailObjectSchema = z135.object({
3899
- messageId: z135.string().optional(),
3900
- inReplyTo: z135.string().optional(),
3901
- references: z135.union([z135.string(), z135.array(z135.string())]).optional(),
3902
- 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(),
3903
3809
  // Complex email address object
3904
- to: z135.any().optional(),
3905
- cc: z135.any().optional(),
3906
- bcc: z135.any().optional(),
3907
- subject: z135.string().optional(),
3908
- date: z135.date().optional(),
3909
- text: z135.string().optional(),
3910
- html: z135.string().optional(),
3911
- attachments: z135.array(emailAttachmentSchema).optional()
3912
- });
3913
- 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({
3914
3820
  parsedEmail: parsedEmailObjectSchema,
3915
- rawEmailS3Key: z135.string().min(1, "rawEmailS3Key cannot be empty"),
3821
+ rawEmailS3Key: z134.string().min(1, "rawEmailS3Key cannot be empty"),
3916
3822
  options: processIngestedEmailOptionsSchema
3917
3823
  });
3918
3824
 
3919
3825
  // ../../b4m-core/packages/services/dist/src/emailAnalysisService/types.js
3920
- import { z as z136 } from "zod";
3921
- var llmAnalysisResponseSchema = z136.object({
3922
- summary: z136.string().min(1, "Summary cannot be empty"),
3923
- entities: z136.object({
3924
- companies: z136.array(z136.string()).default([]),
3925
- people: z136.array(z136.string()).default([]),
3926
- products: z136.array(z136.string()).default([]),
3927
- 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([])
3928
3834
  }),
3929
- sentiment: z136.enum(["positive", "neutral", "negative", "urgent"]),
3930
- actionItems: z136.array(z136.object({
3931
- description: z136.string(),
3932
- 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()
3933
3839
  // ISO date string from LLM
3934
3840
  })).default([]),
3935
- privacyRecommendation: z136.enum(["public", "team", "private"]),
3936
- embargoDetected: z136.boolean().default(false),
3937
- 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([])
3938
3844
  });
3939
3845
 
3940
3846
  // ../../b4m-core/packages/services/dist/src/llm/ChatCompletion.js
3941
- import { z as z138 } from "zod";
3847
+ import { z as z137 } from "zod";
3942
3848
 
3943
3849
  // ../../b4m-core/packages/services/dist/src/llm/ChatCompletionInvoke.js
3944
3850
  import { fromZodError } from "zod-validation-error";
@@ -4052,8 +3958,8 @@ async function processAndStoreImages(images, context) {
4052
3958
  const buffer = await downloadImage(image);
4053
3959
  const fileType = await fileTypeFromBuffer2(buffer);
4054
3960
  const filename = `${uuidv45()}.${fileType?.ext}`;
4055
- const path13 = await context.imageGenerateStorage.upload(buffer, filename, {});
4056
- return path13;
3961
+ const path11 = await context.imageGenerateStorage.upload(buffer, filename, {});
3962
+ return path11;
4057
3963
  }));
4058
3964
  }
4059
3965
  async function updateQuestAndReturnMarkdown(storedImageUrls, context) {
@@ -4998,17 +4904,17 @@ var rechartsTool = {
4998
4904
  };
4999
4905
 
5000
4906
  // ../../b4m-core/packages/services/dist/src/llm/tools/implementation/editFile/index.js
5001
- import { z as z137 } from "zod";
4907
+ import { z as z136 } from "zod";
5002
4908
  import { diffLines as diffLines2 } from "diff";
5003
- var editFileSchema = z137.object({
5004
- fileId: z137.string().describe("The ID of the file to edit"),
5005
- instruction: z137.string().describe("Natural language instruction describing the changes to make"),
5006
- selection: z137.object({
5007
- start: z137.number().describe("Starting character position of the selection"),
5008
- 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")
5009
4915
  }).optional().describe("Optional selection range to edit within the file"),
5010
- preserveFormatting: z137.boolean().optional().default(true).describe("Whether to preserve the original formatting style"),
5011
- 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")
5012
4918
  });
5013
4919
  function generateSimpleDiff(original, modified) {
5014
4920
  const differences = diffLines2(original, modified);
@@ -5237,8 +5143,8 @@ async function processAndStoreImage(imageUrl, context) {
5237
5143
  const buffer = await downloadImage2(imageUrl);
5238
5144
  const fileType = await fileTypeFromBuffer3(buffer);
5239
5145
  const filename = `${uuidv46()}.${fileType?.ext}`;
5240
- const path13 = await context.imageGenerateStorage.upload(buffer, filename, {});
5241
- return path13;
5146
+ const path11 = await context.imageGenerateStorage.upload(buffer, filename, {});
5147
+ return path11;
5242
5148
  }
5243
5149
  async function updateQuestAndReturnMarkdown2(storedImagePath, context) {
5244
5150
  await context.onFinish?.("edit_image", storedImagePath);
@@ -6767,8 +6673,8 @@ var getHeliocentricCoords = (planet, T) => {
6767
6673
  const sinNode = Math.sin(longNode);
6768
6674
  const x = r * (cosNode * cosOmega - sinNode * sinOmega * cosI);
6769
6675
  const y = r * (sinNode * cosOmega + cosNode * sinOmega * cosI);
6770
- const z144 = r * sinOmega * sinI;
6771
- return { x, y, z: z144, r };
6676
+ const z143 = r * sinOmega * sinI;
6677
+ return { x, y, z: z143, r };
6772
6678
  };
6773
6679
  var getGeocentricEcliptic = (planet, earth) => {
6774
6680
  const dx = planet.x - earth.x;
@@ -7075,33 +6981,33 @@ var planetVisibilityTool = {
7075
6981
  };
7076
6982
 
7077
6983
  // ../../b4m-core/packages/services/dist/src/llm/tools/implementation/fileRead/index.js
7078
- import { promises as fs7 } from "fs";
7079
- import { existsSync as existsSync2, statSync as statSync3 } from "fs";
7080
- import path6 from "path";
7081
- 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;
7082
6988
  async function readFileContent(params) {
7083
6989
  const { path: filePath, encoding = "utf-8", maxLines } = params;
7084
- const normalizedPath = path6.normalize(filePath);
7085
- const resolvedPath = path6.resolve(process.cwd(), normalizedPath);
7086
- 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());
7087
6993
  if (!resolvedPath.startsWith(cwd)) {
7088
6994
  throw new Error(`Access denied: Cannot read files outside of current working directory`);
7089
6995
  }
7090
6996
  if (!existsSync2(resolvedPath)) {
7091
6997
  throw new Error(`File not found: ${filePath}`);
7092
6998
  }
7093
- const stats = statSync3(resolvedPath);
6999
+ const stats = statSync(resolvedPath);
7094
7000
  if (stats.isDirectory()) {
7095
7001
  throw new Error(`Path is a directory, not a file: ${filePath}`);
7096
7002
  }
7097
- if (stats.size > MAX_FILE_SIZE2) {
7098
- 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)`);
7099
7005
  }
7100
7006
  const isBinary = await checkIfBinary(resolvedPath);
7101
7007
  if (isBinary && encoding === "utf-8") {
7102
7008
  throw new Error(`File appears to be binary. Use encoding 'base64' to read binary files, or specify a different encoding.`);
7103
7009
  }
7104
- const content = await fs7.readFile(resolvedPath, encoding);
7010
+ const content = await fs5.readFile(resolvedPath, encoding);
7105
7011
  if (maxLines && typeof content === "string") {
7106
7012
  const lines = content.split("\n");
7107
7013
  if (lines.length > maxLines) {
@@ -7116,7 +7022,7 @@ ${content}`;
7116
7022
  }
7117
7023
  async function checkIfBinary(filePath) {
7118
7024
  const buffer = Buffer.alloc(8192);
7119
- const fd = await fs7.open(filePath, "r");
7025
+ const fd = await fs5.open(filePath, "r");
7120
7026
  try {
7121
7027
  const { bytesRead } = await fd.read(buffer, 0, 8192, 0);
7122
7028
  const chunk = buffer.slice(0, bytesRead);
@@ -7133,7 +7039,7 @@ var fileReadTool = {
7133
7039
  context.logger.info("\u{1F4C4} FileRead: Reading file", { path: params.path });
7134
7040
  try {
7135
7041
  const content = await readFileContent(params);
7136
- const stats = statSync3(path6.resolve(process.cwd(), path6.normalize(params.path)));
7042
+ const stats = statSync(path4.resolve(process.cwd(), path4.normalize(params.path)));
7137
7043
  context.logger.info("\u2705 FileRead: Success", {
7138
7044
  path: params.path,
7139
7045
  size: stats.size,
@@ -7172,25 +7078,25 @@ var fileReadTool = {
7172
7078
  };
7173
7079
 
7174
7080
  // ../../b4m-core/packages/services/dist/src/llm/tools/implementation/createFile/index.js
7175
- import { promises as fs8 } from "fs";
7081
+ import { promises as fs6 } from "fs";
7176
7082
  import { existsSync as existsSync3 } from "fs";
7177
- import path7 from "path";
7083
+ import path5 from "path";
7178
7084
  async function createFile(params) {
7179
7085
  const { path: filePath, content, createDirectories = true } = params;
7180
- const normalizedPath = path7.normalize(filePath);
7181
- const resolvedPath = path7.resolve(process.cwd(), normalizedPath);
7182
- 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());
7183
7089
  if (!resolvedPath.startsWith(cwd)) {
7184
7090
  throw new Error(`Access denied: Cannot create files outside of current working directory`);
7185
7091
  }
7186
7092
  const fileExists = existsSync3(resolvedPath);
7187
7093
  const action = fileExists ? "overwritten" : "created";
7188
7094
  if (createDirectories) {
7189
- const dir = path7.dirname(resolvedPath);
7190
- await fs8.mkdir(dir, { recursive: true });
7095
+ const dir = path5.dirname(resolvedPath);
7096
+ await fs6.mkdir(dir, { recursive: true });
7191
7097
  }
7192
- await fs8.writeFile(resolvedPath, content, "utf-8");
7193
- const stats = await fs8.stat(resolvedPath);
7098
+ await fs6.writeFile(resolvedPath, content, "utf-8");
7099
+ const stats = await fs6.stat(resolvedPath);
7194
7100
  const lines = content.split("\n").length;
7195
7101
  return `File ${action} successfully: ${filePath}
7196
7102
  Size: ${stats.size} bytes
@@ -7201,7 +7107,7 @@ var createFileTool = {
7201
7107
  implementation: (context) => ({
7202
7108
  toolFn: async (value) => {
7203
7109
  const params = value;
7204
- const fileExists = existsSync3(path7.resolve(process.cwd(), path7.normalize(params.path)));
7110
+ const fileExists = existsSync3(path5.resolve(process.cwd(), path5.normalize(params.path)));
7205
7111
  context.logger.info(`\u{1F4DD} CreateFile: ${fileExists ? "Overwriting" : "Creating"} file`, {
7206
7112
  path: params.path,
7207
7113
  size: params.content.length
@@ -7242,8 +7148,8 @@ var createFileTool = {
7242
7148
 
7243
7149
  // ../../b4m-core/packages/services/dist/src/llm/tools/implementation/globFiles/index.js
7244
7150
  import { readdir } from "fs/promises";
7245
- import { statSync as statSync4 } from "fs";
7246
- import path8 from "path";
7151
+ import { statSync as statSync2 } from "fs";
7152
+ import path6 from "path";
7247
7153
  function matchGlob(filePath, pattern) {
7248
7154
  let regexPattern = pattern.replace(/\./g, "\\.").replace(/\*\*/g, "{{GLOBSTAR}}").replace(/\*/g, "[^/]*").replace(/\?/g, ".").replace(/\{([^}]+)\}/g, (_, options) => `(${options.split(",").join("|")})`).replace(/\[([^\]]+)\]/g, "[$1]");
7249
7155
  regexPattern = regexPattern.replace(/\{\{GLOBSTAR\}\}\//g, "(.*/)?").replace(/\/\{\{GLOBSTAR\}\}/g, "(/.*)?").replace(/\{\{GLOBSTAR\}\}/g, ".*");
@@ -7261,8 +7167,8 @@ async function walkDir(dir, pattern, includeHidden, maxResults, basePath = "") {
7261
7167
  if (!includeHidden && entry.name.startsWith(".")) {
7262
7168
  continue;
7263
7169
  }
7264
- const relativePath = basePath ? path8.join(basePath, entry.name) : entry.name;
7265
- 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);
7266
7172
  if (matchGlob(relativePath, pattern)) {
7267
7173
  matches.push(relativePath);
7268
7174
  }
@@ -7278,7 +7184,7 @@ async function walkDir(dir, pattern, includeHidden, maxResults, basePath = "") {
7278
7184
  async function listFiles(params) {
7279
7185
  const { pattern, cwd: relativeCwd, includeHidden = false, maxResults = 1e3 } = params;
7280
7186
  const baseCwd = process.cwd();
7281
- const targetCwd = relativeCwd ? path8.resolve(baseCwd, path8.normalize(relativeCwd)) : baseCwd;
7187
+ const targetCwd = relativeCwd ? path6.resolve(baseCwd, path6.normalize(relativeCwd)) : baseCwd;
7282
7188
  if (!targetCwd.startsWith(baseCwd)) {
7283
7189
  throw new Error(`Access denied: Cannot list files outside of current working directory`);
7284
7190
  }
@@ -7289,8 +7195,8 @@ async function listFiles(params) {
7289
7195
  const filesInfo = [];
7290
7196
  for (const match of matches) {
7291
7197
  try {
7292
- const fullPath = path8.join(targetCwd, match);
7293
- const stats = statSync4(fullPath);
7198
+ const fullPath = path6.join(targetCwd, match);
7199
+ const stats = statSync2(fullPath);
7294
7200
  filesInfo.push({
7295
7201
  path: match,
7296
7202
  size: stats.size,
@@ -7371,9 +7277,9 @@ var globFilesTool = {
7371
7277
 
7372
7278
  // ../../b4m-core/packages/services/dist/src/llm/tools/implementation/grepSearch/index.js
7373
7279
  import { readdir as readdir2 } from "fs/promises";
7374
- import { readFileSync as readFileSync2, statSync as statSync5 } from "fs";
7375
- import path9 from "path";
7376
- 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;
7377
7283
  function matchGlob2(filePath, pattern) {
7378
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]");
7379
7285
  const regex = new RegExp(`^${regexPattern}$`);
@@ -7390,8 +7296,8 @@ async function walkDir2(dir, pattern, maxResults, basePath = "") {
7390
7296
  if (entry.name.startsWith(".")) {
7391
7297
  continue;
7392
7298
  }
7393
- const relativePath = basePath ? path9.join(basePath, entry.name) : entry.name;
7394
- 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);
7395
7301
  if (matchGlob2(relativePath, pattern)) {
7396
7302
  matches.push(relativePath);
7397
7303
  }
@@ -7404,10 +7310,10 @@ async function walkDir2(dir, pattern, maxResults, basePath = "") {
7404
7310
  }
7405
7311
  return matches;
7406
7312
  }
7407
- async function searchFiles2(params) {
7313
+ async function searchFiles(params) {
7408
7314
  const { pattern, filePattern = "**/*", cwd: relativeCwd, caseSensitive = false, maxResults = 100, contextLines = 0 } = params;
7409
7315
  const baseCwd = process.cwd();
7410
- const targetCwd = relativeCwd ? path9.resolve(baseCwd, path9.normalize(relativeCwd)) : baseCwd;
7316
+ const targetCwd = relativeCwd ? path7.resolve(baseCwd, path7.normalize(relativeCwd)) : baseCwd;
7411
7317
  if (!targetCwd.startsWith(baseCwd)) {
7412
7318
  throw new Error(`Access denied: Cannot search files outside of current working directory`);
7413
7319
  }
@@ -7421,13 +7327,13 @@ async function searchFiles2(params) {
7421
7327
  const filesToSearch = await walkDir2(targetCwd, filePattern, 1e4);
7422
7328
  const filteredFiles = [];
7423
7329
  for (const match of filesToSearch) {
7424
- const fullPath = path9.join(targetCwd, match);
7330
+ const fullPath = path7.join(targetCwd, match);
7425
7331
  try {
7426
- const stats = statSync5(fullPath);
7427
- if (stats.isDirectory() || stats.size > MAX_FILE_SIZE3) {
7332
+ const stats = statSync3(fullPath);
7333
+ if (stats.isDirectory() || stats.size > MAX_FILE_SIZE2) {
7428
7334
  continue;
7429
7335
  }
7430
- if (isBinaryFile2(fullPath)) {
7336
+ if (isBinaryFile(fullPath)) {
7431
7337
  continue;
7432
7338
  }
7433
7339
  filteredFiles.push(match);
@@ -7445,9 +7351,9 @@ async function searchFiles2(params) {
7445
7351
  break;
7446
7352
  }
7447
7353
  filesSearched++;
7448
- const fullPath = path9.join(targetCwd, file);
7354
+ const fullPath = path7.join(targetCwd, file);
7449
7355
  try {
7450
- const content = readFileSync2(fullPath, "utf-8");
7356
+ const content = readFileSync(fullPath, "utf-8");
7451
7357
  const lines = content.split("\n");
7452
7358
  for (let i = 0; i < lines.length; i++) {
7453
7359
  if (matches.length >= maxResults) {
@@ -7511,7 +7417,7 @@ ${match.context.after.map((l) => ` ${l}`).join("\n")}`;
7511
7417
  }).join("\n");
7512
7418
  return `${summary}${patternInfo}${cwdInfo}${matchesList}`;
7513
7419
  }
7514
- function isBinaryFile2(filePath) {
7420
+ function isBinaryFile(filePath) {
7515
7421
  try {
7516
7422
  const buffer = Buffer.alloc(8192);
7517
7423
  const fd = __require("fs").openSync(filePath, "r");
@@ -7534,7 +7440,7 @@ var grepSearchTool = {
7534
7440
  cwd: params.cwd || "."
7535
7441
  });
7536
7442
  try {
7537
- const result = await searchFiles2(params);
7443
+ const result = await searchFiles(params);
7538
7444
  context.logger.info("\u2705 GrepSearch: Success");
7539
7445
  return result;
7540
7446
  } catch (error) {
@@ -7580,31 +7486,31 @@ var grepSearchTool = {
7580
7486
  };
7581
7487
 
7582
7488
  // ../../b4m-core/packages/services/dist/src/llm/tools/implementation/deleteFile/index.js
7583
- import { promises as fs9 } from "fs";
7584
- import { existsSync as existsSync4, statSync as statSync6 } from "fs";
7585
- 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";
7586
7492
  async function deleteFile(params) {
7587
7493
  const { path: filePath, recursive = false } = params;
7588
- const normalizedPath = path10.normalize(filePath);
7589
- const resolvedPath = path10.resolve(process.cwd(), normalizedPath);
7590
- 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());
7591
7497
  if (!resolvedPath.startsWith(cwd)) {
7592
7498
  throw new Error(`Access denied: Cannot delete files outside of current working directory`);
7593
7499
  }
7594
7500
  if (!existsSync4(resolvedPath)) {
7595
7501
  throw new Error(`File or directory not found: ${filePath}`);
7596
7502
  }
7597
- const stats = statSync6(resolvedPath);
7503
+ const stats = statSync4(resolvedPath);
7598
7504
  const isDirectory = stats.isDirectory();
7599
7505
  const size = stats.size;
7600
7506
  if (isDirectory && !recursive) {
7601
7507
  throw new Error(`Path is a directory: ${filePath}. Use recursive=true to delete directories and their contents.`);
7602
7508
  }
7603
7509
  if (isDirectory) {
7604
- await fs9.rm(resolvedPath, { recursive: true, force: true });
7510
+ await fs7.rm(resolvedPath, { recursive: true, force: true });
7605
7511
  return `Directory deleted successfully: ${filePath}`;
7606
7512
  } else {
7607
- await fs9.unlink(resolvedPath);
7513
+ await fs7.unlink(resolvedPath);
7608
7514
  return `File deleted successfully: ${filePath}
7609
7515
  Size: ${size} bytes`;
7610
7516
  }
@@ -7614,8 +7520,8 @@ var deleteFileTool = {
7614
7520
  implementation: (context) => ({
7615
7521
  toolFn: async (value) => {
7616
7522
  const params = value;
7617
- const resolvedPath = path10.resolve(process.cwd(), path10.normalize(params.path));
7618
- 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();
7619
7525
  context.logger.info(`\u{1F5D1}\uFE0F DeleteFile: Deleting ${isDirectory ? "directory" : "file"}`, {
7620
7526
  path: params.path,
7621
7527
  recursive: params.recursive
@@ -7793,42 +7699,42 @@ var DISABLE_SERVER_THROTTLING = process.env.DISABLE_SERVER_THROTTLING === "true"
7793
7699
  var questSaveMutex = new Mutex();
7794
7700
 
7795
7701
  // ../../b4m-core/packages/services/dist/src/llm/ChatCompletion.js
7796
- var QuestStartBodySchema = z138.object({
7797
- userId: z138.string(),
7798
- sessionId: z138.string(),
7799
- questId: z138.string(),
7800
- message: z138.string(),
7801
- messageFileIds: z138.array(z138.string()),
7802
- historyCount: z138.number(),
7803
- 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()),
7804
7710
  params: ChatCompletionCreateInputSchema,
7805
7711
  dashboardParams: DashboardParamsSchema.optional(),
7806
- enableQuestMaster: z138.boolean().optional(),
7807
- enableMementos: z138.boolean().optional(),
7808
- enableArtifacts: z138.boolean().optional(),
7809
- enableAgents: z138.boolean().optional(),
7712
+ enableQuestMaster: z137.boolean().optional(),
7713
+ enableMementos: z137.boolean().optional(),
7714
+ enableArtifacts: z137.boolean().optional(),
7715
+ enableAgents: z137.boolean().optional(),
7810
7716
  promptMeta: PromptMetaZodSchema,
7811
- tools: z138.array(z138.union([b4mLLMTools, z138.string()])).optional(),
7812
- mcpServers: z138.array(z138.string()).optional(),
7813
- projectId: z138.string().optional(),
7814
- 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(),
7815
7721
  questMaster: QuestMasterParamsSchema.optional(),
7816
- toolPromptId: z138.string().optional(),
7722
+ toolPromptId: z137.string().optional(),
7817
7723
  researchMode: ResearchModeParamsSchema.optional(),
7818
- fallbackModel: z138.string().optional(),
7819
- embeddingModel: z138.string().optional(),
7820
- queryComplexity: z138.string(),
7724
+ fallbackModel: z137.string().optional(),
7725
+ embeddingModel: z137.string().optional(),
7726
+ queryComplexity: z137.string(),
7821
7727
  imageConfig: GenerateImageToolCallSchema.optional(),
7822
- deepResearchConfig: z138.object({
7823
- maxDepth: z138.number().optional(),
7824
- duration: z138.number().optional(),
7728
+ deepResearchConfig: z137.object({
7729
+ maxDepth: z137.number().optional(),
7730
+ duration: z137.number().optional(),
7825
7731
  // Note: searchers are passed via ToolContext and not through this API schema
7826
- searchers: z138.array(z138.any()).optional()
7732
+ searchers: z137.array(z137.any()).optional()
7827
7733
  }).optional(),
7828
- extraContextMessages: z138.array(z138.object({
7829
- role: z138.enum(["user", "assistant", "system", "function", "tool"]),
7830
- content: z138.union([z138.string(), z138.array(z138.any())]),
7831
- 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()
7832
7738
  })).optional()
7833
7739
  });
7834
7740
 
@@ -7836,9 +7742,30 @@ var QuestStartBodySchema = z138.object({
7836
7742
  import axios8 from "axios";
7837
7743
  import { fileTypeFromBuffer as fileTypeFromBuffer4 } from "file-type";
7838
7744
  import { v4 as uuidv47 } from "uuid";
7839
- import { z as z139 } from "zod";
7745
+ import { z as z138 } from "zod";
7840
7746
  import { fromZodError as fromZodError2 } from "zod-validation-error";
7841
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({
7842
7769
  sessionId: z139.string(),
7843
7770
  questId: z139.string(),
7844
7771
  userId: z139.string(),
@@ -7846,56 +7773,35 @@ var ImageGenerationBodySchema = OpenAIImageGenerationInput.extend({
7846
7773
  safety_tolerance: z139.number().min(BFL_SAFETY_TOLERANCE.MIN).max(BFL_SAFETY_TOLERANCE.MAX).optional().default(BFL_SAFETY_TOLERANCE.DEFAULT),
7847
7774
  prompt_upsampling: z139.boolean().optional().default(false),
7848
7775
  seed: z139.number().nullable().optional(),
7849
- output_format: z139.enum(["jpeg", "png"]).nullable().optional().default("png"),
7776
+ output_format: z139.enum(["jpeg", "png"]).optional().default("png"),
7850
7777
  width: z139.number().optional(),
7851
7778
  height: z139.number().optional(),
7852
7779
  aspect_ratio: z139.string().optional(),
7853
- fabFileIds: z139.array(z139.string()).optional()
7854
- });
7855
-
7856
- // ../../b4m-core/packages/services/dist/src/llm/ImageEdit.js
7857
- import axios9 from "axios";
7858
- import { fileTypeFromBuffer as fileTypeFromBuffer5 } from "file-type";
7859
- import { v4 as uuidv48 } from "uuid";
7860
- import { z as z140 } from "zod";
7861
- import { fromZodError as fromZodError3 } from "zod-validation-error";
7862
- var ImageEditBodySchema = OpenAIImageGenerationInput.extend({
7863
- sessionId: z140.string(),
7864
- questId: z140.string(),
7865
- userId: z140.string(),
7866
- prompt: z140.string(),
7867
- safety_tolerance: z140.number().min(BFL_SAFETY_TOLERANCE.MIN).max(BFL_SAFETY_TOLERANCE.MAX).optional().default(BFL_SAFETY_TOLERANCE.DEFAULT),
7868
- prompt_upsampling: z140.boolean().optional().default(false),
7869
- seed: z140.number().nullable().optional(),
7870
- output_format: z140.enum(["jpeg", "png"]).optional().default("png"),
7871
- width: z140.number().optional(),
7872
- height: z140.number().optional(),
7873
- aspect_ratio: z140.string().optional(),
7874
- size: z140.string().optional(),
7875
- fabFileIds: z140.array(z140.string()).optional(),
7876
- image: z140.string()
7780
+ size: z139.string().optional(),
7781
+ fabFileIds: z139.array(z139.string()).optional(),
7782
+ image: z139.string()
7877
7783
  });
7878
7784
 
7879
7785
  // ../../b4m-core/packages/services/dist/src/llm/refineText.js
7880
- import { z as z141 } from "zod";
7881
- var refineTextLLMSchema = z141.object({
7882
- text: z141.string(),
7883
- 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()
7884
7790
  // tone: z.enum(['formal', 'informal', 'neutral']).optional(),
7885
7791
  // style: z.enum(['technical', 'creative', 'academic', 'business', 'narrative']).optional(),
7886
7792
  });
7887
7793
 
7888
7794
  // ../../b4m-core/packages/services/dist/src/llm/MementoEvaluationService.js
7889
- import { z as z142 } from "zod";
7890
- var SingleMementoEvalSchema = z142.object({
7891
- 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),
7892
7798
  // 1-10 scale for personal info importance
7893
- summary: z142.string(),
7894
- tags: z142.array(z142.string()).optional()
7799
+ summary: z141.string(),
7800
+ tags: z141.array(z141.string()).optional()
7895
7801
  });
7896
- var MementoEvalResponseSchema = z142.object({
7897
- isPersonal: z142.boolean(),
7898
- mementos: z142.array(SingleMementoEvalSchema).optional()
7802
+ var MementoEvalResponseSchema = z141.object({
7803
+ isPersonal: z141.boolean(),
7804
+ mementos: z141.array(SingleMementoEvalSchema).optional()
7899
7805
  // Array of distinct personal information
7900
7806
  });
7901
7807
 
@@ -7941,7 +7847,7 @@ async function generateFileDeletePreview(args) {
7941
7847
  if (!existsSync5(args.path)) {
7942
7848
  return `[File does not exist: ${args.path}]`;
7943
7849
  }
7944
- 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));
7945
7851
  return `[File will be deleted]
7946
7852
 
7947
7853
  Path: ${args.path}
@@ -7957,21 +7863,21 @@ var NoOpStorage = class extends BaseStorage {
7957
7863
  async upload(input, destination, options) {
7958
7864
  return `/tmp/${destination}`;
7959
7865
  }
7960
- async download(path13) {
7866
+ async download(path11) {
7961
7867
  throw new Error("Download not supported in CLI");
7962
7868
  }
7963
- async delete(path13) {
7869
+ async delete(path11) {
7964
7870
  }
7965
- async getSignedUrl(path13) {
7966
- return `/tmp/${path13}`;
7871
+ async getSignedUrl(path11) {
7872
+ return `/tmp/${path11}`;
7967
7873
  }
7968
- getPublicUrl(path13) {
7969
- return `/tmp/${path13}`;
7874
+ getPublicUrl(path11) {
7875
+ return `/tmp/${path11}`;
7970
7876
  }
7971
- async getPreview(path13) {
7972
- return `/tmp/${path13}`;
7877
+ async getPreview(path11) {
7878
+ return `/tmp/${path11}`;
7973
7879
  }
7974
- async getMetadata(path13) {
7880
+ async getMetadata(path11) {
7975
7881
  return { size: 0, contentType: "application/octet-stream" };
7976
7882
  }
7977
7883
  };
@@ -7991,7 +7897,7 @@ var CliLogger = class extends Logger {
7991
7897
  log(...args) {
7992
7898
  }
7993
7899
  };
7994
- function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, agentContext) {
7900
+ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, agentContext, configStore) {
7995
7901
  const originalFn = tool.toolFn;
7996
7902
  const toolName = tool.toolSchema.name;
7997
7903
  return {
@@ -8035,7 +7941,25 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
8035
7941
  throw new PermissionDeniedError(toolName, args);
8036
7942
  }
8037
7943
  if (response.action === "allow-always") {
8038
- 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
+ }
8039
7963
  }
8040
7964
  const result = await originalFn(args);
8041
7965
  agentContext.observationQueue.push({ toolName, result });
@@ -8043,7 +7967,7 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
8043
7967
  }
8044
7968
  };
8045
7969
  }
8046
- function generateCliTools(userId, llm, model, permissionManager, showPermissionPrompt, agentContext, toolApiKeys) {
7970
+ function generateCliTools(userId, llm, model, permissionManager, showPermissionPrompt, agentContext, configStore, toolApiKeys) {
8047
7971
  const logger2 = new CliLogger();
8048
7972
  const storage = new NoOpStorage();
8049
7973
  const user = {
@@ -8127,13 +8051,15 @@ function generateCliTools(userId, llm, model, permissionManager, showPermissionP
8127
8051
  toolConfig,
8128
8052
  model
8129
8053
  );
8130
- 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
+ );
8131
8057
  return { tools: tools2, agentContext };
8132
8058
  }
8133
8059
 
8134
8060
  // src/config/toolSafety.ts
8135
- import { z as z143 } from "zod";
8136
- var ToolCategorySchema = z143.enum([
8061
+ import { z as z142 } from "zod";
8062
+ var ToolCategorySchema = z142.enum([
8137
8063
  "auto_approve",
8138
8064
  // Safe tools that run automatically without permission
8139
8065
  "prompt_always",
@@ -8141,9 +8067,9 @@ var ToolCategorySchema = z143.enum([
8141
8067
  "prompt_default"
8142
8068
  // Tools that prompt by default but can be trusted
8143
8069
  ]);
8144
- var ToolSafetyConfigSchema = z143.object({
8145
- categories: z143.record(z143.string(), ToolCategorySchema),
8146
- trustedTools: z143.array(z143.string())
8070
+ var ToolSafetyConfigSchema = z142.object({
8071
+ categories: z142.record(z142.string(), ToolCategorySchema),
8072
+ trustedTools: z142.array(z142.string())
8147
8073
  });
8148
8074
  var DEFAULT_TOOL_CATEGORIES = {
8149
8075
  // ===== AUTO APPROVE (Safe tools) =====
@@ -8192,23 +8118,30 @@ function canTrustTool(toolName, customCategories) {
8192
8118
 
8193
8119
  // src/utils/PermissionManager.ts
8194
8120
  var PermissionManager = class {
8195
- constructor(trustedTools = [], customCategories) {
8121
+ constructor(trustedTools = [], customCategories, deniedTools) {
8196
8122
  this.trustedTools = /* @__PURE__ */ new Set();
8123
+ this.deniedTools = /* @__PURE__ */ new Set();
8197
8124
  this.trustedTools = new Set(trustedTools);
8198
8125
  this.customCategories = new Map(Object.entries(customCategories || {}));
8126
+ this.deniedTools = new Set(deniedTools || []);
8199
8127
  }
8200
8128
  /**
8201
8129
  * Check if a tool needs permission before execution
8202
8130
  *
8203
8131
  * A tool needs permission if:
8204
- * 1. It's not in the auto_approve category, AND
8205
- * 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
8206
8135
  *
8207
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)
8208
8138
  */
8209
8139
  needsPermission(toolName) {
8210
8140
  const categoryMap = Object.fromEntries(this.customCategories);
8211
8141
  const category = getToolCategory(toolName, categoryMap);
8142
+ if (this.deniedTools.has(toolName)) {
8143
+ return true;
8144
+ }
8212
8145
  if (category === "auto_approve") {
8213
8146
  return false;
8214
8147
  }
@@ -8219,10 +8152,13 @@ var PermissionManager = class {
8219
8152
  }
8220
8153
  /**
8221
8154
  * Add a tool to the trusted list
8222
- * 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)
8223
8156
  */
8224
8157
  trustTool(toolName) {
8225
8158
  const categoryMap = Object.fromEntries(this.customCategories);
8159
+ if (this.deniedTools.has(toolName)) {
8160
+ return false;
8161
+ }
8226
8162
  if (!canTrustTool(toolName, categoryMap)) {
8227
8163
  return false;
8228
8164
  }
@@ -8255,12 +8191,27 @@ var PermissionManager = class {
8255
8191
  return getToolCategory(toolName, categoryMap);
8256
8192
  }
8257
8193
  /**
8258
- * 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)
8259
8195
  */
8260
8196
  canBeTrusted(toolName) {
8261
8197
  const categoryMap = Object.fromEntries(this.customCategories);
8198
+ if (this.deniedTools.has(toolName)) {
8199
+ return false;
8200
+ }
8262
8201
  return canTrustTool(toolName, categoryMap);
8263
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
+ }
8264
8215
  /**
8265
8216
  * Clear all trusted tools
8266
8217
  */
@@ -8297,8 +8248,8 @@ function getEnvironmentName(configApiConfig) {
8297
8248
  }
8298
8249
 
8299
8250
  // src/utils/Logger.ts
8300
- import fs10 from "fs/promises";
8301
- import path11 from "path";
8251
+ import fs8 from "fs/promises";
8252
+ import path9 from "path";
8302
8253
  import os from "os";
8303
8254
  var Logger2 = class _Logger {
8304
8255
  constructor() {
@@ -8321,9 +8272,9 @@ var Logger2 = class _Logger {
8321
8272
  */
8322
8273
  async initialize(sessionId) {
8323
8274
  this.sessionId = sessionId;
8324
- const debugDir = path11.join(os.homedir(), ".bike4mind", "debug");
8325
- await fs10.mkdir(debugDir, { recursive: true });
8326
- 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`);
8327
8278
  await this.writeToFile("INFO", "=== CLI SESSION START ===");
8328
8279
  }
8329
8280
  /**
@@ -8387,7 +8338,7 @@ var Logger2 = class _Logger {
8387
8338
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").substring(0, 19);
8388
8339
  const logEntry = `[${timestamp}] [${level}] ${message}
8389
8340
  `;
8390
- await fs10.appendFile(this.logFilePath, logEntry, "utf-8");
8341
+ await fs8.appendFile(this.logFilePath, logEntry, "utf-8");
8391
8342
  } catch (error) {
8392
8343
  console.error("File logging failed:", error);
8393
8344
  }
@@ -8533,15 +8484,15 @@ var Logger2 = class _Logger {
8533
8484
  async cleanupOldLogs() {
8534
8485
  if (!this.fileLoggingEnabled) return;
8535
8486
  try {
8536
- const debugDir = path11.join(os.homedir(), ".bike4mind", "debug");
8537
- const files = await fs10.readdir(debugDir);
8487
+ const debugDir = path9.join(os.homedir(), ".bike4mind", "debug");
8488
+ const files = await fs8.readdir(debugDir);
8538
8489
  const now = Date.now();
8539
8490
  const thirtyDaysAgo = now - 30 * 24 * 60 * 60 * 1e3;
8540
8491
  for (const file of files) {
8541
- const filePath = path11.join(debugDir, file);
8542
- const stats = await fs10.stat(filePath);
8492
+ const filePath = path9.join(debugDir, file);
8493
+ const stats = await fs8.stat(filePath);
8543
8494
  if (stats.mtime.getTime() < thirtyDaysAgo) {
8544
- await fs10.unlink(filePath);
8495
+ await fs8.unlink(filePath);
8545
8496
  }
8546
8497
  }
8547
8498
  } catch (error) {
@@ -8554,8 +8505,8 @@ var logger = Logger2.getInstance();
8554
8505
  // ../../b4m-core/packages/mcp/dist/src/client.js
8555
8506
  import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
8556
8507
  import { Client as Client2 } from "@modelcontextprotocol/sdk/client/index.js";
8557
- import path12 from "path";
8558
- import { existsSync as existsSync6, readdirSync as readdirSync3 } from "fs";
8508
+ import path10 from "path";
8509
+ import { existsSync as existsSync6, readdirSync } from "fs";
8559
8510
  var MCPClient = class {
8560
8511
  // Note: This class handles MCP server communication with repository filtering
8561
8512
  mcp;
@@ -8580,20 +8531,20 @@ var MCPClient = class {
8580
8531
  const root = process.env.INIT_CWD || process.cwd();
8581
8532
  const candidatePaths = [
8582
8533
  // When running from SST Lambda with node_modules structure (copyFiles)
8583
- 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`),
8584
8535
  // When running from SST Lambda deployed environment (/var/task)
8585
- 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`),
8586
8537
  // When running from SST Lambda (.sst/artifacts/mcpHandler-dev), navigate to monorepo root (3 levels up)
8587
- 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`),
8588
8539
  // When running from packages/client (Next.js app), navigate to monorepo root (2 levels up)
8589
- 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`),
8590
8541
  // Original paths (backward compatibility)
8591
- path12.join(root, `/b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
8592
- 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")
8593
8544
  ];
8594
8545
  const serverScriptPath = candidatePaths.find((p) => existsSync6(p));
8595
8546
  if (!serverScriptPath) {
8596
- 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);
8597
8548
  console.error(`[MCP] Server script not found. Tried paths:`, candidatePaths);
8598
8549
  console.error(`[MCP] Available directories in ${root}:`, getDirectories(root));
8599
8550
  throw new Error(`MCP Server script path not found for ${this.serverName}. Root: ${root}, Available dirs: ${getDirectories(root).join(", ")}`);
@@ -8622,7 +8573,7 @@ var MCPClient = class {
8622
8573
  }
8623
8574
  };
8624
8575
  await this.mcp.connect(this.transport);
8625
- await new Promise((resolve3) => setTimeout(resolve3, 100));
8576
+ await new Promise((resolve) => setTimeout(resolve, 100));
8626
8577
  const toolsResult = await this.mcp.listTools();
8627
8578
  this.tools = toolsResult.tools.map((tool) => {
8628
8579
  return {
@@ -8805,7 +8756,7 @@ var ServerLlmBackend = class {
8805
8756
  */
8806
8757
  async complete(model, messages, options, callback) {
8807
8758
  logger.debug(`[ServerLlmBackend] Starting complete() with model: ${model}`);
8808
- return new Promise(async (resolve3, reject) => {
8759
+ return new Promise(async (resolve, reject) => {
8809
8760
  try {
8810
8761
  logger.debug("[ServerLlmBackend] Making streaming request...");
8811
8762
  const response = await this.makeStreamingRequest(model, messages, options);
@@ -8835,15 +8786,15 @@ var ServerLlmBackend = class {
8835
8786
  reject(err);
8836
8787
  }).then(() => {
8837
8788
  logger.debug("[ServerLlmBackend] Callback completed, resolving");
8838
- resolve3();
8789
+ resolve();
8839
8790
  });
8840
8791
  } else if (cleanedText) {
8841
8792
  callback([cleanedText], lastUsageInfo).catch((err) => {
8842
8793
  logger.error("[ServerLlmBackend] Callback error:", err);
8843
8794
  reject(err);
8844
- }).then(() => resolve3());
8795
+ }).then(() => resolve());
8845
8796
  } else {
8846
- resolve3();
8797
+ resolve();
8847
8798
  }
8848
8799
  return;
8849
8800
  }
@@ -8903,7 +8854,7 @@ var ServerLlmBackend = class {
8903
8854
  response.data.on("end", () => {
8904
8855
  if (!receivedDone) {
8905
8856
  logger.debug("[ServerLlmBackend] Stream ended without [DONE], resolving anyway");
8906
- resolve3();
8857
+ resolve();
8907
8858
  } else {
8908
8859
  logger.debug("[ServerLlmBackend] Stream ended, [DONE] handler will resolve");
8909
8860
  }
@@ -9170,7 +9121,7 @@ var ApiClient = class {
9170
9121
  // package.json
9171
9122
  var package_default = {
9172
9123
  name: "@bike4mind/cli",
9173
- version: "0.2.1-feat-cli-file-reference.17024+3bc00b63c",
9124
+ version: "0.2.1-feat-cli-project-scoped-config.16996+16c515189",
9174
9125
  type: "module",
9175
9126
  description: "Interactive CLI tool for Bike4Mind with ReAct agents",
9176
9127
  license: "UNLICENSED",
@@ -9181,9 +9132,6 @@ var package_default = {
9181
9132
  },
9182
9133
  homepage: "https://github.com/bike4mind/lumina5#readme",
9183
9134
  bugs: "https://github.com/bike4mind/lumina5/issues",
9184
- publishConfig: {
9185
- access: "public"
9186
- },
9187
9135
  keywords: [
9188
9136
  "cli",
9189
9137
  "ai",
@@ -9204,8 +9152,6 @@ var package_default = {
9204
9152
  dev: "tsx src/index.tsx",
9205
9153
  build: "tsup",
9206
9154
  typecheck: "tsc --noEmit",
9207
- test: "vitest run",
9208
- "test:watch": "vitest",
9209
9155
  start: "node dist/index.js",
9210
9156
  prepublishOnly: "pnpm build"
9211
9157
  },
@@ -9272,10 +9218,10 @@ var package_default = {
9272
9218
  },
9273
9219
  devDependencies: {
9274
9220
  "@bike4mind/agents": "0.1.0",
9275
- "@bike4mind/common": "2.36.1-feat-cli-file-reference.17024+3bc00b63c",
9276
- "@bike4mind/mcp": "1.19.4-feat-cli-file-reference.17024+3bc00b63c",
9277
- "@bike4mind/services": "2.29.1-feat-cli-file-reference.17024+3bc00b63c",
9278
- "@bike4mind/utils": "2.0.3-feat-cli-file-reference.17024+3bc00b63c",
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",
9279
9225
  "@types/diff": "^5.0.9",
9280
9226
  "@types/jsonwebtoken": "^9.0.4",
9281
9227
  "@types/node": "^22.9.0",
@@ -9284,10 +9230,9 @@ var package_default = {
9284
9230
  "@types/yargs": "^17.0.32",
9285
9231
  tsup: "^8.5.1",
9286
9232
  tsx: "^4.21.0",
9287
- typescript: "^5.9.3",
9288
- vitest: "^3.2.4"
9233
+ typescript: "^5.9.3"
9289
9234
  },
9290
- gitHead: "3bc00b63c23e8153e62c6f7f28671702dfc0deba"
9235
+ gitHead: "16c515189f0b9a7e3ccea2c9874866dd2e8fe084"
9291
9236
  };
9292
9237
 
9293
9238
  // src/index.tsx
@@ -9310,7 +9255,8 @@ function CliApp() {
9310
9255
  agent: null,
9311
9256
  mcpManager: null,
9312
9257
  permissionManager: null,
9313
- permissionPrompt: null
9258
+ permissionPrompt: null,
9259
+ trustLocationSelector: null
9314
9260
  });
9315
9261
  const [isInitialized, setIsInitialized] = useState3(false);
9316
9262
  const [initError, setInitError] = useState3(null);
@@ -9339,7 +9285,7 @@ function CliApp() {
9339
9285
  }
9340
9286
  await Promise.race([
9341
9287
  Promise.all(cleanupTasks),
9342
- new Promise((resolve3) => setTimeout(resolve3, 500))
9288
+ new Promise((resolve) => setTimeout(resolve, 500))
9343
9289
  // 500ms timeout
9344
9290
  ]);
9345
9291
  setTimeout(() => {
@@ -9471,11 +9417,17 @@ function CliApp() {
9471
9417
  debug: () => {
9472
9418
  }
9473
9419
  };
9474
- 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
+ );
9475
9427
  const promptFn = (toolName, args, preview) => {
9476
- return new Promise((resolve3) => {
9428
+ return new Promise((resolve) => {
9477
9429
  const canBeTrusted = permissionManager.canBeTrusted(toolName);
9478
- const prompt = { toolName, args, preview, canBeTrusted, resolve: resolve3 };
9430
+ const prompt = { toolName, args, preview, canBeTrusted, resolve };
9479
9431
  setState((prev) => ({
9480
9432
  ...prev,
9481
9433
  permissionManager,
@@ -9499,6 +9451,7 @@ function CliApp() {
9499
9451
  permissionManager,
9500
9452
  promptFn,
9501
9453
  agentContext,
9454
+ state.configStore,
9502
9455
  config.toolApiKeys
9503
9456
  );
9504
9457
  console.log(`\u{1F6E0}\uFE0F Loaded ${b4mTools.length} B4M tool(s)`);
@@ -9549,7 +9502,7 @@ Remember: Use context from previous messages to understand follow-up questions.`
9549
9502
  llm,
9550
9503
  model: modelInfo.id,
9551
9504
  tools: allTools,
9552
- maxIterations: 10,
9505
+ maxIterations: 3,
9553
9506
  maxTokens: config.preferences.maxTokens,
9554
9507
  temperature: config.preferences.temperature,
9555
9508
  systemPrompt: cliSystemPrompt
@@ -9677,6 +9630,9 @@ Tool Permissions:
9677
9630
  /trust <tool-name> - Trust a tool (won't ask permission again)
9678
9631
  /untrust <tool-name> - Remove tool from trusted list
9679
9632
  /trusted - List all trusted tools
9633
+
9634
+ Project Configuration:
9635
+ /project-config - Show merged project configuration
9680
9636
  `);
9681
9637
  break;
9682
9638
  case "exit":
@@ -9768,7 +9724,7 @@ Tool Permissions:
9768
9724
  console.log("");
9769
9725
  break;
9770
9726
  }
9771
- case "trust":
9727
+ case "trust": {
9772
9728
  if (!state.permissionManager) {
9773
9729
  console.log("Permission manager not initialized");
9774
9730
  return;
@@ -9776,16 +9732,85 @@ Tool Permissions:
9776
9732
  const toolToTrust = args[0];
9777
9733
  if (!toolToTrust) {
9778
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("");
9779
9739
  return;
9780
9740
  }
9781
- const trusted = state.permissionManager.trustTool(toolToTrust);
9782
- if (trusted) {
9783
- await state.configStore.trustTool(toolToTrust);
9784
- console.log(`\u2705 Tool '${toolToTrust}' is now trusted and won't require permission`);
9785
- } else {
9786
- 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;
9787
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
+ }));
9788
9812
  break;
9813
+ }
9789
9814
  case "untrust":
9790
9815
  if (!state.permissionManager) {
9791
9816
  console.log("Permission manager not initialized");
@@ -9834,6 +9859,50 @@ Tool Permissions:
9834
9859
  console.log(`Expires: ${new Date(authTokens.expiresAt).toLocaleString()}`);
9835
9860
  console.log("");
9836
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
+ }
9837
9906
  default:
9838
9907
  console.log(`Unknown command: /${command}`);
9839
9908
  console.log("Type /help for available commands");
@@ -9842,6 +9911,26 @@ Tool Permissions:
9842
9911
  if (initError) {
9843
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"));
9844
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
+ }
9845
9934
  if (state.showLoginFlow) {
9846
9935
  const loginApiUrl = getApiUrl(state.config?.apiConfig);
9847
9936
  return /* @__PURE__ */ React11.createElement(