@bike4mind/cli 0.2.12-cli-todo-list.17408 → 0.2.12-feat-secops-secrets.17399

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-XM52K32A.js";
8
- import "./chunk-JXROCVSM.js";
9
- import "./chunk-7N7AZPLK.js";
7
+ } from "./chunk-ZHCX7BLB.js";
8
+ import "./chunk-ID4NS6KF.js";
9
+ import "./chunk-RJFNIMVH.js";
10
10
  import {
11
11
  BFLImageService,
12
12
  BaseStorage,
@@ -15,10 +15,10 @@ import {
15
15
  OpenAIBackend,
16
16
  OpenAIImageService,
17
17
  XAIImageService
18
- } from "./chunk-INYINU6X.js";
18
+ } from "./chunk-BU5TP3BH.js";
19
19
  import {
20
20
  Logger
21
- } from "./chunk-OCYRD7D6.js";
21
+ } from "./chunk-AMDXHL6S.js";
22
22
  import "./chunk-BPFEGDC7.js";
23
23
  import {
24
24
  AiEvents,
@@ -74,6 +74,9 @@ import {
74
74
  b4mLLMTools,
75
75
  getMcpProviderMetadata
76
76
  } from "./chunk-OHR7UCTC.js";
77
+ import {
78
+ __require
79
+ } from "./chunk-PDX44BCA.js";
77
80
 
78
81
  // src/index.tsx
79
82
  import React17, { useState as useState8, useEffect as useEffect3, useCallback, useRef as useRef2 } from "react";
@@ -179,11 +182,11 @@ function CustomTextInput({
179
182
  setCursorOffset(Math.min(value.length, cursorOffset + 1));
180
183
  return;
181
184
  }
182
- if (!key.ctrl && !key.meta && input.length > 0) {
185
+ if (!key.ctrl && !key.meta && input.length === 1) {
183
186
  const sanitizedInput = input === "\r" ? "\n" : input;
184
187
  const newValue = value.slice(0, cursorOffset) + sanitizedInput + value.slice(cursorOffset);
185
188
  onChange(newValue);
186
- setCursorOffset(cursorOffset + sanitizedInput.length);
189
+ setCursorOffset(cursorOffset + 1);
187
190
  }
188
191
  },
189
192
  { isActive: !disabled }
@@ -710,7 +713,7 @@ var ImageInputDetector = class {
710
713
  if (!this.looksLikeFilePath(input)) return null;
711
714
  let filepath = input.trim();
712
715
  filepath = filepath.replace(/^["']|["']$/g, "");
713
- filepath = filepath.replace(/\\(.)/g, "$1");
716
+ filepath = filepath.replace(/\\\s/g, " ");
714
717
  if (!existsSync(filepath)) return null;
715
718
  const stats = statSync2(filepath);
716
719
  if (!stats.isFile()) return null;
@@ -737,15 +740,7 @@ var ImageInputDetector = class {
737
740
  */
738
741
  static looksLikeFilePath(input) {
739
742
  const trimmed = input.trim();
740
- if (trimmed.startsWith("/")) {
741
- const hasMultipleSegments = trimmed.indexOf("/", 1) !== -1;
742
- const hasImageExtension = this.SUPPORTED_EXTENSIONS.some((ext) => trimmed.toLowerCase().endsWith(ext));
743
- if (hasMultipleSegments || hasImageExtension) {
744
- return true;
745
- }
746
- return false;
747
- }
748
- if (trimmed.match(/^[a-zA-Z]:\\/)) {
743
+ if (trimmed.startsWith("/") || trimmed.match(/^[a-zA-Z]:\\/)) {
749
744
  return true;
750
745
  }
751
746
  if (trimmed.startsWith("~")) {
@@ -774,16 +769,6 @@ var ImageInputDetector = class {
774
769
  };
775
770
 
776
771
  // src/components/InputPrompt.tsx
777
- function looksLikeFilePath(input) {
778
- const trimmed = input.trim();
779
- if (trimmed.startsWith("/")) {
780
- const hasMultipleSegments = trimmed.indexOf("/", 1) !== -1;
781
- if (hasMultipleSegments) return true;
782
- }
783
- if (trimmed.startsWith("~")) return true;
784
- if (trimmed.match(/^[a-zA-Z]:\\/)) return true;
785
- return false;
786
- }
787
772
  function findAtTrigger(value) {
788
773
  for (let i = value.length - 1; i >= 0; i--) {
789
774
  if (value[i] === "@") {
@@ -827,7 +812,7 @@ function InputPrompt({
827
812
  useEffect(() => {
828
813
  onBashModeChange?.(isBashMode);
829
814
  }, [isBashMode, onBashModeChange]);
830
- const shouldShowCommandAutocomplete = value.startsWith("/") && !disabled && !fileAutocomplete?.active && !looksLikeFilePath(value);
815
+ const shouldShowCommandAutocomplete = value.startsWith("/") && !disabled && !fileAutocomplete?.active;
831
816
  const commandQuery = shouldShowCommandAutocomplete ? value.slice(1) : "";
832
817
  const filteredCommands = useMemo(() => {
833
818
  if (!shouldShowCommandAutocomplete) return [];
@@ -1373,7 +1358,7 @@ function isNameSuffix(value) {
1373
1358
 
1374
1359
  // src/utils/processFileReferences.ts
1375
1360
  var FILE_REFERENCE_REGEX = /(?:^|\s)@([^\s@]+)/g;
1376
- function looksLikeFilePath2(ref) {
1361
+ function looksLikeFilePath(ref) {
1377
1362
  if (ref.includes("/") || ref.includes(path2.sep)) {
1378
1363
  return true;
1379
1364
  }
@@ -1396,7 +1381,7 @@ function extractFileReferences(message) {
1396
1381
  let match;
1397
1382
  while ((match = FILE_REFERENCE_REGEX.exec(message)) !== null) {
1398
1383
  const ref = match[1];
1399
- if (looksLikeFilePath2(ref)) {
1384
+ if (looksLikeFilePath(ref)) {
1400
1385
  references.push(ref);
1401
1386
  }
1402
1387
  }
@@ -3108,21 +3093,6 @@ ${options.context}` : this.getSystemPrompt()
3108
3093
  let finalAnswer = "";
3109
3094
  let reachedMaxIterations = false;
3110
3095
  while (iterations < maxIterations) {
3111
- if (options.signal?.aborted) {
3112
- this.context.logger.info("[ReActAgent] Operation aborted by user");
3113
- const result2 = {
3114
- finalAnswer: "Interrupted",
3115
- steps: this.steps,
3116
- completionInfo: {
3117
- totalTokens: this.totalTokens,
3118
- iterations,
3119
- toolCalls: this.toolCallCount,
3120
- reachedMaxIterations: false
3121
- }
3122
- };
3123
- this.emit("complete", result2);
3124
- return result2;
3125
- }
3126
3096
  iterations++;
3127
3097
  this.context.logger.debug(`[ReActAgent] Starting iteration ${iterations}/${maxIterations}`);
3128
3098
  let iterationComplete = false;
@@ -3136,8 +3106,7 @@ ${options.context}` : this.getSystemPrompt()
3136
3106
  stream: false,
3137
3107
  tools: this.context.tools,
3138
3108
  maxTokens,
3139
- temperature,
3140
- abortSignal: options.signal
3109
+ temperature
3141
3110
  },
3142
3111
  async (texts, completionInfo) => {
3143
3112
  for (const text of texts) {
@@ -3280,9 +3249,6 @@ ${options.context}` : this.getSystemPrompt()
3280
3249
  this.emit("final_answer", finalStep);
3281
3250
  }
3282
3251
  }
3283
- if (options.signal?.aborted && !finalAnswer) {
3284
- finalAnswer = "Interrupted";
3285
- }
3286
3252
  const result = {
3287
3253
  finalAnswer,
3288
3254
  steps: this.steps,
@@ -3390,70 +3356,6 @@ Remember: You are an autonomous AGENT. Act independently and solve problems proa
3390
3356
  }
3391
3357
  };
3392
3358
 
3393
- // src/core/prompts.ts
3394
- var TOOL_GREP_SEARCH = "grep_search";
3395
- var TOOL_GLOB_FILES = "glob_files";
3396
- var TOOL_FILE_READ = "file_read";
3397
- var TOOL_EDIT_LOCAL_FILE = "edit_local_file";
3398
- var TOOL_CREATE_FILE = "create_file";
3399
- var TOOL_BASH_EXECUTE = "bash_execute";
3400
- var TOOL_SUBAGENT_DELEGATE = "subagent_delegate";
3401
- var TOOL_WRITE_TODOS = "write_todos";
3402
- var EXPLORE_SUBAGENT_TYPE = "explore";
3403
- function buildCoreSystemPrompt(contextSection = "") {
3404
- return `You are an autonomous AI assistant with access to tools. Your job is to help users by taking action and solving problems proactively.
3405
-
3406
- CORE BEHAVIOR:
3407
- - Be proactive: Take action instead of asking for permission or clarification
3408
- - Make smart assumptions: If unclear, choose the most reasonable interpretation
3409
- - Use conversation history: Reference previous exchanges to understand context
3410
- - Complete tasks fully: Don't just show what to do - actually do it
3411
-
3412
- FOR SOFTWARE ENGINEERING TASKS:
3413
- When requested to perform tasks like fixing bugs, adding features, refactoring, or explaining code, follow this sequence:
3414
- 1. **Understand:** Think about the user's request and the relevant codebase context. Use '${TOOL_GREP_SEARCH}' and '${TOOL_GLOB_FILES}' search tools extensively (in parallel if independent) to understand file structures, existing code patterns, and conventions. Use '${TOOL_FILE_READ}' to understand context and validate any assumptions you may have. If you need to read multiple files, you should make multiple parallel calls to '${TOOL_FILE_READ}'.
3415
- When the task involves **complex refactoring, codebase exploration or system-wide analysis**, your **first and primary action** must be to delegate to the '${EXPLORE_SUBAGENT_TYPE}' agent using the '${TOOL_SUBAGENT_DELEGATE}' tool. Use it to build a comprehensive understanding of the code, its structure, and dependencies. For **simple, targeted searches** (like finding a specific function name, file path, or variable declaration), you should use '${TOOL_GREP_SEARCH}' or '${TOOL_GLOB_FILES}' directly.
3416
- 2. **Plan:** Build a coherent and grounded (based on the understanding in step 1) plan for how you intend to resolve the user's task. Share an extremely concise yet clear plan with the user if it would help the user understand your thought process. As part of the plan, you should use an iterative development process that includes writing unit tests to verify your changes. Use output logs or debug statements as part of this process to arrive at a solution.
3417
- If '${EXPLORE_SUBAGENT_TYPE}' subagent was used, do not ignore the output of the agent, you must use it as the foundation of your plan. For complex tasks, break them down into smaller, manageable subtasks and use the \`${TOOL_WRITE_TODOS}\` tool to track your progress. Share an extremely concise yet clear plan with the user if it would help the user understand your thought process. As part of the plan, you should use an iterative development process that includes writing unit tests to verify your changes. Use output logs or debug statements as part of this process to arrive at a solution.
3418
- 3. **Implement:** Use the available tools (e.g., '${TOOL_EDIT_LOCAL_FILE}', '${TOOL_CREATE_FILE}', '${TOOL_BASH_EXECUTE}' ...) to act on the plan, strictly adhering to the project's established conventions.
3419
- 4. **Verify (Tests):** If applicable and feasible, verify the changes using the project's testing procedures. Identify the correct test commands and frameworks by examining 'README' files, build/package configuration (e.g., 'package.json'), or existing test execution patterns. NEVER assume standard test commands. When executing test commands, prefer "run once" or "CI" modes to ensure the command terminates after completion.
3420
- 5. **Verify (Standards):** VERY IMPORTANT: After making code changes, execute the project-specific build, linting and type-checking commands (e.g., 'tsc', 'npm run lint', 'ruff check .') that you have identified for this project (or obtained from the user). This ensures code quality and adherence to standards.
3421
- 6. **Finalize:** After all verification passes, consider the task complete. Do not remove or revert any changes or created files (like tests). Await the user's next instruction.
3422
-
3423
- SUBAGENT DELEGATION:
3424
- - You have access to specialized subagents via the ${TOOL_SUBAGENT_DELEGATE} tool
3425
- - Use subagents for focused exploration, planning, or review tasks:
3426
- * explore: Fast read-only codebase search (e.g., "find all auth files", "locate API endpoints")
3427
- * plan: Break down complex tasks into actionable steps
3428
- * review: Analyze code quality and identify issues
3429
- - Subagents keep the main conversation clean and run faster with optimized models
3430
- - Delegate when you need to search extensively or analyze code structure
3431
-
3432
- FOR GENERAL TASKS:
3433
- - Use available tools to get information (weather, web search, calculations, etc.)
3434
- - When user asks follow-up questions, use conversation context to understand what they're referring to
3435
- - If user asks "how about X?" after a previous question, apply the same question type to X
3436
-
3437
- ## Shell tool output token efficiency:
3438
- IT IS CRITICAL TO FOLLOW THESE GUIDELINES TO AVOID EXCESSIVE TOKEN CONSUMPTION.
3439
-
3440
- - Always prefer command flags that reduce output verbosity when using '${TOOL_BASH_EXECUTE}'.
3441
- - Aim to minimize tool output tokens while still capturing necessary information.
3442
- - If a command is expected to produce a lot of output, use quiet or silent flags where available and appropriate.
3443
- - Always consider the trade-off between output verbosity and the need for information. If a command's full output is essential for understanding the result, avoid overly aggressive quieting that might obscure important details.
3444
- - If a command does not have quiet/silent flags or for commands with potentially long output that may not be useful, redirect stdout and stderr to temp files in the project's temporary directory. For example: 'command > <temp_dir>/out.log 2> <temp_dir>/err.log'.
3445
- - After the command runs, inspect the temp files (e.g. '<temp_dir>/out.log' and '<temp_dir>/err.log') using commands like 'grep', 'tail', 'head', ... (or platform equivalents). Remove the temp files when done.
3446
-
3447
- EXAMPLES:
3448
- - "what should I wear in Texas?" \u2192 use weather tool for Texas
3449
- - "how about Japan?" \u2192 use weather tool for Japan (applying same question from context)
3450
- - "enhance README" \u2192 ${TOOL_FILE_READ} \u2192 generate \u2192 ${TOOL_EDIT_LOCAL_FILE}
3451
- - "what packages installed?" \u2192 ${TOOL_GLOB_FILES} "**/package.json" \u2192 ${TOOL_FILE_READ}
3452
- - "find all components using React hooks" \u2192 ${TOOL_SUBAGENT_DELEGATE}(task="find all components using React hooks", type="explore")
3453
-
3454
- Remember: Use context from previous messages to understand follow-up questions.${contextSection}`;
3455
- }
3456
-
3457
3359
  // ../../b4m-core/packages/services/dist/src/referService/generateCodes.js
3458
3360
  import { randomBytes } from "crypto";
3459
3361
  import range from "lodash/range.js";
@@ -8805,80 +8707,98 @@ var createFileTool = {
8805
8707
  };
8806
8708
 
8807
8709
  // ../../b4m-core/packages/services/dist/src/llm/tools/implementation/globFiles/index.js
8808
- import { glob } from "glob";
8809
- import { stat } from "fs/promises";
8710
+ import { readdir } from "fs/promises";
8711
+ import { statSync as statSync5 } from "fs";
8810
8712
  import path9 from "path";
8811
- var DEFAULT_IGNORE_PATTERNS2 = [
8812
- "**/node_modules/**",
8813
- "**/.git/**",
8814
- "**/dist/**",
8815
- "**/build/**",
8816
- "**/.next/**",
8817
- "**/coverage/**",
8818
- "**/.turbo/**",
8819
- "**/.sst/**",
8820
- "**/*.min.js",
8821
- "**/*.min.css"
8822
- ];
8823
- async function findFiles(params) {
8824
- const { pattern, dir_path, case_sensitive = true, respect_git_ignore = true } = params;
8713
+ function matchGlob(filePath, pattern) {
8714
+ let regexPattern = pattern.replace(/\./g, "\\.").replace(/\*\*/g, "{{GLOBSTAR}}").replace(/\*/g, "[^/]*").replace(/\?/g, ".").replace(/\{([^}]+)\}/g, (_, options) => `(${options.split(",").join("|")})`).replace(/\[([^\]]+)\]/g, "[$1]");
8715
+ regexPattern = regexPattern.replace(/\{\{GLOBSTAR\}\}\//g, "(.*/)?").replace(/\/\{\{GLOBSTAR\}\}/g, "(/.*)?").replace(/\{\{GLOBSTAR\}\}/g, ".*");
8716
+ const regex = new RegExp(`^${regexPattern}$`);
8717
+ return regex.test(filePath);
8718
+ }
8719
+ async function walkDir(dir, pattern, includeHidden, maxResults, basePath = "") {
8720
+ const matches = [];
8721
+ try {
8722
+ const entries = await readdir(dir, { withFileTypes: true });
8723
+ for (const entry of entries) {
8724
+ if (matches.length >= maxResults) {
8725
+ break;
8726
+ }
8727
+ if (!includeHidden && entry.name.startsWith(".")) {
8728
+ continue;
8729
+ }
8730
+ const relativePath = basePath ? path9.join(basePath, entry.name) : entry.name;
8731
+ const fullPath = path9.join(dir, entry.name);
8732
+ if (matchGlob(relativePath, pattern)) {
8733
+ matches.push(relativePath);
8734
+ }
8735
+ if (entry.isDirectory() && (pattern.includes("**") || pattern.includes("/"))) {
8736
+ const subMatches = await walkDir(fullPath, pattern, includeHidden, maxResults - matches.length, relativePath);
8737
+ matches.push(...subMatches);
8738
+ }
8739
+ }
8740
+ } catch (error) {
8741
+ }
8742
+ return matches;
8743
+ }
8744
+ async function listFiles(params) {
8745
+ const { pattern, cwd: relativeCwd, includeHidden = false, maxResults = 1e3 } = params;
8825
8746
  const baseCwd = process.cwd();
8826
- const targetDir = dir_path ? path9.resolve(baseCwd, path9.normalize(dir_path)) : baseCwd;
8827
- if (!targetDir.startsWith(baseCwd)) {
8828
- throw new Error(`Access denied: Cannot search outside of current working directory`);
8829
- }
8830
- const ignorePatterns = respect_git_ignore ? DEFAULT_IGNORE_PATTERNS2 : [];
8831
- const matches = await glob(pattern, {
8832
- cwd: targetDir,
8833
- dot: false,
8834
- // Don't match hidden files by default
8835
- ignore: ignorePatterns,
8836
- absolute: true,
8837
- nodir: true,
8838
- // Only return files, not directories
8839
- nocase: !case_sensitive,
8840
- // Case-insensitive if requested
8841
- maxDepth: 20
8842
- // Reasonable depth limit
8843
- });
8747
+ const targetCwd = relativeCwd ? path9.resolve(baseCwd, path9.normalize(relativeCwd)) : baseCwd;
8748
+ if (!targetCwd.startsWith(baseCwd)) {
8749
+ throw new Error(`Access denied: Cannot list files outside of current working directory`);
8750
+ }
8751
+ const matches = await walkDir(targetCwd, pattern, includeHidden, maxResults);
8844
8752
  if (matches.length === 0) {
8845
- return `No files found matching pattern: ${pattern}${dir_path ? ` in ${dir_path}` : ""}`;
8753
+ return `No files found matching pattern: ${pattern}`;
8846
8754
  }
8847
- const filesWithStats = [];
8848
- for (const filePath of matches) {
8755
+ const filesInfo = [];
8756
+ for (const match of matches) {
8849
8757
  try {
8850
- const stats = await stat(filePath);
8851
- filesWithStats.push({
8852
- path: filePath,
8853
- mtime: stats.mtimeMs
8758
+ const fullPath = path9.join(targetCwd, match);
8759
+ const stats = statSync5(fullPath);
8760
+ filesInfo.push({
8761
+ path: match,
8762
+ size: stats.size,
8763
+ isDirectory: stats.isDirectory(),
8764
+ modified: stats.mtime.toISOString()
8854
8765
  });
8855
- } catch {
8766
+ } catch (error) {
8856
8767
  continue;
8857
8768
  }
8858
8769
  }
8859
- filesWithStats.sort((a, b) => b.mtime - a.mtime);
8860
- const MAX_RESULTS = 500;
8861
- const truncated = filesWithStats.length > MAX_RESULTS;
8862
- const results = truncated ? filesWithStats.slice(0, MAX_RESULTS) : filesWithStats;
8863
- const summary = `Found ${filesWithStats.length} file(s)${truncated ? ` (showing first ${MAX_RESULTS})` : ""} matching: ${pattern}`;
8864
- const dirInfo = dir_path ? `
8865
- Directory: ${dir_path}` : "";
8866
- const filesList = results.map((file) => path9.relative(baseCwd, file.path)).join("\n");
8867
- return `${summary}${dirInfo}
8868
-
8770
+ const truncated = matches.length >= maxResults;
8771
+ const summary = `Found ${filesInfo.length} file(s)${truncated ? ` (truncated to ${maxResults})` : ""} matching: ${pattern}
8772
+ `;
8773
+ const cwdInfo = relativeCwd ? `Directory: ${relativeCwd}
8774
+ ` : "";
8775
+ const filesList = filesInfo.map((file) => {
8776
+ const typeIcon = file.isDirectory ? "\u{1F4C1}" : "\u{1F4C4}";
8777
+ const sizeStr = file.isDirectory ? "" : ` (${formatBytes(file.size)})`;
8778
+ return `${typeIcon} ${file.path}${sizeStr}`;
8779
+ }).join("\n");
8780
+ return `${summary}${cwdInfo}
8869
8781
  ${filesList}`;
8870
8782
  }
8783
+ function formatBytes(bytes) {
8784
+ if (bytes === 0)
8785
+ return "0 B";
8786
+ const k = 1024;
8787
+ const sizes = ["B", "KB", "MB", "GB"];
8788
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
8789
+ return `${(bytes / Math.pow(k, i)).toFixed(1)} ${sizes[i]}`;
8790
+ }
8871
8791
  var globFilesTool = {
8872
8792
  name: "glob_files",
8873
8793
  implementation: (context) => ({
8874
8794
  toolFn: async (value) => {
8875
8795
  const params = value;
8876
- context.logger.info("\u{1F50D} GlobFiles: Finding files", {
8796
+ context.logger.info("\u{1F50D} GlobFiles: Listing files", {
8877
8797
  pattern: params.pattern,
8878
- dir_path: params.dir_path || "."
8798
+ cwd: params.cwd || "."
8879
8799
  });
8880
8800
  try {
8881
- const result = await findFiles(params);
8801
+ const result = await listFiles(params);
8882
8802
  context.logger.info("\u2705 GlobFiles: Success");
8883
8803
  return result;
8884
8804
  } catch (error) {
@@ -8888,25 +8808,25 @@ var globFilesTool = {
8888
8808
  },
8889
8809
  toolSchema: {
8890
8810
  name: "glob_files",
8891
- description: "Efficiently finds files matching specific glob patterns (e.g., `src/**/*.ts`, `**/*.md`), returning absolute paths sorted by modification time (newest first). Use this to locate files by name or extension when you need to discover or explore files in a project.",
8811
+ description: "List files and directories matching a glob pattern. Supports wildcards like *, **, ?, and character ranges. Restricted to current working directory for security.",
8892
8812
  parameters: {
8893
8813
  type: "object",
8894
8814
  properties: {
8895
8815
  pattern: {
8896
8816
  type: "string",
8897
- description: 'The glob pattern to match against file paths. Supports wildcards (*, **), character ranges ([abc]), and brace expansion ({ts,tsx}). Examples: "*.ts" for TypeScript files in current dir, "src/**/*.tsx" for all TSX files in src tree, "**/*.{js,ts}" for all JS/TS files.'
8817
+ description: 'Glob pattern to match files (e.g., "*.ts", "src/**/*.tsx", "test/*.{js,ts}"). Use ** for recursive directory search.'
8898
8818
  },
8899
- dir_path: {
8819
+ cwd: {
8900
8820
  type: "string",
8901
- description: "Optional: The absolute path to the directory to search in. If not specified, uses the current working directory. Must be within the current working directory."
8821
+ description: "Directory to search in, relative to current working directory (optional). Defaults to current directory."
8902
8822
  },
8903
- case_sensitive: {
8823
+ includeHidden: {
8904
8824
  type: "boolean",
8905
- description: "Optional: Whether the pattern matching should be case-sensitive. Defaults to true. Set to false for case-insensitive matching on case-sensitive file systems."
8825
+ description: "Include hidden files and directories (starting with .). Defaults to false."
8906
8826
  },
8907
- respect_git_ignore: {
8908
- type: "boolean",
8909
- description: "Optional: Whether to respect common ignore patterns (node_modules, .git, dist, build, etc.). Defaults to true. Set to false to include all files."
8827
+ maxResults: {
8828
+ type: "number",
8829
+ description: "Maximum number of results to return (default: 1000). Prevents overwhelming output."
8910
8830
  }
8911
8831
  },
8912
8832
  required: ["pattern"]
@@ -8916,144 +8836,158 @@ var globFilesTool = {
8916
8836
  };
8917
8837
 
8918
8838
  // ../../b4m-core/packages/services/dist/src/llm/tools/implementation/grepSearch/index.js
8919
- import { globStream } from "glob";
8920
- import { readFile, stat as stat2 } from "fs/promises";
8839
+ import { readdir as readdir2 } from "fs/promises";
8840
+ import { readFileSync as readFileSync3, statSync as statSync6 } from "fs";
8921
8841
  import path10 from "path";
8922
8842
  var MAX_FILE_SIZE3 = 10 * 1024 * 1024;
8923
- var DEFAULT_IGNORE_PATTERNS3 = [
8924
- "**/node_modules/**",
8925
- "**/.git/**",
8926
- "**/dist/**",
8927
- "**/build/**",
8928
- "**/.next/**",
8929
- "**/coverage/**",
8930
- "**/*.min.js",
8931
- "**/*.min.css",
8932
- "**/package-lock.json",
8933
- "**/pnpm-lock.yaml",
8934
- "**/yarn.lock"
8935
- ];
8936
- async function isBinaryFile2(filePath) {
8843
+ function matchGlob2(filePath, pattern) {
8844
+ const regexPattern = pattern.replace(/\./g, "\\.").replace(/\*\*/g, "{{GLOBSTAR}}").replace(/\*/g, "[^/]*").replace(/\{\{GLOBSTAR\}\}/g, ".*").replace(/\?/g, ".").replace(/\{([^}]+)\}/g, (_, options) => `(${options.split(",").join("|")})`).replace(/\[([^\]]+)\]/g, "[$1]");
8845
+ const regex = new RegExp(`^${regexPattern}$`);
8846
+ return regex.test(filePath);
8847
+ }
8848
+ async function walkDir2(dir, pattern, maxResults, basePath = "") {
8849
+ const matches = [];
8937
8850
  try {
8938
- const { openSync, readSync, closeSync } = await import("fs");
8939
- const buffer = Buffer.alloc(8192);
8940
- const fd = openSync(filePath, "r");
8941
- const bytesRead = readSync(fd, buffer, 0, 8192, 0);
8942
- closeSync(fd);
8943
- const chunk = buffer.slice(0, bytesRead);
8944
- return chunk.includes(0);
8945
- } catch {
8946
- return true;
8851
+ const entries = await readdir2(dir, { withFileTypes: true });
8852
+ for (const entry of entries) {
8853
+ if (matches.length >= maxResults) {
8854
+ break;
8855
+ }
8856
+ if (entry.name.startsWith(".")) {
8857
+ continue;
8858
+ }
8859
+ const relativePath = basePath ? path10.join(basePath, entry.name) : entry.name;
8860
+ const fullPath = path10.join(dir, entry.name);
8861
+ if (matchGlob2(relativePath, pattern)) {
8862
+ matches.push(relativePath);
8863
+ }
8864
+ if (entry.isDirectory() && (pattern.includes("**") || pattern.includes("/"))) {
8865
+ const subMatches = await walkDir2(fullPath, pattern, maxResults - matches.length, relativePath);
8866
+ matches.push(...subMatches);
8867
+ }
8868
+ }
8869
+ } catch (error) {
8947
8870
  }
8948
- }
8949
- function isPathWithinWorkspace(targetPath, baseCwd) {
8950
- const resolvedTarget = path10.resolve(targetPath);
8951
- const resolvedBase = path10.resolve(baseCwd);
8952
- return resolvedTarget.startsWith(resolvedBase);
8871
+ return matches;
8953
8872
  }
8954
8873
  async function searchFiles2(params) {
8955
- const { pattern, dir_path, include } = params;
8874
+ const { pattern, filePattern = "**/*", cwd: relativeCwd, caseSensitive = false, maxResults = 100, contextLines = 0 } = params;
8956
8875
  const baseCwd = process.cwd();
8957
- const targetDir = dir_path ? path10.resolve(baseCwd, dir_path) : baseCwd;
8958
- if (!isPathWithinWorkspace(targetDir, baseCwd)) {
8959
- throw new Error(`Path validation failed: "${dir_path}" resolves outside the allowed workspace directory`);
8960
- }
8961
- try {
8962
- const stats = await stat2(targetDir);
8963
- if (!stats.isDirectory()) {
8964
- throw new Error(`Path is not a directory: ${dir_path}`);
8965
- }
8966
- } catch (error) {
8967
- if (error.code === "ENOENT") {
8968
- throw new Error(`Path does not exist: ${dir_path}`);
8969
- }
8970
- throw error;
8876
+ const targetCwd = relativeCwd ? path10.resolve(baseCwd, path10.normalize(relativeCwd)) : baseCwd;
8877
+ if (!targetCwd.startsWith(baseCwd)) {
8878
+ throw new Error(`Access denied: Cannot search files outside of current working directory`);
8971
8879
  }
8972
8880
  let searchRegex;
8973
8881
  try {
8974
- searchRegex = new RegExp(pattern, "i");
8882
+ const flags = caseSensitive ? "g" : "gi";
8883
+ searchRegex = new RegExp(pattern, flags);
8975
8884
  } catch (error) {
8976
8885
  throw new Error(`Invalid regex pattern: ${pattern}`);
8977
8886
  }
8978
- const globPattern = include || "**/*";
8979
- const filesStream = globStream(globPattern, {
8980
- cwd: targetDir,
8981
- dot: false,
8982
- // Skip hidden files
8983
- ignore: DEFAULT_IGNORE_PATTERNS3,
8984
- absolute: true,
8985
- nodir: true
8986
- // Only match files, not directories
8987
- });
8988
- const allMatches = [];
8989
- let filesSearched = 0;
8990
- const maxMatches = 500;
8991
- for await (const filePath of filesStream) {
8992
- if (allMatches.length >= maxMatches) {
8993
- break;
8994
- }
8995
- const fileAbsPath = filePath;
8887
+ const filesToSearch = await walkDir2(targetCwd, filePattern, 1e4);
8888
+ const filteredFiles = [];
8889
+ for (const match of filesToSearch) {
8890
+ const fullPath = path10.join(targetCwd, match);
8996
8891
  try {
8997
- const stats = await stat2(fileAbsPath);
8998
- if (stats.size > MAX_FILE_SIZE3) {
8892
+ const stats = statSync6(fullPath);
8893
+ if (stats.isDirectory() || stats.size > MAX_FILE_SIZE3) {
8999
8894
  continue;
9000
8895
  }
9001
- if (await isBinaryFile2(fileAbsPath)) {
8896
+ if (isBinaryFile2(fullPath)) {
9002
8897
  continue;
9003
8898
  }
9004
- filesSearched++;
9005
- const content = await readFile(fileAbsPath, "utf8");
9006
- const lines = content.split(/\r?\n/);
9007
- lines.forEach((line, index) => {
9008
- if (allMatches.length < maxMatches && searchRegex.test(line)) {
9009
- allMatches.push({
9010
- filePath: path10.relative(targetDir, fileAbsPath) || path10.basename(fileAbsPath),
9011
- lineNumber: index + 1,
9012
- line
9013
- });
8899
+ filteredFiles.push(match);
8900
+ } catch {
8901
+ continue;
8902
+ }
8903
+ }
8904
+ if (filteredFiles.length === 0) {
8905
+ return `No files found matching pattern: ${filePattern}`;
8906
+ }
8907
+ const matches = [];
8908
+ let filesSearched = 0;
8909
+ for (const file of filteredFiles) {
8910
+ if (matches.length >= maxResults) {
8911
+ break;
8912
+ }
8913
+ filesSearched++;
8914
+ const fullPath = path10.join(targetCwd, file);
8915
+ try {
8916
+ const content = readFileSync3(fullPath, "utf-8");
8917
+ const lines = content.split("\n");
8918
+ for (let i = 0; i < lines.length; i++) {
8919
+ if (matches.length >= maxResults) {
8920
+ break;
9014
8921
  }
9015
- });
9016
- } catch (readError) {
9017
- const errCode = readError.code;
9018
- if (errCode !== "ENOENT" && errCode !== "EACCES") {
9019
- console.debug(`Could not read ${fileAbsPath}: ${readError.message}`);
8922
+ const line = lines[i];
8923
+ if (searchRegex.test(line)) {
8924
+ const match = {
8925
+ file,
8926
+ line: i + 1,
8927
+ // 1-indexed line numbers
8928
+ content: line.trim()
8929
+ };
8930
+ if (contextLines > 0) {
8931
+ const before = [];
8932
+ const after = [];
8933
+ for (let j = Math.max(0, i - contextLines); j < i; j++) {
8934
+ before.push(lines[j]);
8935
+ }
8936
+ for (let j = i + 1; j <= Math.min(lines.length - 1, i + contextLines); j++) {
8937
+ after.push(lines[j]);
8938
+ }
8939
+ match.context = { before, after };
8940
+ }
8941
+ matches.push(match);
8942
+ }
8943
+ searchRegex.lastIndex = 0;
9020
8944
  }
8945
+ } catch {
8946
+ continue;
9021
8947
  }
9022
8948
  }
9023
- const searchDirDisplay = dir_path || ".";
9024
- const filterInfo = include ? ` (filter: "${include}")` : "";
9025
- if (allMatches.length === 0) {
9026
- return `No matches found for pattern "${pattern}" in "${searchDirDisplay}"${filterInfo}.
9027
- Searched ${filesSearched} file(s).`;
8949
+ if (matches.length === 0) {
8950
+ return `No matches found for pattern: ${pattern}
8951
+ Searched ${filesSearched} file(s)`;
9028
8952
  }
9029
- const matchesByFile = allMatches.reduce((acc, match) => {
9030
- if (!acc[match.filePath]) {
9031
- acc[match.filePath] = [];
9032
- }
9033
- acc[match.filePath].push(match);
9034
- acc[match.filePath].sort((a, b) => a.lineNumber - b.lineNumber);
9035
- return acc;
9036
- }, {});
9037
- const matchCount = allMatches.length;
9038
- const matchTerm = matchCount === 1 ? "match" : "matches";
9039
- const truncated = matchCount >= maxMatches;
9040
- let result = `Found ${matchCount} ${matchTerm}${truncated ? " (truncated)" : ""} for pattern "${pattern}" in "${searchDirDisplay}"${filterInfo}:
8953
+ const truncated = matches.length >= maxResults;
8954
+ const summary = `Found ${matches.length} match(es)${truncated ? ` (truncated to ${maxResults})` : ""} in ${filesSearched} file(s)
9041
8955
  `;
9042
- result += `Searched ${filesSearched} file(s)
9043
- ---
8956
+ const patternInfo = `Pattern: ${pattern}${caseSensitive ? "" : " (case-insensitive)"}
9044
8957
  `;
9045
- for (const filePath in matchesByFile) {
9046
- result += `File: ${filePath}
9047
- `;
9048
- matchesByFile[filePath].forEach((match) => {
9049
- const trimmedLine = match.line.trim();
9050
- const displayLine = trimmedLine.length > 200 ? trimmedLine.slice(0, 200) + "..." : trimmedLine;
9051
- result += `L${match.lineNumber}: ${displayLine}
9052
- `;
9053
- });
9054
- result += "---\n";
8958
+ const cwdInfo = relativeCwd ? `Directory: ${relativeCwd}
8959
+ ` : "";
8960
+ const matchesList = matches.map((match) => {
8961
+ let result = `
8962
+ \u{1F4C4} ${match.file}:${match.line}
8963
+ ${match.content}`;
8964
+ if (match.context) {
8965
+ if (match.context.before.length > 0) {
8966
+ result = `${result}
8967
+ Context before:
8968
+ ${match.context.before.map((l) => ` ${l}`).join("\n")}`;
8969
+ }
8970
+ if (match.context.after.length > 0) {
8971
+ result = `${result}
8972
+ Context after:
8973
+ ${match.context.after.map((l) => ` ${l}`).join("\n")}`;
8974
+ }
8975
+ }
8976
+ return result;
8977
+ }).join("\n");
8978
+ return `${summary}${patternInfo}${cwdInfo}${matchesList}`;
8979
+ }
8980
+ function isBinaryFile2(filePath) {
8981
+ try {
8982
+ const buffer = Buffer.alloc(8192);
8983
+ const fd = __require("fs").openSync(filePath, "r");
8984
+ const bytesRead = __require("fs").readSync(fd, buffer, 0, 8192, 0);
8985
+ __require("fs").closeSync(fd);
8986
+ const chunk = buffer.slice(0, bytesRead);
8987
+ return chunk.includes(0);
8988
+ } catch {
8989
+ return true;
9055
8990
  }
9056
- return result.trim();
9057
8991
  }
9058
8992
  var grepSearchTool = {
9059
8993
  name: "grep_search",
@@ -9062,8 +8996,8 @@ var grepSearchTool = {
9062
8996
  const params = value;
9063
8997
  context.logger.info("\u{1F50D} GrepSearch: Searching files", {
9064
8998
  pattern: params.pattern,
9065
- dir_path: params.dir_path || ".",
9066
- include: params.include || "**/*"
8999
+ filePattern: params.filePattern || "**/*",
9000
+ cwd: params.cwd || "."
9067
9001
  });
9068
9002
  try {
9069
9003
  const result = await searchFiles2(params);
@@ -9076,21 +9010,33 @@ var grepSearchTool = {
9076
9010
  },
9077
9011
  toolSchema: {
9078
9012
  name: "grep_search",
9079
- description: "Searches for a regular expression pattern within the content of files in a specified directory (or current working directory). Can filter files by a glob pattern. Returns the lines containing matches, along with their file paths and line numbers.",
9013
+ description: "Search for a regex pattern in file contents. Similar to grep command. Searches text files only, excluding binary files. Restricted to current working directory for security.",
9080
9014
  parameters: {
9081
9015
  type: "object",
9082
9016
  properties: {
9083
9017
  pattern: {
9084
9018
  type: "string",
9085
- description: "The regular expression (regex) pattern to search for within file contents (e.g., 'function\\s+myFunction', 'import\\s+\\{.*\\}\\s+from\\s+.*')."
9019
+ description: "Regular expression pattern to search for in file contents"
9086
9020
  },
9087
- dir_path: {
9021
+ filePattern: {
9088
9022
  type: "string",
9089
- description: "Optional: The absolute path to the directory to search within. If omitted, searches the current working directory."
9023
+ description: 'Glob pattern to filter which files to search (optional, default: "**/*"). Example: "src/**/*.ts" to search only TypeScript files in src directory.'
9090
9024
  },
9091
- include: {
9025
+ cwd: {
9092
9026
  type: "string",
9093
- description: "Optional: A glob pattern to filter which files are searched (e.g., '*.js', '*.{ts,tsx}', 'src/**'). If omitted, searches all files (respecting potential global ignores)."
9027
+ description: "Directory to search in, relative to current working directory (optional). Defaults to current directory."
9028
+ },
9029
+ caseSensitive: {
9030
+ type: "boolean",
9031
+ description: "Whether the search should be case-sensitive (default: false)"
9032
+ },
9033
+ maxResults: {
9034
+ type: "number",
9035
+ description: "Maximum number of matches to return (default: 100). Prevents overwhelming output."
9036
+ },
9037
+ contextLines: {
9038
+ type: "number",
9039
+ description: "Number of context lines to show before and after each match (default: 0). Similar to grep -C option."
9094
9040
  }
9095
9041
  },
9096
9042
  required: ["pattern"]
@@ -9101,7 +9047,7 @@ var grepSearchTool = {
9101
9047
 
9102
9048
  // ../../b4m-core/packages/services/dist/src/llm/tools/implementation/deleteFile/index.js
9103
9049
  import { promises as fs10 } from "fs";
9104
- import { existsSync as existsSync6, statSync as statSync5 } from "fs";
9050
+ import { existsSync as existsSync6, statSync as statSync7 } from "fs";
9105
9051
  import path11 from "path";
9106
9052
  async function deleteFile(params) {
9107
9053
  const { path: filePath, recursive = false } = params;
@@ -9114,7 +9060,7 @@ async function deleteFile(params) {
9114
9060
  if (!existsSync6(resolvedPath)) {
9115
9061
  throw new Error(`File or directory not found: ${filePath}`);
9116
9062
  }
9117
- const stats = statSync5(resolvedPath);
9063
+ const stats = statSync7(resolvedPath);
9118
9064
  const isDirectory = stats.isDirectory();
9119
9065
  const size = stats.size;
9120
9066
  if (isDirectory && !recursive) {
@@ -9135,7 +9081,7 @@ var deleteFileTool = {
9135
9081
  toolFn: async (value) => {
9136
9082
  const params = value;
9137
9083
  const resolvedPath = path11.resolve(process.cwd(), path11.normalize(params.path));
9138
- const isDirectory = existsSync6(resolvedPath) && statSync5(resolvedPath).isDirectory();
9084
+ const isDirectory = existsSync6(resolvedPath) && statSync7(resolvedPath).isDirectory();
9139
9085
  context.logger.info(`\u{1F5D1}\uFE0F DeleteFile: Deleting ${isDirectory ? "directory" : "file"}`, {
9140
9086
  path: params.path,
9141
9087
  recursive: params.recursive
@@ -9911,7 +9857,7 @@ var ToolErrorType;
9911
9857
 
9912
9858
  // src/utils/diffPreview.ts
9913
9859
  import * as Diff from "diff";
9914
- import { readFile as readFile2 } from "fs/promises";
9860
+ import { readFile } from "fs/promises";
9915
9861
  import { existsSync as existsSync8 } from "fs";
9916
9862
  async function generateFileDiffPreview(args) {
9917
9863
  try {
@@ -9926,7 +9872,7 @@ ${preview}${hasMore ? `
9926
9872
 
9927
9873
  ... (${lines2.length - 20} more lines)` : ""}`;
9928
9874
  }
9929
- const currentContent = await readFile2(args.path, "utf-8");
9875
+ const currentContent = await readFile(args.path, "utf-8");
9930
9876
  const patch = Diff.createPatch(
9931
9877
  args.path,
9932
9878
  currentContent,
@@ -11302,10 +11248,6 @@ var ServerLlmBackend = class {
11302
11248
  */
11303
11249
  async complete(model, messages, options, callback) {
11304
11250
  logger.debug(`[ServerLlmBackend] Starting complete() with model: ${model}`);
11305
- if (options.abortSignal?.aborted) {
11306
- logger.debug("[ServerLlmBackend] Request aborted before start");
11307
- return;
11308
- }
11309
11251
  return new Promise(async (resolve3, reject) => {
11310
11252
  try {
11311
11253
  logger.debug("[ServerLlmBackend] Making streaming request...");
@@ -11406,25 +11348,7 @@ var ServerLlmBackend = class {
11406
11348
  }
11407
11349
  }
11408
11350
  });
11409
- if (options.abortSignal) {
11410
- const abortHandler = () => {
11411
- logger.debug("[ServerLlmBackend] Abort signal received, destroying stream");
11412
- response.data.destroy();
11413
- resolve3();
11414
- };
11415
- if (options.abortSignal.aborted) {
11416
- abortHandler();
11417
- return;
11418
- }
11419
- options.abortSignal.addEventListener("abort", abortHandler, { once: true });
11420
- response.data.on("close", () => {
11421
- options.abortSignal?.removeEventListener("abort", abortHandler);
11422
- });
11423
- }
11424
11351
  response.data.on("data", (chunk) => {
11425
- if (options.abortSignal?.aborted) {
11426
- return;
11427
- }
11428
11352
  parser.feed(chunk.toString());
11429
11353
  });
11430
11354
  response.data.on("end", () => {
@@ -11436,23 +11360,9 @@ var ServerLlmBackend = class {
11436
11360
  }
11437
11361
  });
11438
11362
  response.data.on("error", (error) => {
11439
- if (options.abortSignal?.aborted) {
11440
- resolve3();
11441
- return;
11442
- }
11443
11363
  reject(error);
11444
11364
  });
11445
11365
  } catch (error) {
11446
- if (options.abortSignal?.aborted) {
11447
- logger.debug("[ServerLlmBackend] Request was aborted, resolving gracefully");
11448
- resolve3();
11449
- return;
11450
- }
11451
- if (isAxiosError(error) && error.code === "ERR_CANCELED") {
11452
- logger.debug("[ServerLlmBackend] Request was canceled, resolving gracefully");
11453
- resolve3();
11454
- return;
11455
- }
11456
11366
  logger.error("LLM completion failed", error);
11457
11367
  if (isAxiosError(error)) {
11458
11368
  logger.debug(
@@ -11603,10 +11513,8 @@ var ServerLlmBackend = class {
11603
11513
  logger.debug(` Body: ${logger.formatBytes(bodySize)}`);
11604
11514
  logger.debug(` Preview: ${bodyStr.substring(0, 200)}`);
11605
11515
  const response = await axiosInstance.post(this.completionsEndpoint, requestBody, {
11606
- responseType: "stream",
11516
+ responseType: "stream"
11607
11517
  // Auth header is automatically injected by ApiClient interceptor
11608
- // Pass abort signal to cancel request if user presses ESC
11609
- signal: options.abortSignal
11610
11518
  });
11611
11519
  logger.debug(`\u2190 ${response.status} ${response.statusText}`);
11612
11520
  return response;
@@ -11750,7 +11658,7 @@ import { isAxiosError as isAxiosError2 } from "axios";
11750
11658
  // package.json
11751
11659
  var package_default = {
11752
11660
  name: "@bike4mind/cli",
11753
- version: "0.2.12-cli-todo-list.17408+244ee96b6",
11661
+ version: "0.2.12-feat-secops-secrets.17399+ae2b8a0b6",
11754
11662
  type: "module",
11755
11663
  description: "Interactive CLI tool for Bike4Mind with ReAct agents",
11756
11664
  license: "UNLICENSED",
@@ -11787,8 +11695,7 @@ var package_default = {
11787
11695
  test: "vitest run",
11788
11696
  "test:watch": "vitest",
11789
11697
  start: "node dist/index.js",
11790
- prepublishOnly: "pnpm build",
11791
- postinstall: `node -e "try { require('better-sqlite3') } catch(e) { if(e.message.includes('bindings')) { console.log('\\n\u26A0\uFE0F Rebuilding better-sqlite3 native bindings...'); require('child_process').execSync('pnpm rebuild better-sqlite3', {stdio:'inherit'}) } }"`
11698
+ prepublishOnly: "pnpm build"
11792
11699
  },
11793
11700
  dependencies: {
11794
11701
  "@anthropic-ai/sdk": "^0.22.0",
@@ -11821,7 +11728,6 @@ var package_default = {
11821
11728
  "eventsource-parser": "^3.0.6",
11822
11729
  "file-type": "^18.7.0",
11823
11730
  "fuse.js": "^7.1.0",
11824
- glob: "^13.0.0",
11825
11731
  "gray-matter": "^4.0.3",
11826
11732
  ink: "^6.5.1",
11827
11733
  "ink-select-input": "^6.2.0",
@@ -11856,10 +11762,10 @@ var package_default = {
11856
11762
  },
11857
11763
  devDependencies: {
11858
11764
  "@bike4mind/agents": "0.1.0",
11859
- "@bike4mind/common": "2.41.1-cli-todo-list.17408+244ee96b6",
11860
- "@bike4mind/mcp": "1.21.1-cli-todo-list.17408+244ee96b6",
11861
- "@bike4mind/services": "2.36.1-cli-todo-list.17408+244ee96b6",
11862
- "@bike4mind/utils": "2.1.6-cli-todo-list.17408+244ee96b6",
11765
+ "@bike4mind/common": "2.41.1-feat-secops-secrets.17399+ae2b8a0b6",
11766
+ "@bike4mind/mcp": "1.21.1-feat-secops-secrets.17399+ae2b8a0b6",
11767
+ "@bike4mind/services": "2.36.1-feat-secops-secrets.17399+ae2b8a0b6",
11768
+ "@bike4mind/utils": "2.1.6-feat-secops-secrets.17399+ae2b8a0b6",
11863
11769
  "@types/better-sqlite3": "^7.6.13",
11864
11770
  "@types/diff": "^5.0.9",
11865
11771
  "@types/jsonwebtoken": "^9.0.4",
@@ -11872,7 +11778,7 @@ var package_default = {
11872
11778
  typescript: "^5.9.3",
11873
11779
  vitest: "^3.2.4"
11874
11780
  },
11875
- gitHead: "244ee96b6f743aeff0513fc84f573050b624d4e7"
11781
+ gitHead: "ae2b8a0b668497b8b3d94c6e055ce1565fde45b3"
11876
11782
  };
11877
11783
 
11878
11784
  // src/config/constants.ts
@@ -12228,131 +12134,6 @@ function createSubagentDelegateTool(orchestrator, parentSessionId) {
12228
12134
  };
12229
12135
  }
12230
12136
 
12231
- // src/tools/writeTodosTool.ts
12232
- var VALID_STATUSES = ["pending", "in_progress", "completed", "cancelled"];
12233
- function validateTodos(todos) {
12234
- if (!Array.isArray(todos)) {
12235
- throw new Error("write_todos: todos must be an array");
12236
- }
12237
- if (todos.length === 0) {
12238
- throw new Error("write_todos: todos array cannot be empty");
12239
- }
12240
- let inProgressCount = 0;
12241
- const validatedTodos = todos.map((item, index) => {
12242
- if (!item || typeof item !== "object") {
12243
- throw new Error(`write_todos: item at index ${index} must be an object`);
12244
- }
12245
- const { description, status } = item;
12246
- if (typeof description !== "string" || description.trim() === "") {
12247
- throw new Error(`write_todos: item at index ${index} must have a non-empty description`);
12248
- }
12249
- if (typeof status !== "string" || !VALID_STATUSES.includes(status)) {
12250
- throw new Error(
12251
- `write_todos: item at index ${index} has invalid status "${status}". Must be one of: ${VALID_STATUSES.join(", ")}`
12252
- );
12253
- }
12254
- if (status === "in_progress") {
12255
- inProgressCount++;
12256
- }
12257
- return {
12258
- description: description.trim(),
12259
- status
12260
- };
12261
- });
12262
- if (inProgressCount > 1) {
12263
- throw new Error(`write_todos: only one task can be 'in_progress' at a time, but found ${inProgressCount}`);
12264
- }
12265
- return validatedTodos;
12266
- }
12267
- function formatTodosOutput(todos) {
12268
- const statusEmoji = {
12269
- pending: "\u2B1C",
12270
- in_progress: "\u{1F504}",
12271
- completed: "\u2705",
12272
- cancelled: "\u274C"
12273
- };
12274
- const lines = todos.map((todo, index) => {
12275
- const emoji = statusEmoji[todo.status];
12276
- return `${index + 1}. ${emoji} [${todo.status}] ${todo.description}`;
12277
- });
12278
- return lines.join("\n");
12279
- }
12280
- function createWriteTodosTool(todoStore) {
12281
- return {
12282
- toolFn: async (args) => {
12283
- const params = args;
12284
- const validatedTodos = validateTodos(params.todos);
12285
- todoStore.todos = validatedTodos;
12286
- if (todoStore.onUpdate) {
12287
- todoStore.onUpdate(validatedTodos);
12288
- }
12289
- const output = formatTodosOutput(validatedTodos);
12290
- return `Todo list updated successfully:
12291
-
12292
- ${output}`;
12293
- },
12294
- toolSchema: {
12295
- name: "write_todos",
12296
- description: `Create or update a list of subtasks for complex multi-step requests.
12297
-
12298
- **When to use this tool:**
12299
- - When handling complex requests that require multiple steps
12300
- - To break down a large task into smaller, manageable subtasks
12301
- - To track progress through a multi-step workflow
12302
-
12303
- **Important guidelines:**
12304
- - Call this tool early when receiving complex requests
12305
- - Update the list immediately when starting, completing, or cancelling tasks
12306
- - Only ONE task should be 'in_progress' at a time
12307
- - Never batch updates - update as soon as state changes
12308
-
12309
- **Status values:**
12310
- - pending: Task not yet started
12311
- - in_progress: Currently working on this task (only ONE allowed)
12312
- - completed: Task finished successfully
12313
- - cancelled: Task will not be completed
12314
-
12315
- **Example:**
12316
- If asked to "create a new React component with tests", break it down:
12317
- 1. Create component file \u2192 in_progress
12318
- 2. Add component logic \u2192 pending
12319
- 3. Create test file \u2192 pending
12320
- 4. Write unit tests \u2192 pending`,
12321
- parameters: {
12322
- type: "object",
12323
- properties: {
12324
- todos: {
12325
- type: "array",
12326
- description: "Complete list of todo items. This replaces any existing list. Each item needs a description and status.",
12327
- items: {
12328
- type: "object",
12329
- properties: {
12330
- description: {
12331
- type: "string",
12332
- description: "Clear, concise description of the task"
12333
- },
12334
- status: {
12335
- type: "string",
12336
- enum: ["pending", "in_progress", "completed", "cancelled"],
12337
- description: "Current status of the task. Only ONE task can be 'in_progress' at a time."
12338
- }
12339
- },
12340
- required: ["description", "status"]
12341
- }
12342
- }
12343
- },
12344
- required: ["todos"]
12345
- }
12346
- }
12347
- };
12348
- }
12349
- function createTodoStore(onUpdate) {
12350
- return {
12351
- todos: [],
12352
- onUpdate
12353
- };
12354
- }
12355
-
12356
12137
  // src/index.tsx
12357
12138
  process.removeAllListeners("warning");
12358
12139
  process.on("warning", (warning) => {
@@ -12384,8 +12165,7 @@ function CliApp() {
12384
12165
  trustLocationSelector: null,
12385
12166
  rewindSelector: null,
12386
12167
  sessionSelector: null,
12387
- orchestrator: null,
12388
- abortController: null
12168
+ orchestrator: null
12389
12169
  });
12390
12170
  const [isInitialized, setIsInitialized] = useState8(false);
12391
12171
  const [initError, setInitError] = useState8(null);
@@ -12431,15 +12211,6 @@ function CliApp() {
12431
12211
  }, 100);
12432
12212
  }, [state.session, state.sessionStore, state.mcpManager, state.agent, state.imageStore]);
12433
12213
  useInput6((input, key) => {
12434
- if (key.escape) {
12435
- if (state.abortController) {
12436
- logger.debug("[ABORT] ESC pressed - aborting current operation...");
12437
- state.abortController.abort();
12438
- setState((prev) => ({ ...prev, abortController: null }));
12439
- useCliStore.getState().setIsThinking(false);
12440
- }
12441
- return;
12442
- }
12443
12214
  if (key.ctrl && input === "c") {
12444
12215
  const now = Date.now();
12445
12216
  if (exitTimestamp && now - exitTimestamp < EXIT_TIMEOUT_MS) {
@@ -12637,9 +12408,7 @@ function CliApp() {
12637
12408
  subagentConfigs
12638
12409
  });
12639
12410
  const subagentDelegateTool = createSubagentDelegateTool(orchestrator, newSession.id);
12640
- const todoStore = createTodoStore();
12641
- const writeTodosTool = createWriteTodosTool(todoStore);
12642
- const allTools = [...b4mTools, ...mcpTools, subagentDelegateTool, writeTodosTool];
12411
+ const allTools = [...b4mTools, ...mcpTools, subagentDelegateTool];
12643
12412
  console.log(`\u{1F916} Subagent delegation enabled (explore, plan, review)`);
12644
12413
  const projectDir = state.configStore.getProjectConfigDir();
12645
12414
  const contextResult = await loadContextFiles(projectDir);
@@ -12659,7 +12428,46 @@ function CliApp() {
12659
12428
  Follow these project-specific instructions:
12660
12429
 
12661
12430
  ${contextResult.mergedContent}` : "";
12662
- const cliSystemPrompt = buildCoreSystemPrompt(contextSection);
12431
+ const cliSystemPrompt = `You are an autonomous AI assistant with access to tools. Your job is to help users by taking action and solving problems proactively.
12432
+
12433
+ CORE BEHAVIOR:
12434
+ - Be proactive: Take action instead of asking for permission or clarification
12435
+ - Make smart assumptions: If unclear, choose the most reasonable interpretation
12436
+ - Use conversation history: Reference previous exchanges to understand context
12437
+ - Complete tasks fully: Don't just show what to do - actually do it
12438
+
12439
+ FOR CODING TASKS:
12440
+ - You have file system access (file_read, create_file, glob_files, grep_search, delete_file)
12441
+ - When user says "enhance", "update", "fix", "improve" a file:
12442
+ * Use file_read to get current content
12443
+ * Generate the improved version
12444
+ * Use create_file to write it back
12445
+ * Don't just show suggestions - make the changes
12446
+ - When searching for code: Use grep_search or glob_files to find relevant files
12447
+ - Permission system will ask for approval before any file writes
12448
+
12449
+ SUBAGENT DELEGATION:
12450
+ - You have access to specialized subagents via the subagent_delegate tool
12451
+ - Use subagents for focused exploration, planning, or review tasks:
12452
+ * explore: Fast read-only codebase search (e.g., "find all auth files", "locate API endpoints")
12453
+ * plan: Break down complex tasks into actionable steps
12454
+ * review: Analyze code quality and identify issues
12455
+ - Subagents keep the main conversation clean and run faster with optimized models
12456
+ - Delegate when you need to search extensively or analyze code structure
12457
+
12458
+ FOR GENERAL TASKS:
12459
+ - Use available tools to get information (weather, web search, calculations, etc.)
12460
+ - When user asks follow-up questions, use conversation context to understand what they're referring to
12461
+ - If user asks "how about X?" after a previous question, apply the same question type to X
12462
+
12463
+ EXAMPLES:
12464
+ - "what should I wear in Texas?" \u2192 use weather tool for Texas
12465
+ - "how about Japan?" \u2192 use weather tool for Japan (applying same question from context)
12466
+ - "enhance README" \u2192 file_read \u2192 generate \u2192 create_file
12467
+ - "what packages installed?" \u2192 glob_files "**/package.json" \u2192 file_read
12468
+ - "find all components using React hooks" \u2192 subagent_delegate(task="find all components using React hooks", type="explore")
12469
+
12470
+ Remember: Use context from previous messages to understand follow-up questions.${contextSection}`;
12663
12471
  const maxIterations = config.preferences.maxIterations === null ? 999999 : config.preferences.maxIterations;
12664
12472
  const agent = new ReActAgent({
12665
12473
  userId: config.userId,
@@ -12704,16 +12512,13 @@ ${contextResult.mergedContent}` : "";
12704
12512
  }
12705
12513
  };
12706
12514
  agent.on("thought", stepHandler);
12707
- agent.on("observation", stepHandler);
12708
12515
  agent.on("action", stepHandler);
12709
12516
  orchestrator.setBeforeRunCallback((subagent, _subagentType) => {
12710
12517
  subagent.on("thought", stepHandler);
12711
- subagent.on("observation", stepHandler);
12712
12518
  subagent.on("action", stepHandler);
12713
12519
  });
12714
12520
  orchestrator.setAfterRunCallback((subagent, _subagentType) => {
12715
12521
  subagent.off("thought", stepHandler);
12716
- subagent.off("observation", stepHandler);
12717
12522
  subagent.off("action", stepHandler);
12718
12523
  });
12719
12524
  setState((prev) => ({
@@ -12760,8 +12565,6 @@ ${contextResult.mergedContent}` : "";
12760
12565
  return;
12761
12566
  }
12762
12567
  useCliStore.getState().setIsThinking(true);
12763
- const abortController = new AbortController();
12764
- setState((prev) => ({ ...prev, abortController }));
12765
12568
  const currentSteps = [];
12766
12569
  const stepHandler = (step) => {
12767
12570
  currentSteps.push(step);
@@ -12821,8 +12624,7 @@ ${contextResult.mergedContent}` : "";
12821
12624
  content: msg.content
12822
12625
  }));
12823
12626
  const result = await state.agent.run(messageContent, {
12824
- previousMessages: previousMessages.length > 0 ? previousMessages : void 0,
12825
- signal: abortController.signal
12627
+ previousMessages: previousMessages.length > 0 ? previousMessages : void 0
12826
12628
  });
12827
12629
  const permissionDenied = result.finalAnswer.startsWith("Permission denied for tool");
12828
12630
  if (permissionDenied) {
@@ -12867,33 +12669,6 @@ ${contextResult.mergedContent}` : "";
12867
12669
  useCliStore.getState().setIsThinking(false);
12868
12670
  } catch (error) {
12869
12671
  useCliStore.getState().setIsThinking(false);
12870
- if (error instanceof Error && error.name === "AbortError") {
12871
- logger.debug("[ABORT] Custom command aborted by user");
12872
- const currentSession2 = useCliStore.getState().session;
12873
- if (currentSession2) {
12874
- const messages2 = [...currentSession2.messages];
12875
- const lastMessage2 = messages2[messages2.length - 1];
12876
- if (lastMessage2 && lastMessage2.role === "assistant") {
12877
- messages2[messages2.length - 1] = {
12878
- ...lastMessage2,
12879
- content: "\u26A0\uFE0F Operation cancelled by user",
12880
- metadata: {
12881
- ...lastMessage2.metadata,
12882
- cancelled: true
12883
- }
12884
- };
12885
- }
12886
- const sessionWithCancel = {
12887
- ...currentSession2,
12888
- messages: messages2,
12889
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
12890
- };
12891
- setState((prev) => ({ ...prev, session: sessionWithCancel }));
12892
- setStoreSession(sessionWithCancel);
12893
- await state.sessionStore.save(sessionWithCancel);
12894
- }
12895
- return;
12896
- }
12897
12672
  if (error?.message?.includes("Permission denied")) {
12898
12673
  console.log("\n\u26A0\uFE0F Action blocked by permission settings");
12899
12674
  const currentSession2 = useCliStore.getState().session;
@@ -12934,7 +12709,6 @@ ${contextResult.mergedContent}` : "";
12934
12709
  setState((prev) => ({ ...prev, session: sessionWithError }));
12935
12710
  setStoreSession(sessionWithError);
12936
12711
  } finally {
12937
- setState((prev) => ({ ...prev, abortController: null }));
12938
12712
  state.agent.off("thought", stepHandler);
12939
12713
  state.agent.off("action", stepHandler);
12940
12714
  }
@@ -12954,8 +12728,6 @@ ${contextResult.mergedContent}` : "";
12954
12728
  return;
12955
12729
  }
12956
12730
  useCliStore.getState().setIsThinking(true);
12957
- const abortController = new AbortController();
12958
- setState((prev) => ({ ...prev, abortController }));
12959
12731
  try {
12960
12732
  let messageContent = message;
12961
12733
  let userMessageContent = message;
@@ -12993,8 +12765,7 @@ ${contextResult.mergedContent}` : "";
12993
12765
  content: msg.content
12994
12766
  }));
12995
12767
  const result = await state.agent.run(messageContent, {
12996
- previousMessages: previousMessages.length > 0 ? previousMessages : void 0,
12997
- signal: abortController.signal
12768
+ previousMessages: previousMessages.length > 0 ? previousMessages : void 0
12998
12769
  });
12999
12770
  const permissionDenied = result.finalAnswer.startsWith("Permission denied for tool");
13000
12771
  if (permissionDenied) {
@@ -13034,30 +12805,6 @@ ${contextResult.mergedContent}` : "";
13034
12805
  await state.sessionStore.save(updatedSession);
13035
12806
  } catch (error) {
13036
12807
  useCliStore.getState().clearPendingMessages();
13037
- if (error instanceof Error && error.name === "AbortError") {
13038
- logger.debug("[ABORT] Operation aborted by user");
13039
- const currentSession = useCliStore.getState().session;
13040
- if (currentSession) {
13041
- const cancelMessage = {
13042
- id: uuidv410(),
13043
- role: "assistant",
13044
- content: "\u26A0\uFE0F Operation cancelled by user",
13045
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
13046
- metadata: {
13047
- cancelled: true
13048
- }
13049
- };
13050
- const sessionWithCancel = {
13051
- ...currentSession,
13052
- messages: [...currentSession.messages, cancelMessage],
13053
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
13054
- };
13055
- setState((prev) => ({ ...prev, session: sessionWithCancel }));
13056
- setStoreSession(sessionWithCancel);
13057
- await state.sessionStore.save(sessionWithCancel);
13058
- }
13059
- return;
13060
- }
13061
12808
  if (error instanceof Error) {
13062
12809
  if (error.message.includes("Authentication failed") || error.message.includes("Authentication expired")) {
13063
12810
  console.log("\n\u274C Authentication failed");
@@ -13066,9 +12813,6 @@ ${contextResult.mergedContent}` : "";
13066
12813
  }
13067
12814
  }
13068
12815
  console.error("Error processing message:", error);
13069
- } finally {
13070
- setState((prev) => ({ ...prev, abortController: null }));
13071
- useCliStore.getState().setIsThinking(false);
13072
12816
  }
13073
12817
  };
13074
12818
  const handleBashCommand = useCallback(
@@ -13119,7 +12863,7 @@ ${output}` : output.trim() || "(no output)",
13119
12863
  if (!imageStore) {
13120
12864
  if (!imageStoreInitPromise.current) {
13121
12865
  imageStoreInitPromise.current = (async () => {
13122
- const { ImageStore: ImageStoreClass } = await import("./ImageStore-MMUOUPI2.js");
12866
+ const { ImageStore: ImageStoreClass } = await import("./ImageStore-RQZ7OF7P.js");
13123
12867
  const newImageStore = new ImageStoreClass();
13124
12868
  setState((prev) => ({
13125
12869
  ...prev,