@rdmind/rdmind 0.0.22-alpha.0 → 0.0.23-alpha.0

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.
Files changed (2) hide show
  1. package/cli.js +277 -476
  2. package/package.json +2 -2
package/cli.js CHANGED
@@ -183770,7 +183770,7 @@ function createContentGeneratorConfig(config, authType, generationConfig) {
183770
183770
  };
183771
183771
  }
183772
183772
  async function createContentGenerator(config, gcConfig, sessionId2) {
183773
- const version2 = "0.0.22-alpha.0";
183773
+ const version2 = "0.0.23-alpha.0";
183774
183774
  const userAgent2 = `QwenCode/${version2} (${process.platform}; ${process.arch})`;
183775
183775
  const baseHeaders = {
183776
183776
  "User-Agent": userAgent2
@@ -185708,6 +185708,7 @@ var init_gitUtils = __esm({
185708
185708
  });
185709
185709
 
185710
185710
  // packages/core/src/utils/paths.ts
185711
+ import fs19 from "node:fs";
185711
185712
  import path15 from "node:path";
185712
185713
  import os11 from "node:os";
185713
185714
  import * as crypto11 from "node:crypto";
@@ -185799,11 +185800,51 @@ function isSubpath(parentPath, childPath) {
185799
185800
  const relative10 = pathModule2.relative(parentPath, childPath);
185800
185801
  return !relative10.startsWith(`..${pathModule2.sep}`) && relative10 !== ".." && !pathModule2.isAbsolute(relative10);
185801
185802
  }
185803
+ function resolvePath(baseDir = process.cwd(), relativePath) {
185804
+ const homeDir = os11.homedir();
185805
+ if (relativePath === "~") {
185806
+ return homeDir;
185807
+ } else if (relativePath.startsWith("~/")) {
185808
+ return path15.join(homeDir, relativePath.slice(2));
185809
+ } else if (path15.isAbsolute(relativePath)) {
185810
+ return relativePath;
185811
+ } else {
185812
+ return path15.resolve(baseDir, relativePath);
185813
+ }
185814
+ }
185815
+ function validatePath(config, resolvedPath, options2 = {}) {
185816
+ const { allowFiles = false } = options2;
185817
+ const workspaceContext = config.getWorkspaceContext();
185818
+ if (!workspaceContext.isPathWithinWorkspace(resolvedPath)) {
185819
+ throw new Error("Path is not within workspace");
185820
+ }
185821
+ try {
185822
+ const stats = fs19.statSync(resolvedPath);
185823
+ if (!allowFiles && !stats.isDirectory()) {
185824
+ throw new Error(`Path is not a directory: ${resolvedPath}`);
185825
+ }
185826
+ } catch (error) {
185827
+ if (isNodeError(error) && error.code === "ENOENT") {
185828
+ throw new Error(`Path does not exist: ${resolvedPath}`);
185829
+ }
185830
+ throw error;
185831
+ }
185832
+ }
185833
+ function resolveAndValidatePath(config, relativePath, options2 = {}) {
185834
+ const targetDir = config.getTargetDir();
185835
+ if (!relativePath) {
185836
+ return targetDir;
185837
+ }
185838
+ const resolvedPath = resolvePath(targetDir, relativePath);
185839
+ validatePath(config, resolvedPath, options2);
185840
+ return resolvedPath;
185841
+ }
185802
185842
  var QWEN_DIR5, SHELL_SPECIAL_CHARS;
185803
185843
  var init_paths = __esm({
185804
185844
  "packages/core/src/utils/paths.ts"() {
185805
185845
  "use strict";
185806
185846
  init_esbuild_shims();
185847
+ init_errors();
185807
185848
  QWEN_DIR5 = ".rdmind";
185808
185849
  SHELL_SPECIAL_CHARS = /[ \t()[\]{};|*?$`'"#&<>!~]/;
185809
185850
  __name(tildeifyPath, "tildeifyPath");
@@ -185813,11 +185854,14 @@ var init_paths = __esm({
185813
185854
  __name(unescapePath, "unescapePath");
185814
185855
  __name(getProjectHash, "getProjectHash");
185815
185856
  __name(isSubpath, "isSubpath");
185857
+ __name(resolvePath, "resolvePath");
185858
+ __name(validatePath, "validatePath");
185859
+ __name(resolveAndValidatePath, "resolveAndValidatePath");
185816
185860
  }
185817
185861
  });
185818
185862
 
185819
185863
  // packages/core/src/tools/memoryTool.ts
185820
- import * as fs19 from "node:fs/promises";
185864
+ import * as fs20 from "node:fs/promises";
185821
185865
  import * as path16 from "node:path";
185822
185866
  function setGeminiMdFilename(newFilename) {
185823
185867
  if (Array.isArray(newFilename)) {
@@ -185859,7 +185903,7 @@ function ensureNewlineSeparation(currentContent) {
185859
185903
  }
185860
185904
  async function readMemoryFileContent(scope = "global") {
185861
185905
  try {
185862
- return await fs19.readFile(getMemoryFilePath(scope), "utf-8");
185906
+ return await fs20.readFile(getMemoryFilePath(scope), "utf-8");
185863
185907
  } catch (err) {
185864
185908
  const error = err;
185865
185909
  if (!(error instanceof Error) || error.code !== "ENOENT") throw err;
@@ -186084,10 +186128,10 @@ Project: ${projectPath} (current project only)`;
186084
186128
  const memoryFilePath = getMemoryFilePath(scope);
186085
186129
  try {
186086
186130
  if (modified_by_user && modified_content !== void 0) {
186087
- await fs19.mkdir(path16.dirname(memoryFilePath), {
186131
+ await fs20.mkdir(path16.dirname(memoryFilePath), {
186088
186132
  recursive: true
186089
186133
  });
186090
- await fs19.writeFile(memoryFilePath, modified_content, "utf-8");
186134
+ await fs20.writeFile(memoryFilePath, modified_content, "utf-8");
186091
186135
  const successMessage = `Okay, I've updated the ${scope} memory file with your modifications.`;
186092
186136
  return {
186093
186137
  llmContent: successMessage,
@@ -186095,9 +186139,9 @@ Project: ${projectPath} (current project only)`;
186095
186139
  };
186096
186140
  } else {
186097
186141
  await MemoryTool.performAddMemoryEntry(fact, memoryFilePath, {
186098
- readFile: fs19.readFile,
186099
- writeFile: fs19.writeFile,
186100
- mkdir: fs19.mkdir
186142
+ readFile: fs20.readFile,
186143
+ writeFile: fs20.writeFile,
186144
+ mkdir: fs20.mkdir
186101
186145
  });
186102
186146
  const successMessage = `Okay, I've remembered that in ${scope} memory: "${fact}"`;
186103
186147
  return {
@@ -186256,7 +186300,7 @@ ${newContent}`;
186256
186300
 
186257
186301
  // packages/core/src/core/prompts.ts
186258
186302
  import path17 from "node:path";
186259
- import fs20 from "node:fs";
186303
+ import fs21 from "node:fs";
186260
186304
  import os12 from "node:os";
186261
186305
  import process18 from "node:process";
186262
186306
  function resolvePathFromEnv(envVar) {
@@ -186321,11 +186365,11 @@ function getCoreSystemPrompt(userMemory, model) {
186321
186365
  if (!systemMdResolution.isSwitch) {
186322
186366
  systemMdPath = systemMdResolution.value;
186323
186367
  }
186324
- if (!fs20.existsSync(systemMdPath)) {
186368
+ if (!fs21.existsSync(systemMdPath)) {
186325
186369
  throw new Error(`missing system prompt file '${systemMdPath}'`);
186326
186370
  }
186327
186371
  }
186328
- const basePrompt = systemMdEnabled ? fs20.readFileSync(systemMdPath, "utf8") : `
186372
+ const basePrompt = systemMdEnabled ? fs21.readFileSync(systemMdPath, "utf8") : `
186329
186373
  You are RDMind, an interactive CLI agent, specializing in software engineering tasks. Your primary goal is to help users safely and efficiently, adhering strictly to the following instructions and utilizing your available tools.
186330
186374
 
186331
186375
  # Core Mandates
@@ -186507,8 +186551,8 @@ Your core function is efficient and safe assistance. Balance extreme conciseness
186507
186551
  );
186508
186552
  if (writeSystemMdResolution.value && !writeSystemMdResolution.isDisabled) {
186509
186553
  const writePath = writeSystemMdResolution.isSwitch ? systemMdPath : writeSystemMdResolution.value;
186510
- fs20.mkdirSync(path17.dirname(writePath), { recursive: true });
186511
- fs20.writeFileSync(writePath, basePrompt);
186554
+ fs21.mkdirSync(path17.dirname(writePath), { recursive: true });
186555
+ fs21.writeFileSync(writePath, basePrompt);
186512
186556
  }
186513
186557
  const memorySuffix = userMemory && userMemory.trim().length > 0 ? `
186514
186558
 
@@ -198134,7 +198178,7 @@ ${stderr}`));
198134
198178
  });
198135
198179
 
198136
198180
  // packages/core/src/tools/shell.ts
198137
- import fs21 from "node:fs";
198181
+ import fs22 from "node:fs";
198138
198182
  import path18 from "node:path";
198139
198183
  import os16, { EOL } from "node:os";
198140
198184
  import crypto12 from "node:crypto";
@@ -198321,8 +198365,8 @@ var init_shell = __esm({
198321
198365
  const result = await resultPromise;
198322
198366
  const backgroundPIDs = [];
198323
198367
  if (os16.platform() !== "win32") {
198324
- if (fs21.existsSync(tempFilePath)) {
198325
- const pgrepLines = fs21.readFileSync(tempFilePath, "utf8").split(EOL).filter(Boolean);
198368
+ if (fs22.existsSync(tempFilePath)) {
198369
+ const pgrepLines = fs22.readFileSync(tempFilePath, "utf8").split(EOL).filter(Boolean);
198326
198370
  for (const line of pgrepLines) {
198327
198371
  if (!/^\d+$/.test(line)) {
198328
198372
  console.error(`pgrep: ${line}`);
@@ -198407,8 +198451,8 @@ ${result.output}`;
198407
198451
  ...executionError
198408
198452
  };
198409
198453
  } finally {
198410
- if (fs21.existsSync(tempFilePath)) {
198411
- fs21.unlinkSync(tempFilePath);
198454
+ if (fs22.existsSync(tempFilePath)) {
198455
+ fs22.unlinkSync(tempFilePath);
198412
198456
  }
198413
198457
  }
198414
198458
  }
@@ -198517,7 +198561,7 @@ Co-authored-by: ${gitCoAuthorSettings.name} <${gitCoAuthorSettings.email}>`;
198517
198561
  });
198518
198562
 
198519
198563
  // packages/core/src/core/coreToolScheduler.ts
198520
- import * as fs22 from "node:fs/promises";
198564
+ import * as fs23 from "node:fs/promises";
198521
198565
  import * as path19 from "node:path";
198522
198566
  function createFunctionResponsePart(callId, toolName, output) {
198523
198567
  return {
@@ -198607,7 +198651,7 @@ async function truncateAndSaveToFile(content, callId, projectTempDir, threshold,
198607
198651
  const safeFileName = `${path19.basename(callId)}.output`;
198608
198652
  const outputFile = path19.join(projectTempDir, safeFileName);
198609
198653
  try {
198610
- await fs22.writeFile(outputFile, fileContent);
198654
+ await fs23.writeFile(outputFile, fileContent);
198611
198655
  return {
198612
198656
  content: `Tool output was too large and has been truncated.
198613
198657
  The full output has been saved to: ${outputFile}
@@ -199386,7 +199430,7 @@ var init_thoughtUtils = __esm({
199386
199430
 
199387
199431
  // packages/core/src/services/chatRecordingService.ts
199388
199432
  import path20 from "node:path";
199389
- import fs23 from "node:fs";
199433
+ import fs24 from "node:fs";
199390
199434
  import { randomUUID as randomUUID4 } from "node:crypto";
199391
199435
  var ChatRecordingService;
199392
199436
  var init_chatRecordingService = __esm({
@@ -199431,7 +199475,7 @@ var init_chatRecordingService = __esm({
199431
199475
  this.config.storage.getProjectTempDir(),
199432
199476
  "chats"
199433
199477
  );
199434
- fs23.mkdirSync(chatsDir, { recursive: true });
199478
+ fs24.mkdirSync(chatsDir, { recursive: true });
199435
199479
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().slice(0, 16).replace(/:/g, "-");
199436
199480
  const filename = `session-${timestamp}-${this.sessionId.slice(
199437
199481
  0,
@@ -199607,7 +199651,7 @@ var init_chatRecordingService = __esm({
199607
199651
  */
199608
199652
  readConversation() {
199609
199653
  try {
199610
- this.cachedLastConvData = fs23.readFileSync(this.conversationFile, "utf8");
199654
+ this.cachedLastConvData = fs24.readFileSync(this.conversationFile, "utf8");
199611
199655
  return JSON.parse(this.cachedLastConvData);
199612
199656
  } catch (error) {
199613
199657
  if (error.code !== "ENOENT") {
@@ -199634,7 +199678,7 @@ var init_chatRecordingService = __esm({
199634
199678
  conversation.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
199635
199679
  const newContent = JSON.stringify(conversation, null, 2);
199636
199680
  this.cachedLastConvData = newContent;
199637
- fs23.writeFileSync(this.conversationFile, newContent);
199681
+ fs24.writeFileSync(this.conversationFile, newContent);
199638
199682
  }
199639
199683
  } catch (error) {
199640
199684
  console.error("Error writing conversation file:", error);
@@ -199660,7 +199704,7 @@ var init_chatRecordingService = __esm({
199660
199704
  "chats"
199661
199705
  );
199662
199706
  const sessionPath = path20.join(chatsDir, `${sessionId2}.json`);
199663
- fs23.unlinkSync(sessionPath);
199707
+ fs24.unlinkSync(sessionPath);
199664
199708
  } catch (error) {
199665
199709
  console.error("Error deleting session:", error);
199666
199710
  throw error;
@@ -200532,7 +200576,7 @@ var init_constants3 = __esm({
200532
200576
  });
200533
200577
 
200534
200578
  // packages/core/src/utils/getFolderStructure.ts
200535
- import * as fs24 from "node:fs/promises";
200579
+ import * as fs25 from "node:fs/promises";
200536
200580
  import * as path21 from "node:path";
200537
200581
  async function readFullStructure(rootPath, options2) {
200538
200582
  const rootName = path21.basename(rootPath);
@@ -200560,7 +200604,7 @@ async function readFullStructure(rootPath, options2) {
200560
200604
  }
200561
200605
  let entries;
200562
200606
  try {
200563
- const rawEntries = await fs24.readdir(currentPath, { withFileTypes: true });
200607
+ const rawEntries = await fs25.readdir(currentPath, { withFileTypes: true });
200564
200608
  entries = rawEntries.sort((a, b) => a.name.localeCompare(b.name));
200565
200609
  } catch (error) {
200566
200610
  if (isNodeError(error) && (error.code === "EACCES" || error.code === "ENOENT")) {
@@ -208025,7 +208069,7 @@ var require_ignore = __commonJS({
208025
208069
  });
208026
208070
 
208027
208071
  // packages/core/src/utils/gitIgnoreParser.ts
208028
- import * as fs25 from "node:fs";
208072
+ import * as fs26 from "node:fs";
208029
208073
  import * as path22 from "node:path";
208030
208074
  var import_ignore, GitIgnoreParser;
208031
208075
  var init_gitIgnoreParser = __esm({
@@ -208046,7 +208090,7 @@ var init_gitIgnoreParser = __esm({
208046
208090
  loadPatternsForFile(patternsFilePath) {
208047
208091
  let content;
208048
208092
  try {
208049
- content = fs25.readFileSync(patternsFilePath, "utf-8");
208093
+ content = fs26.readFileSync(patternsFilePath, "utf-8");
208050
208094
  } catch (_error) {
208051
208095
  return [];
208052
208096
  }
@@ -208113,7 +208157,7 @@ var init_gitIgnoreParser = __esm({
208113
208157
  "info",
208114
208158
  "exclude"
208115
208159
  );
208116
- this.globalPatterns = fs25.existsSync(excludeFile) ? this.loadPatternsForFile(excludeFile) : [];
208160
+ this.globalPatterns = fs26.existsSync(excludeFile) ? this.loadPatternsForFile(excludeFile) : [];
208117
208161
  }
208118
208162
  ig.add(this.globalPatterns);
208119
208163
  const pathParts = relativePath.split(path22.sep);
@@ -208138,7 +208182,7 @@ var init_gitIgnoreParser = __esm({
208138
208182
  }
208139
208183
  } else {
208140
208184
  const gitignorePath = path22.join(dir, ".gitignore");
208141
- if (fs25.existsSync(gitignorePath)) {
208185
+ if (fs26.existsSync(gitignorePath)) {
208142
208186
  const patterns = this.loadPatternsForFile(gitignorePath);
208143
208187
  this.cache.set(dir, patterns);
208144
208188
  ig.add(patterns);
@@ -208157,7 +208201,7 @@ var init_gitIgnoreParser = __esm({
208157
208201
  });
208158
208202
 
208159
208203
  // packages/core/src/utils/qwenIgnoreParser.ts
208160
- import * as fs26 from "node:fs";
208204
+ import * as fs27 from "node:fs";
208161
208205
  import * as path23 from "node:path";
208162
208206
  var import_ignore2, QwenIgnoreParser;
208163
208207
  var init_qwenIgnoreParser = __esm({
@@ -208180,7 +208224,7 @@ var init_qwenIgnoreParser = __esm({
208180
208224
  const patternsFilePath = path23.join(this.projectRoot, ".rdmindignore");
208181
208225
  let content;
208182
208226
  try {
208183
- content = fs26.readFileSync(patternsFilePath, "utf-8");
208227
+ content = fs27.readFileSync(patternsFilePath, "utf-8");
208184
208228
  } catch (_error) {
208185
208229
  return;
208186
208230
  }
@@ -215142,7 +215186,7 @@ var init_esm9 = __esm({
215142
215186
  });
215143
215187
 
215144
215188
  // packages/core/src/services/fileSystemService.ts
215145
- import fs27 from "node:fs/promises";
215189
+ import fs28 from "node:fs/promises";
215146
215190
  import * as path26 from "node:path";
215147
215191
  var StandardFileSystemService;
215148
215192
  var init_fileSystemService = __esm({
@@ -215155,10 +215199,10 @@ var init_fileSystemService = __esm({
215155
215199
  __name(this, "StandardFileSystemService");
215156
215200
  }
215157
215201
  async readTextFile(filePath) {
215158
- return fs27.readFile(filePath, "utf-8");
215202
+ return fs28.readFile(filePath, "utf-8");
215159
215203
  }
215160
215204
  async writeTextFile(filePath, content) {
215161
- await fs27.writeFile(filePath, content, "utf-8");
215205
+ await fs28.writeFile(filePath, content, "utf-8");
215162
215206
  }
215163
215207
  findFiles(fileName, searchPaths) {
215164
215208
  return searchPaths.flatMap((searchPath) => {
@@ -219988,7 +220032,7 @@ var init_esm10 = __esm({
219988
220032
  });
219989
220033
 
219990
220034
  // packages/core/src/services/gitService.ts
219991
- import * as fs28 from "node:fs/promises";
220035
+ import * as fs29 from "node:fs/promises";
219992
220036
  import * as path27 from "node:path";
219993
220037
  var GitService;
219994
220038
  var init_gitService = __esm({
@@ -220041,9 +220085,9 @@ var init_gitService = __esm({
220041
220085
  async setupShadowGitRepository() {
220042
220086
  const repoDir = this.getHistoryDir();
220043
220087
  const gitConfigPath = path27.join(repoDir, ".gitconfig");
220044
- await fs28.mkdir(repoDir, { recursive: true });
220088
+ await fs29.mkdir(repoDir, { recursive: true });
220045
220089
  const gitConfigContent = "[user]\n name = Qwen Code\n email = qwen-code@qwen.ai\n[commit]\n gpgsign = false\n";
220046
- await fs28.writeFile(gitConfigPath, gitConfigContent);
220090
+ await fs29.writeFile(gitConfigPath, gitConfigContent);
220047
220091
  const repo = simpleGit(repoDir);
220048
220092
  const isRepoDefined = await repo.checkIsRepo(CheckRepoActions.IS_REPO_ROOT);
220049
220093
  if (!isRepoDefined) {
@@ -220056,13 +220100,13 @@ var init_gitService = __esm({
220056
220100
  const shadowGitIgnorePath = path27.join(repoDir, ".gitignore");
220057
220101
  let userGitIgnoreContent = "";
220058
220102
  try {
220059
- userGitIgnoreContent = await fs28.readFile(userGitIgnorePath, "utf-8");
220103
+ userGitIgnoreContent = await fs29.readFile(userGitIgnorePath, "utf-8");
220060
220104
  } catch (error) {
220061
220105
  if (isNodeError(error) && error.code !== "ENOENT") {
220062
220106
  throw error;
220063
220107
  }
220064
220108
  }
220065
- await fs28.writeFile(shadowGitIgnorePath, userGitIgnoreContent);
220109
+ await fs29.writeFile(shadowGitIgnorePath, userGitIgnoreContent);
220066
220110
  }
220067
220111
  get shadowGitRepository() {
220068
220112
  const repoDir = this.getHistoryDir();
@@ -220751,7 +220795,7 @@ var init_ignorePatterns = __esm({
220751
220795
  });
220752
220796
 
220753
220797
  // packages/core/src/utils/fileUtils.ts
220754
- import fs29 from "node:fs";
220798
+ import fs30 from "node:fs";
220755
220799
  import fsPromises from "node:fs/promises";
220756
220800
  import path29 from "node:path";
220757
220801
  function detectBOM(buf) {
@@ -220799,7 +220843,7 @@ function decodeUTF32(buf, littleEndian) {
220799
220843
  return out;
220800
220844
  }
220801
220845
  async function readFileWithEncoding(filePath) {
220802
- const full = await fs29.promises.readFile(filePath);
220846
+ const full = await fs30.promises.readFile(filePath);
220803
220847
  if (full.length === 0) return "";
220804
220848
  const bom = detectBOM(full);
220805
220849
  if (!bom) {
@@ -220834,7 +220878,7 @@ function isWithinRoot(pathToCheck, rootDirectory) {
220834
220878
  async function isBinaryFile(filePath) {
220835
220879
  let fh = null;
220836
220880
  try {
220837
- fh = await fs29.promises.open(filePath, "r");
220881
+ fh = await fs30.promises.open(filePath, "r");
220838
220882
  const stats = await fh.stat();
220839
220883
  const fileSize = stats.size;
220840
220884
  if (fileSize === 0) return false;
@@ -220904,7 +220948,7 @@ async function detectFileType(filePath) {
220904
220948
  }
220905
220949
  async function processSingleFileContent(filePath, rootDirectory, fileSystemService, offset, limit2) {
220906
220950
  try {
220907
- if (!fs29.existsSync(filePath)) {
220951
+ if (!fs30.existsSync(filePath)) {
220908
220952
  return {
220909
220953
  llmContent: "Could not read file because no file was found at the specified path.",
220910
220954
  returnDisplay: "File not found.",
@@ -220912,7 +220956,7 @@ async function processSingleFileContent(filePath, rootDirectory, fileSystemServi
220912
220956
  errorType: "file_not_found" /* FILE_NOT_FOUND */
220913
220957
  };
220914
220958
  }
220915
- const stats = await fs29.promises.stat(filePath);
220959
+ const stats = await fs30.promises.stat(filePath);
220916
220960
  if (stats.isDirectory()) {
220917
220961
  return {
220918
220962
  llmContent: "Could not read file because the provided path is a directory, not a file.",
@@ -220994,7 +221038,7 @@ async function processSingleFileContent(filePath, rootDirectory, fileSystemServi
220994
221038
  case "pdf":
220995
221039
  case "audio":
220996
221040
  case "video": {
220997
- const contentBuffer = await fs29.promises.readFile(filePath);
221041
+ const contentBuffer = await fs30.promises.readFile(filePath);
220998
221042
  const base64Data = contentBuffer.toString("base64");
220999
221043
  return {
221000
221044
  llmContent: {
@@ -221028,7 +221072,7 @@ async function processSingleFileContent(filePath, rootDirectory, fileSystemServi
221028
221072
  }
221029
221073
  async function fileExists(filePath) {
221030
221074
  try {
221031
- await fsPromises.access(filePath, fs29.constants.F_OK);
221075
+ await fsPromises.access(filePath, fs30.constants.F_OK);
221032
221076
  return true;
221033
221077
  } catch (_) {
221034
221078
  return false;
@@ -231286,18 +231330,18 @@ var init_stdio2 = __esm({
231286
231330
  });
231287
231331
 
231288
231332
  // packages/core/src/ide/ide-client.ts
231289
- import * as fs30 from "node:fs";
231333
+ import * as fs31 from "node:fs";
231290
231334
  import * as os18 from "node:os";
231291
231335
  import * as path33 from "node:path";
231292
231336
  function getRealPath(path110) {
231293
231337
  try {
231294
- return fs30.realpathSync(path110);
231338
+ return fs31.realpathSync(path110);
231295
231339
  } catch (_e) {
231296
231340
  return path110;
231297
231341
  }
231298
231342
  }
231299
231343
  function getIdeServerHost() {
231300
- const isInContainer = fs30.existsSync("/.dockerenv") || fs30.existsSync("/run/.containerenv");
231344
+ const isInContainer = fs31.existsSync("/.dockerenv") || fs31.existsSync("/run/.containerenv");
231301
231345
  return isInContainer ? "host.docker.internal" : "127.0.0.1";
231302
231346
  }
231303
231347
  var import_undici, logger, IdeClient;
@@ -231739,14 +231783,14 @@ var init_ide_client = __esm({
231739
231783
  os18.tmpdir(),
231740
231784
  `qwen-code-ide-server-${this.ideProcessInfo.pid}.json`
231741
231785
  );
231742
- const portFileContents = await fs30.promises.readFile(portFile, "utf8");
231786
+ const portFileContents = await fs31.promises.readFile(portFile, "utf8");
231743
231787
  return JSON.parse(portFileContents);
231744
231788
  } catch (_) {
231745
231789
  }
231746
231790
  const portFileDir = path33.join(os18.tmpdir(), "gemini", "ide");
231747
231791
  let portFiles;
231748
231792
  try {
231749
- portFiles = await fs30.promises.readdir(portFileDir);
231793
+ portFiles = await fs31.promises.readdir(portFileDir);
231750
231794
  } catch (e2) {
231751
231795
  logger.debug("Failed to read IDE connection directory:", e2);
231752
231796
  return void 0;
@@ -231765,7 +231809,7 @@ var init_ide_client = __esm({
231765
231809
  try {
231766
231810
  fileContents = await Promise.all(
231767
231811
  matchingFiles.map(
231768
- (file) => fs30.promises.readFile(path33.join(portFileDir, file), "utf8")
231812
+ (file) => fs31.promises.readFile(path33.join(portFileDir, file), "utf8")
231769
231813
  )
231770
231814
  );
231771
231815
  } catch (e2) {
@@ -231977,7 +232021,7 @@ ${errorMessage}`,
231977
232021
  });
231978
232022
 
231979
232023
  // packages/core/src/tools/edit.ts
231980
- import * as fs31 from "node:fs";
232024
+ import * as fs32 from "node:fs";
231981
232025
  import * as path34 from "node:path";
231982
232026
  function applyReplacement(currentContent, oldString, newString, isNewFile) {
231983
232027
  if (isNewFile) {
@@ -232307,8 +232351,8 @@ var init_edit = __esm({
232307
232351
  */
232308
232352
  ensureParentDirectoriesExist(filePath) {
232309
232353
  const dirName = path34.dirname(filePath);
232310
- if (!fs31.existsSync(dirName)) {
232311
- fs31.mkdirSync(dirName, { recursive: true });
232354
+ if (!fs32.existsSync(dirName)) {
232355
+ fs32.mkdirSync(dirName, { recursive: true });
232312
232356
  }
232313
232357
  }
232314
232358
  };
@@ -232562,7 +232606,7 @@ Eg.
232562
232606
  });
232563
232607
 
232564
232608
  // packages/core/src/tools/glob.ts
232565
- import fs32 from "node:fs";
232609
+ import fs33 from "node:fs";
232566
232610
  import path35 from "node:path";
232567
232611
  function sortFileEntries(entries, nowTimestamp, recencyThresholdMs) {
232568
232612
  const sortedEntries = [...entries];
@@ -232583,7 +232627,7 @@ function sortFileEntries(entries, nowTimestamp, recencyThresholdMs) {
232583
232627
  });
232584
232628
  return sortedEntries;
232585
232629
  }
232586
- var GlobToolInvocation, GlobTool;
232630
+ var MAX_FILE_COUNT, GlobToolInvocation, GlobTool;
232587
232631
  var init_glob2 = __esm({
232588
232632
  "packages/core/src/tools/glob.ts"() {
232589
232633
  "use strict";
@@ -232595,80 +232639,55 @@ var init_glob2 = __esm({
232595
232639
  init_config3();
232596
232640
  init_constants3();
232597
232641
  init_tool_error();
232642
+ init_errors();
232643
+ MAX_FILE_COUNT = 100;
232598
232644
  __name(sortFileEntries, "sortFileEntries");
232599
232645
  GlobToolInvocation = class extends BaseToolInvocation {
232600
232646
  constructor(config, params) {
232601
232647
  super(params);
232602
232648
  this.config = config;
232649
+ this.fileService = config.getFileService();
232603
232650
  }
232604
232651
  static {
232605
232652
  __name(this, "GlobToolInvocation");
232606
232653
  }
232654
+ fileService;
232607
232655
  getDescription() {
232608
232656
  let description = `'${this.params.pattern}'`;
232609
232657
  if (this.params.path) {
232610
- const searchDir = path35.resolve(
232611
- this.config.getTargetDir(),
232612
- this.params.path || "."
232613
- );
232614
- const relativePath = makeRelative(searchDir, this.config.getTargetDir());
232615
- description += ` within ${shortenPath(relativePath)}`;
232658
+ description += ` in path '${this.params.path}'`;
232616
232659
  }
232617
232660
  return description;
232618
232661
  }
232619
232662
  async execute(signal) {
232620
232663
  try {
232621
- const workspaceContext = this.config.getWorkspaceContext();
232622
- const workspaceDirectories = workspaceContext.getDirectories();
232623
- let searchDirectories;
232624
- if (this.params.path) {
232625
- const searchDirAbsolute = path35.resolve(
232626
- this.config.getTargetDir(),
232627
- this.params.path
232628
- );
232629
- if (!workspaceContext.isPathWithinWorkspace(searchDirAbsolute)) {
232630
- const rawError = `Error: Path "${this.params.path}" is not within any workspace directory`;
232631
- return {
232632
- llmContent: rawError,
232633
- returnDisplay: `Path is not within workspace`,
232634
- error: {
232635
- message: rawError,
232636
- type: "path_not_in_workspace" /* PATH_NOT_IN_WORKSPACE */
232637
- }
232638
- };
232639
- }
232640
- searchDirectories = [searchDirAbsolute];
232641
- } else {
232642
- searchDirectories = workspaceDirectories;
232643
- }
232644
- const fileDiscovery = this.config.getFileService();
232645
- const allEntries = [];
232646
- for (const searchDir of searchDirectories) {
232647
- let pattern = this.params.pattern;
232648
- const fullPath = path35.join(searchDir, pattern);
232649
- if (fs32.existsSync(fullPath)) {
232650
- pattern = escape3(pattern);
232651
- }
232652
- const entries = await glob(pattern, {
232653
- cwd: searchDir,
232654
- withFileTypes: true,
232655
- nodir: true,
232656
- stat: true,
232657
- nocase: !this.params.case_sensitive,
232658
- dot: true,
232659
- ignore: this.config.getFileExclusions().getGlobExcludes(),
232660
- follow: false,
232661
- signal
232662
- });
232663
- allEntries.push(...entries);
232664
- }
232664
+ const searchDirAbs = resolveAndValidatePath(
232665
+ this.config,
232666
+ this.params.path
232667
+ );
232668
+ const searchLocationDescription = this.params.path ? `within ${searchDirAbs}` : `in the workspace directory`;
232669
+ let pattern = this.params.pattern;
232670
+ const fullPath = path35.join(searchDirAbs, pattern);
232671
+ if (fs33.existsSync(fullPath)) {
232672
+ pattern = escape3(pattern);
232673
+ }
232674
+ const allEntries = await glob(pattern, {
232675
+ cwd: searchDirAbs,
232676
+ withFileTypes: true,
232677
+ nodir: true,
232678
+ stat: true,
232679
+ nocase: true,
232680
+ dot: true,
232681
+ follow: false,
232682
+ signal
232683
+ });
232665
232684
  const relativePaths = allEntries.map(
232666
232685
  (p) => path35.relative(this.config.getTargetDir(), p.fullpath())
232667
232686
  );
232668
- const { filteredPaths, gitIgnoredCount, qwenIgnoredCount } = fileDiscovery.filterFilesWithReport(relativePaths, {
232669
- respectGitIgnore: this.params?.respect_git_ignore ?? this.config.getFileFilteringOptions().respectGitIgnore ?? DEFAULT_FILE_FILTERING_OPTIONS.respectGitIgnore,
232670
- respectQwenIgnore: this.params?.respect_qwen_ignore ?? this.config.getFileFilteringOptions().respectQwenIgnore ?? DEFAULT_FILE_FILTERING_OPTIONS.respectQwenIgnore
232671
- });
232687
+ const { filteredPaths } = this.fileService.filterFilesWithReport(
232688
+ relativePaths,
232689
+ this.getFileFilteringOptions()
232690
+ );
232672
232691
  const filteredAbsolutePaths = new Set(
232673
232692
  filteredPaths.map((p) => path35.resolve(this.config.getTargetDir(), p))
232674
232693
  );
@@ -232676,20 +232695,8 @@ var init_glob2 = __esm({
232676
232695
  (entry) => filteredAbsolutePaths.has(entry.fullpath())
232677
232696
  );
232678
232697
  if (!filteredEntries || filteredEntries.length === 0) {
232679
- let message = `No files found matching pattern "${this.params.pattern}"`;
232680
- if (searchDirectories.length === 1) {
232681
- message += ` within ${searchDirectories[0]}`;
232682
- } else {
232683
- message += ` within ${searchDirectories.length} workspace directories`;
232684
- }
232685
- if (gitIgnoredCount > 0) {
232686
- message += ` (${gitIgnoredCount} files were git-ignored)`;
232687
- }
232688
- if (qwenIgnoredCount > 0) {
232689
- message += ` (${qwenIgnoredCount} files were rdmind-ignored)`;
232690
- }
232691
232698
  return {
232692
- llmContent: message,
232699
+ llmContent: `No files found matching pattern "${this.params.pattern}" ${searchLocationDescription}`,
232693
232700
  returnDisplay: `No files found`
232694
232701
  };
232695
232702
  }
@@ -232700,28 +232707,27 @@ var init_glob2 = __esm({
232700
232707
  nowTimestamp,
232701
232708
  oneDayInMs
232702
232709
  );
232703
- const sortedAbsolutePaths = sortedEntries.map(
232710
+ const totalFileCount = sortedEntries.length;
232711
+ const truncated = totalFileCount > MAX_FILE_COUNT;
232712
+ const entriesToShow = truncated ? sortedEntries.slice(0, MAX_FILE_COUNT) : sortedEntries;
232713
+ const sortedAbsolutePaths = entriesToShow.map(
232704
232714
  (entry) => entry.fullpath()
232705
232715
  );
232706
232716
  const fileListDescription = sortedAbsolutePaths.join("\n");
232707
- const fileCount = sortedAbsolutePaths.length;
232708
- let resultMessage = `Found ${fileCount} file(s) matching "${this.params.pattern}"`;
232709
- if (searchDirectories.length === 1) {
232710
- resultMessage += ` within ${searchDirectories[0]}`;
232711
- } else {
232712
- resultMessage += ` across ${searchDirectories.length} workspace directories`;
232713
- }
232714
- if (gitIgnoredCount > 0) {
232715
- resultMessage += ` (${gitIgnoredCount} additional files were git-ignored)`;
232716
- }
232717
- if (qwenIgnoredCount > 0) {
232718
- resultMessage += ` (${qwenIgnoredCount} additional files were rdmind-ignored)`;
232719
- }
232717
+ let resultMessage = `Found ${totalFileCount} file(s) matching "${this.params.pattern}" ${searchLocationDescription}`;
232720
232718
  resultMessage += `, sorted by modification time (newest first):
232719
+ ---
232721
232720
  ${fileListDescription}`;
232721
+ if (truncated) {
232722
+ const omittedFiles = totalFileCount - MAX_FILE_COUNT;
232723
+ const fileTerm = omittedFiles === 1 ? "file" : "files";
232724
+ resultMessage += `
232725
+ ---
232726
+ [${omittedFiles} ${fileTerm} truncated] ...`;
232727
+ }
232722
232728
  return {
232723
232729
  llmContent: resultMessage,
232724
- returnDisplay: `Found ${fileCount} matching file(s)`
232730
+ returnDisplay: `Found ${totalFileCount} matching file(s)${truncated ? " (truncated)" : ""}`
232725
232731
  };
232726
232732
  } catch (error) {
232727
232733
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -232729,7 +232735,7 @@ ${fileListDescription}`;
232729
232735
  const rawError = `Error during glob search operation: ${errorMessage}`;
232730
232736
  return {
232731
232737
  llmContent: rawError,
232732
- returnDisplay: `Error: An unexpected error occurred.`,
232738
+ returnDisplay: `Error: ${errorMessage || "An unexpected error occurred."}`,
232733
232739
  error: {
232734
232740
  message: rawError,
232735
232741
  type: "glob_execution_error" /* GLOB_EXECUTION_ERROR */
@@ -232737,35 +232743,30 @@ ${fileListDescription}`;
232737
232743
  };
232738
232744
  }
232739
232745
  }
232746
+ getFileFilteringOptions() {
232747
+ const options2 = this.config.getFileFilteringOptions?.();
232748
+ return {
232749
+ respectGitIgnore: options2?.respectGitIgnore ?? DEFAULT_FILE_FILTERING_OPTIONS.respectGitIgnore,
232750
+ respectQwenIgnore: options2?.respectQwenIgnore ?? DEFAULT_FILE_FILTERING_OPTIONS.respectQwenIgnore
232751
+ };
232752
+ }
232740
232753
  };
232741
232754
  GlobTool = class _GlobTool extends BaseDeclarativeTool {
232742
232755
  constructor(config) {
232743
232756
  super(
232744
232757
  _GlobTool.Name,
232745
232758
  "FindFiles",
232746
- "Efficiently finds files matching specific glob patterns (e.g., `src/**/*.ts`, `**/*.md`), returning absolute paths sorted by modification time (newest first). Ideal for quickly locating files based on their name or path structure, especially in large codebases.",
232759
+ 'Fast file pattern matching tool that works with any codebase size\n- Supports glob patterns like "**/*.js" or "src/**/*.ts"\n- Returns matching file paths sorted by modification time\n- Use this tool when you need to find files by name patterns\n- When you are doing an open ended search that may require multiple rounds of globbing and grepping, use the Agent tool instead\n- You have the capability to call multiple tools in a single response. It is always better to speculatively perform multiple searches as a batch that are potentially useful.',
232747
232760
  "search" /* Search */,
232748
232761
  {
232749
232762
  properties: {
232750
232763
  pattern: {
232751
- description: "The glob pattern to match against (e.g., '**/*.py', 'docs/*.md').",
232764
+ description: "The glob pattern to match files against",
232752
232765
  type: "string"
232753
232766
  },
232754
232767
  path: {
232755
- description: "Optional: The absolute path to the directory to search within. If omitted, searches the root directory.",
232768
+ description: 'The directory to search in. If not specified, the current working directory will be used. IMPORTANT: Omit this field to use the default directory. DO NOT enter "undefined" or "null" - simply omit it for the default behavior. Must be a valid directory path if provided.',
232756
232769
  type: "string"
232757
- },
232758
- case_sensitive: {
232759
- description: "Optional: Whether the search should be case-sensitive. Defaults to false.",
232760
- type: "boolean"
232761
- },
232762
- respect_git_ignore: {
232763
- description: "Optional: Whether to respect .gitignore patterns when finding files. Only available in git repositories. Defaults to true.",
232764
- type: "boolean"
232765
- },
232766
- respect_qwen_ignore: {
232767
- description: "Optional: Whether to respect .rdmindignore patterns when finding files. Defaults to true.",
232768
- type: "boolean"
232769
232770
  }
232770
232771
  },
232771
232772
  required: ["pattern"],
@@ -232782,29 +232783,16 @@ ${fileListDescription}`;
232782
232783
  * Validates the parameters for the tool.
232783
232784
  */
232784
232785
  validateToolParamValues(params) {
232785
- const searchDirAbsolute = path35.resolve(
232786
- this.config.getTargetDir(),
232787
- params.path || "."
232788
- );
232789
- const workspaceContext = this.config.getWorkspaceContext();
232790
- if (!workspaceContext.isPathWithinWorkspace(searchDirAbsolute)) {
232791
- const directories = workspaceContext.getDirectories();
232792
- return `Search path ("${searchDirAbsolute}") resolves outside the allowed workspace directories: ${directories.join(", ")}`;
232793
- }
232794
- const targetDir = searchDirAbsolute || this.config.getTargetDir();
232795
- try {
232796
- if (!fs32.existsSync(targetDir)) {
232797
- return `Search path does not exist ${targetDir}`;
232798
- }
232799
- if (!fs32.statSync(targetDir).isDirectory()) {
232800
- return `Search path is not a directory: ${targetDir}`;
232801
- }
232802
- } catch (e2) {
232803
- return `Error accessing search path: ${e2}`;
232804
- }
232805
232786
  if (!params.pattern || typeof params.pattern !== "string" || params.pattern.trim() === "") {
232806
232787
  return "The 'pattern' parameter cannot be empty.";
232807
232788
  }
232789
+ if (params.path) {
232790
+ try {
232791
+ resolveAndValidatePath(this.config, params.path);
232792
+ } catch (error) {
232793
+ return getErrorMessage(error);
232794
+ }
232795
+ }
232808
232796
  return null;
232809
232797
  }
232810
232798
  createInvocation(params) {
@@ -232815,12 +232803,11 @@ ${fileListDescription}`;
232815
232803
  });
232816
232804
 
232817
232805
  // packages/core/src/tools/grep.ts
232818
- import fs33 from "node:fs";
232819
232806
  import fsPromises2 from "node:fs/promises";
232820
232807
  import path36 from "node:path";
232821
232808
  import { EOL as EOL2 } from "node:os";
232822
232809
  import { spawn as spawn5 } from "node:child_process";
232823
- var GrepToolInvocation, GrepTool;
232810
+ var MAX_LLM_CONTENT_LENGTH, GrepToolInvocation, GrepTool;
232824
232811
  var init_grep2 = __esm({
232825
232812
  "packages/core/src/tools/grep.ts"() {
232826
232813
  "use strict";
@@ -232832,6 +232819,7 @@ var init_grep2 = __esm({
232832
232819
  init_errors();
232833
232820
  init_gitUtils();
232834
232821
  init_tool_error();
232822
+ MAX_LLM_CONTENT_LENGTH = 2e4;
232835
232823
  GrepToolInvocation = class extends BaseToolInvocation {
232836
232824
  constructor(config, params) {
232837
232825
  super(params);
@@ -232842,93 +232830,37 @@ var init_grep2 = __esm({
232842
232830
  __name(this, "GrepToolInvocation");
232843
232831
  }
232844
232832
  fileExclusions;
232845
- /**
232846
- * Checks if a path is within the root directory and resolves it.
232847
- * @param relativePath Path relative to the root directory (or undefined for root).
232848
- * @returns The absolute path if valid and exists, or null if no path specified (to search all directories).
232849
- * @throws {Error} If path is outside root, doesn't exist, or isn't a directory.
232850
- */
232851
- resolveAndValidatePath(relativePath) {
232852
- if (!relativePath) {
232853
- return null;
232854
- }
232855
- const targetPath = path36.resolve(this.config.getTargetDir(), relativePath);
232856
- const workspaceContext = this.config.getWorkspaceContext();
232857
- if (!workspaceContext.isPathWithinWorkspace(targetPath)) {
232858
- const directories = workspaceContext.getDirectories();
232859
- throw new Error(
232860
- `Path validation failed: Attempted path "${relativePath}" resolves outside the allowed workspace directories: ${directories.join(", ")}`
232861
- );
232862
- }
232863
- try {
232864
- const stats = fs33.statSync(targetPath);
232865
- if (!stats.isDirectory()) {
232866
- throw new Error(`Path is not a directory: ${targetPath}`);
232867
- }
232868
- } catch (error) {
232869
- if (isNodeError(error) && error.code !== "ENOENT") {
232870
- throw new Error(`Path does not exist: ${targetPath}`);
232871
- }
232872
- throw new Error(
232873
- `Failed to access path stats for ${targetPath}: ${error}`
232874
- );
232875
- }
232876
- return targetPath;
232877
- }
232878
232833
  async execute(signal) {
232879
232834
  try {
232880
- const workspaceContext = this.config.getWorkspaceContext();
232881
- const searchDirAbs = this.resolveAndValidatePath(this.params.path);
232835
+ const searchDirAbs = resolveAndValidatePath(
232836
+ this.config,
232837
+ this.params.path
232838
+ );
232882
232839
  const searchDirDisplay = this.params.path || ".";
232883
- let searchDirectories;
232884
- if (searchDirAbs === null) {
232885
- searchDirectories = workspaceContext.getDirectories();
232886
- } else {
232887
- searchDirectories = [searchDirAbs];
232888
- }
232889
- let allMatches = [];
232890
- const maxResults = this.params.maxResults ?? 20;
232891
- let totalMatchesFound = 0;
232892
- let searchTruncated = false;
232893
- for (const searchDir of searchDirectories) {
232894
- const matches = await this.performGrepSearch({
232895
- pattern: this.params.pattern,
232896
- path: searchDir,
232897
- include: this.params.include,
232898
- signal
232899
- });
232900
- totalMatchesFound += matches.length;
232901
- if (searchDirectories.length > 1) {
232902
- const dirName = path36.basename(searchDir);
232903
- matches.forEach((match2) => {
232904
- match2.filePath = path36.join(dirName, match2.filePath);
232905
- });
232906
- }
232907
- const remainingSlots = maxResults - allMatches.length;
232908
- if (remainingSlots <= 0) {
232909
- searchTruncated = true;
232910
- break;
232911
- }
232912
- if (matches.length > remainingSlots) {
232913
- allMatches = allMatches.concat(matches.slice(0, remainingSlots));
232914
- searchTruncated = true;
232915
- break;
232916
- } else {
232917
- allMatches = allMatches.concat(matches);
232918
- }
232919
- }
232920
- let searchLocationDescription;
232921
- if (searchDirAbs === null) {
232922
- const numDirs = workspaceContext.getDirectories().length;
232923
- searchLocationDescription = numDirs > 1 ? `across ${numDirs} workspace directories` : `in the workspace directory`;
232924
- } else {
232925
- searchLocationDescription = `in path "${searchDirDisplay}"`;
232926
- }
232927
- if (allMatches.length === 0) {
232928
- const noMatchMsg = `No matches found for pattern "${this.params.pattern}" ${searchLocationDescription}${this.params.include ? ` (filter: "${this.params.include}")` : ""}.`;
232840
+ const rawMatches = await this.performGrepSearch({
232841
+ pattern: this.params.pattern,
232842
+ path: searchDirAbs,
232843
+ glob: this.params.glob,
232844
+ signal
232845
+ });
232846
+ const searchLocationDescription = this.params.path ? `in path "${searchDirDisplay}"` : `in the workspace directory`;
232847
+ const filterDescription = this.params.glob ? ` (filter: "${this.params.glob}")` : "";
232848
+ if (rawMatches.length === 0) {
232849
+ const noMatchMsg = `No matches found for pattern "${this.params.pattern}" ${searchLocationDescription}${filterDescription}.`;
232929
232850
  return { llmContent: noMatchMsg, returnDisplay: `No matches found` };
232930
232851
  }
232931
- const matchesByFile = allMatches.reduce(
232852
+ let truncatedByLineLimit = false;
232853
+ let matchesToInclude = rawMatches;
232854
+ if (this.params.limit !== void 0 && rawMatches.length > this.params.limit) {
232855
+ matchesToInclude = rawMatches.slice(0, this.params.limit);
232856
+ truncatedByLineLimit = true;
232857
+ }
232858
+ const totalMatches = rawMatches.length;
232859
+ const matchTerm = totalMatches === 1 ? "match" : "matches";
232860
+ const header = `Found ${totalMatches} ${matchTerm} for pattern "${this.params.pattern}" ${searchLocationDescription}${filterDescription}:
232861
+ ---
232862
+ `;
232863
+ const matchesByFile = matchesToInclude.reduce(
232932
232864
  (acc, match2) => {
232933
232865
  const fileKey = match2.filePath;
232934
232866
  if (!acc[fileKey]) {
@@ -232940,40 +232872,38 @@ var init_grep2 = __esm({
232940
232872
  },
232941
232873
  {}
232942
232874
  );
232943
- const matchCount = allMatches.length;
232944
- const matchTerm = matchCount === 1 ? "match" : "matches";
232945
- let headerText = `Found ${matchCount} ${matchTerm} for pattern "${this.params.pattern}" ${searchLocationDescription}${this.params.include ? ` (filter: "${this.params.include}")` : ""}`;
232946
- if (searchTruncated) {
232947
- headerText += ` (showing first ${matchCount} of ${totalMatchesFound}+ total matches)`;
232948
- }
232949
- let llmContent = `${headerText}:
232950
- ---
232951
- `;
232875
+ let grepOutput = "";
232952
232876
  for (const filePath in matchesByFile) {
232953
- llmContent += `File: ${filePath}
232877
+ grepOutput += `File: ${filePath}
232954
232878
  `;
232955
232879
  matchesByFile[filePath].forEach((match2) => {
232956
232880
  const trimmedLine = match2.line.trim();
232957
- llmContent += `L${match2.lineNumber}: ${trimmedLine}
232881
+ grepOutput += `L${match2.lineNumber}: ${trimmedLine}
232958
232882
  `;
232959
232883
  });
232960
- llmContent += "---\n";
232884
+ grepOutput += "---\n";
232961
232885
  }
232962
- if (searchTruncated) {
232963
- llmContent += `
232964
- WARNING: Results truncated to prevent context overflow. To see more results:
232965
- - Use a more specific pattern to reduce matches
232966
- - Add file filters with the 'include' parameter (e.g., "*.js", "src/**")
232967
- - Specify a narrower 'path' to search in a subdirectory
232968
- - Increase 'maxResults' parameter if you need more matches (current: ${maxResults})`;
232886
+ let truncatedByCharLimit = false;
232887
+ if (grepOutput.length > MAX_LLM_CONTENT_LENGTH) {
232888
+ grepOutput = grepOutput.slice(0, MAX_LLM_CONTENT_LENGTH) + "...";
232889
+ truncatedByCharLimit = true;
232890
+ }
232891
+ const finalLines = grepOutput.split("\n").filter(
232892
+ (line) => line.trim() && !line.startsWith("File:") && !line.startsWith("---")
232893
+ );
232894
+ const includedLines = finalLines.length;
232895
+ let llmContent = header + grepOutput;
232896
+ if (truncatedByLineLimit || truncatedByCharLimit) {
232897
+ const omittedMatches = totalMatches - includedLines;
232898
+ llmContent += ` [${omittedMatches} ${omittedMatches === 1 ? "line" : "lines"} truncated] ...`;
232969
232899
  }
232970
- let displayText = `Found ${matchCount} ${matchTerm}`;
232971
- if (searchTruncated) {
232972
- displayText += ` (truncated from ${totalMatchesFound}+)`;
232900
+ let displayMessage = `Found ${totalMatches} ${matchTerm}`;
232901
+ if (truncatedByLineLimit || truncatedByCharLimit) {
232902
+ displayMessage += ` (truncated)`;
232973
232903
  }
232974
232904
  return {
232975
232905
  llmContent: llmContent.trim(),
232976
- returnDisplay: displayText
232906
+ returnDisplay: displayMessage
232977
232907
  };
232978
232908
  } catch (error) {
232979
232909
  console.error(`Error during GrepLogic execution: ${error}`);
@@ -233051,40 +232981,19 @@ WARNING: Results truncated to prevent context overflow. To see more results:
233051
232981
  * @returns A string describing the grep
233052
232982
  */
233053
232983
  getDescription() {
233054
- let description = `'${this.params.pattern}'`;
233055
- if (this.params.include) {
233056
- description += ` in ${this.params.include}`;
233057
- }
233058
- if (this.params.path) {
233059
- const resolvedPath = path36.resolve(
233060
- this.config.getTargetDir(),
233061
- this.params.path
233062
- );
233063
- if (resolvedPath === this.config.getTargetDir() || this.params.path === ".") {
233064
- description += ` within ./`;
233065
- } else {
233066
- const relativePath = makeRelative(
233067
- resolvedPath,
233068
- this.config.getTargetDir()
233069
- );
233070
- description += ` within ${shortenPath(relativePath)}`;
233071
- }
233072
- } else {
233073
- const workspaceContext = this.config.getWorkspaceContext();
233074
- const directories = workspaceContext.getDirectories();
233075
- if (directories.length > 1) {
233076
- description += ` across all workspace directories`;
233077
- }
232984
+ let description = `'${this.params.pattern}' in path '${this.params.path || "./"}'`;
232985
+ if (this.params.glob) {
232986
+ description += ` (filter: '${this.params.glob}')`;
233078
232987
  }
233079
232988
  return description;
233080
232989
  }
233081
232990
  /**
233082
232991
  * Performs the actual search using the prioritized strategies.
233083
- * @param options Search options including pattern, absolute path, and include glob.
232992
+ * @param options Search options including pattern, absolute path, and glob filter.
233084
232993
  * @returns A promise resolving to an array of match objects.
233085
232994
  */
233086
232995
  async performGrepSearch(options2) {
233087
- const { pattern, path: absolutePath, include } = options2;
232996
+ const { pattern, path: absolutePath, glob: glob2 } = options2;
233088
232997
  let strategyUsed = "none";
233089
232998
  try {
233090
232999
  const isGit = isGitRepository(absolutePath);
@@ -233099,8 +233008,8 @@ WARNING: Results truncated to prevent context overflow. To see more results:
233099
233008
  "--ignore-case",
233100
233009
  pattern
233101
233010
  ];
233102
- if (include) {
233103
- gitArgs.push("--", include);
233011
+ if (glob2) {
233012
+ gitArgs.push("--", glob2);
233104
233013
  }
233105
233014
  try {
233106
233015
  const output = await new Promise((resolve26, reject) => {
@@ -233158,8 +233067,8 @@ WARNING: Results truncated to prevent context overflow. To see more results:
233158
233067
  return null;
233159
233068
  }).filter((dir) => !!dir);
233160
233069
  commonExcludes.forEach((dir) => grepArgs.push(`--exclude-dir=${dir}`));
233161
- if (include) {
233162
- grepArgs.push(`--include=${include}`);
233070
+ if (glob2) {
233071
+ grepArgs.push(`--include=${glob2}`);
233163
233072
  }
233164
233073
  grepArgs.push(pattern);
233165
233074
  grepArgs.push(".");
@@ -233226,7 +233135,7 @@ WARNING: Results truncated to prevent context overflow. To see more results:
233226
233135
  "GrepLogic: Falling back to JavaScript grep implementation."
233227
233136
  );
233228
233137
  strategyUsed = "javascript fallback";
233229
- const globPattern = include ? include : "**/*";
233138
+ const globPattern = glob2 ? glob2 : "**/*";
233230
233139
  const ignorePatterns = this.fileExclusions.getGlobExcludes();
233231
233140
  const filesIterator = globStream(globPattern, {
233232
233141
  cwd: absolutePath,
@@ -233277,28 +233186,26 @@ WARNING: Results truncated to prevent context overflow. To see more results:
233277
233186
  constructor(config) {
233278
233187
  super(
233279
233188
  _GrepTool.Name,
233280
- "SearchText",
233281
- "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.",
233189
+ "Grep",
233190
+ 'A powerful search tool for finding patterns in files\n\n Usage:\n - ALWAYS use Grep for search tasks. NEVER invoke `grep` or `rg` as a Bash command. The Grep tool has been optimized for correct permissions and access.\n - Supports full regex syntax (e.g., "log.*Error", "function\\s+\\w+")\n - Filter files with glob parameter (e.g., "*.js", "**/*.tsx")\n - Case-insensitive by default\n - Use Task tool for open-ended searches requiring multiple rounds\n',
233282
233191
  "search" /* Search */,
233283
233192
  {
233284
233193
  properties: {
233285
233194
  pattern: {
233286
- description: "The regular expression (regex) pattern to search for within file contents (e.g., 'function\\s+myFunction', 'import\\s+\\{.*\\}\\s+from\\s+.*').",
233287
- type: "string"
233195
+ type: "string",
233196
+ description: "The regular expression pattern to search for in file contents"
233288
233197
  },
233289
- path: {
233290
- description: "Optional: The absolute path to the directory to search within. If omitted, searches the current working directory.",
233291
- type: "string"
233198
+ glob: {
233199
+ type: "string",
233200
+ description: 'Glob pattern to filter files (e.g. "*.js", "*.{ts,tsx}")'
233292
233201
  },
233293
- include: {
233294
- 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).",
233295
- type: "string"
233202
+ path: {
233203
+ type: "string",
233204
+ description: "File or directory to search in. Defaults to current working directory."
233296
233205
  },
233297
- maxResults: {
233298
- description: "Optional: Maximum number of matches to return to prevent context overflow (default: 20, max: 100). Use lower values for broad searches, higher for specific searches.",
233206
+ limit: {
233299
233207
  type: "number",
233300
- minimum: 1,
233301
- maximum: 100
233208
+ description: "Limit output to first N matching lines. Optional - shows all matches if not specified."
233302
233209
  }
233303
233210
  },
233304
233211
  required: ["pattern"],
@@ -233311,39 +233218,6 @@ WARNING: Results truncated to prevent context overflow. To see more results:
233311
233218
  __name(this, "GrepTool");
233312
233219
  }
233313
233220
  static Name = ToolNames.GREP;
233314
- /**
233315
- * Checks if a path is within the root directory and resolves it.
233316
- * @param relativePath Path relative to the root directory (or undefined for root).
233317
- * @returns The absolute path if valid and exists, or null if no path specified (to search all directories).
233318
- * @throws {Error} If path is outside root, doesn't exist, or isn't a directory.
233319
- */
233320
- resolveAndValidatePath(relativePath) {
233321
- if (!relativePath) {
233322
- return null;
233323
- }
233324
- const targetPath = path36.resolve(this.config.getTargetDir(), relativePath);
233325
- const workspaceContext = this.config.getWorkspaceContext();
233326
- if (!workspaceContext.isPathWithinWorkspace(targetPath)) {
233327
- const directories = workspaceContext.getDirectories();
233328
- throw new Error(
233329
- `Path validation failed: Attempted path "${relativePath}" resolves outside the allowed workspace directories: ${directories.join(", ")}`
233330
- );
233331
- }
233332
- try {
233333
- const stats = fs33.statSync(targetPath);
233334
- if (!stats.isDirectory()) {
233335
- throw new Error(`Path is not a directory: ${targetPath}`);
233336
- }
233337
- } catch (error) {
233338
- if (isNodeError(error) && error.code !== "ENOENT") {
233339
- throw new Error(`Path does not exist: ${targetPath}`);
233340
- }
233341
- throw new Error(
233342
- `Failed to access path stats for ${targetPath}: ${error}`
233343
- );
233344
- }
233345
- return targetPath;
233346
- }
233347
233221
  /**
233348
233222
  * Validates the parameters for the tool
233349
233223
  * @param params Parameters to validate
@@ -233353,16 +233227,11 @@ WARNING: Results truncated to prevent context overflow. To see more results:
233353
233227
  try {
233354
233228
  new RegExp(params.pattern);
233355
233229
  } catch (error) {
233356
- return `Invalid regular expression pattern provided: ${params.pattern}. Error: ${getErrorMessage(error)}`;
233357
- }
233358
- if (params.maxResults !== void 0) {
233359
- if (!Number.isInteger(params.maxResults) || params.maxResults < 1 || params.maxResults > 100) {
233360
- return `maxResults must be an integer between 1 and 100, got: ${params.maxResults}`;
233361
- }
233230
+ return `Invalid regular expression pattern: ${params.pattern}. Error: ${getErrorMessage(error)}`;
233362
233231
  }
233363
233232
  if (params.path) {
233364
233233
  try {
233365
- this.resolveAndValidatePath(params.path);
233234
+ resolveAndValidatePath(this.config, params.path);
233366
233235
  } catch (error) {
233367
233236
  return getErrorMessage(error);
233368
233237
  }
@@ -234114,7 +233983,7 @@ import fs36 from "node:fs";
234114
233983
  import path40 from "node:path";
234115
233984
  import { EOL as EOL3 } from "node:os";
234116
233985
  import { spawn as spawn6 } from "node:child_process";
234117
- var MAX_LLM_CONTENT_LENGTH, GrepToolInvocation2, RipGrepTool;
233986
+ var MAX_LLM_CONTENT_LENGTH2, GrepToolInvocation2, RipGrepTool;
234118
233987
  var init_ripGrep = __esm({
234119
233988
  "packages/core/src/tools/ripGrep.ts"() {
234120
233989
  "use strict";
@@ -234126,7 +233995,7 @@ var init_ripGrep = __esm({
234126
233995
  init_ripgrepUtils();
234127
233996
  init_schemaValidator();
234128
233997
  init_constants3();
234129
- MAX_LLM_CONTENT_LENGTH = 2e4;
233998
+ MAX_LLM_CONTENT_LENGTH2 = 2e4;
234130
233999
  GrepToolInvocation2 = class extends BaseToolInvocation {
234131
234000
  constructor(config, params) {
234132
234001
  super(params);
@@ -234135,43 +234004,13 @@ var init_ripGrep = __esm({
234135
234004
  static {
234136
234005
  __name(this, "GrepToolInvocation");
234137
234006
  }
234138
- /**
234139
- * Checks if a path is within the root directory and resolves it.
234140
- * @param relativePath Path relative to the root directory (or undefined for root).
234141
- * @returns The absolute path to search within.
234142
- * @throws {Error} If path is outside root, doesn't exist, or isn't a directory.
234143
- */
234144
- resolveAndValidatePath(relativePath) {
234145
- const targetDir = this.config.getTargetDir();
234146
- const targetPath = relativePath ? path40.resolve(targetDir, relativePath) : targetDir;
234147
- const workspaceContext = this.config.getWorkspaceContext();
234148
- if (!workspaceContext.isPathWithinWorkspace(targetPath)) {
234149
- const directories = workspaceContext.getDirectories();
234150
- throw new Error(
234151
- `Path validation failed: Attempted path "${relativePath}" resolves outside the allowed workspace directories: ${directories.join(", ")}`
234152
- );
234153
- }
234154
- return this.ensureDirectory(targetPath);
234155
- }
234156
- ensureDirectory(targetPath) {
234157
- try {
234158
- const stats = fs36.statSync(targetPath);
234159
- if (!stats.isDirectory()) {
234160
- throw new Error(`Path is not a directory: ${targetPath}`);
234161
- }
234162
- } catch (error) {
234163
- if (isNodeError(error) && error.code !== "ENOENT") {
234164
- throw new Error(`Path does not exist: ${targetPath}`);
234165
- }
234166
- throw new Error(
234167
- `Failed to access path stats for ${targetPath}: ${error}`
234168
- );
234169
- }
234170
- return targetPath;
234171
- }
234172
234007
  async execute(signal) {
234173
234008
  try {
234174
- const searchDirAbs = this.resolveAndValidatePath(this.params.path);
234009
+ const searchDirAbs = resolveAndValidatePath(
234010
+ this.config,
234011
+ this.params.path,
234012
+ { allowFiles: true }
234013
+ );
234175
234014
  const searchDirDisplay = this.params.path || ".";
234176
234015
  const rawOutput = await this.performRipgrepSearch({
234177
234016
  pattern: this.params.pattern,
@@ -234191,26 +234030,39 @@ var init_ripGrep = __esm({
234191
234030
  const header = `Found ${totalMatches} ${matchTerm} for pattern "${this.params.pattern}" ${searchLocationDescription}${filterDescription}:
234192
234031
  ---
234193
234032
  `;
234194
- const maxTruncationNoticeLength = 100;
234195
- const maxGrepOutputLength = MAX_LLM_CONTENT_LENGTH - header.length - maxTruncationNoticeLength;
234196
234033
  let truncatedByLineLimit = false;
234197
234034
  let linesToInclude = allLines;
234198
234035
  if (this.params.limit !== void 0 && allLines.length > this.params.limit) {
234199
234036
  linesToInclude = allLines.slice(0, this.params.limit);
234200
234037
  truncatedByLineLimit = true;
234201
234038
  }
234202
- let grepOutput = linesToInclude.join(EOL3);
234039
+ const parts = [];
234040
+ let includedLines = 0;
234203
234041
  let truncatedByCharLimit = false;
234204
- if (grepOutput.length > maxGrepOutputLength) {
234205
- grepOutput = grepOutput.slice(0, maxGrepOutputLength) + "...";
234206
- truncatedByCharLimit = true;
234042
+ let currentLength = 0;
234043
+ for (const line of linesToInclude) {
234044
+ const sep7 = includedLines > 0 ? 1 : 0;
234045
+ includedLines++;
234046
+ if (currentLength + line.length <= MAX_LLM_CONTENT_LENGTH2) {
234047
+ parts.push(line);
234048
+ currentLength = currentLength + line.length + sep7;
234049
+ } else {
234050
+ const remaining = Math.max(
234051
+ MAX_LLM_CONTENT_LENGTH2 - currentLength - sep7,
234052
+ 10
234053
+ );
234054
+ parts.push(line.slice(0, remaining) + "...");
234055
+ truncatedByCharLimit = true;
234056
+ break;
234057
+ }
234207
234058
  }
234208
- const finalLines = grepOutput.split(EOL3).filter((line) => line.trim());
234209
- const includedLines = finalLines.length;
234059
+ const grepOutput = parts.join("\n");
234210
234060
  let llmContent = header + grepOutput;
234211
234061
  if (truncatedByLineLimit || truncatedByCharLimit) {
234212
234062
  const omittedMatches = totalMatches - includedLines;
234213
- llmContent += ` [${omittedMatches} ${omittedMatches === 1 ? "line" : "lines"} truncated] ...`;
234063
+ llmContent += `
234064
+ ---
234065
+ [${omittedMatches} ${omittedMatches === 1 ? "line" : "lines"} truncated] ...`;
234214
234066
  }
234215
234067
  let displayMessage = `Found ${totalMatches} ${matchTerm}`;
234216
234068
  if (truncatedByLineLimit || truncatedByCharLimit) {
@@ -234311,29 +234163,11 @@ var init_ripGrep = __esm({
234311
234163
  */
234312
234164
  getDescription() {
234313
234165
  let description = `'${this.params.pattern}'`;
234314
- if (this.params.glob) {
234315
- description += ` in ${this.params.glob}`;
234316
- }
234317
234166
  if (this.params.path) {
234318
- const resolvedPath = path40.resolve(
234319
- this.config.getTargetDir(),
234320
- this.params.path
234321
- );
234322
- if (resolvedPath === this.config.getTargetDir() || this.params.path === ".") {
234323
- description += ` within ./`;
234324
- } else {
234325
- const relativePath = makeRelative(
234326
- resolvedPath,
234327
- this.config.getTargetDir()
234328
- );
234329
- description += ` within ${shortenPath(relativePath)}`;
234330
- }
234331
- } else {
234332
- const workspaceContext = this.config.getWorkspaceContext();
234333
- const directories = workspaceContext.getDirectories();
234334
- if (directories.length > 1) {
234335
- description += ` across all workspace directories`;
234336
- }
234167
+ description += ` in path '${this.params.path}'`;
234168
+ }
234169
+ if (this.params.glob) {
234170
+ description += ` (filter: '${this.params.glob}')`;
234337
234171
  }
234338
234172
  return description;
234339
234173
  }
@@ -234374,39 +234208,6 @@ var init_ripGrep = __esm({
234374
234208
  __name(this, "RipGrepTool");
234375
234209
  }
234376
234210
  static Name = ToolNames.GREP;
234377
- /**
234378
- * Checks if a path is within the root directory and resolves it.
234379
- * @param relativePath Path relative to the root directory (or undefined for root).
234380
- * @returns The absolute path to search within.
234381
- * @throws {Error} If path is outside root, doesn't exist, or isn't a directory.
234382
- */
234383
- resolveAndValidatePath(relativePath) {
234384
- if (!relativePath) {
234385
- return this.config.getTargetDir();
234386
- }
234387
- const targetPath = path40.resolve(this.config.getTargetDir(), relativePath);
234388
- const workspaceContext = this.config.getWorkspaceContext();
234389
- if (!workspaceContext.isPathWithinWorkspace(targetPath)) {
234390
- const directories = workspaceContext.getDirectories();
234391
- throw new Error(
234392
- `Path validation failed: Attempted path "${relativePath}" resolves outside the allowed workspace directories: ${directories.join(", ")}`
234393
- );
234394
- }
234395
- try {
234396
- const stats = fs36.statSync(targetPath);
234397
- if (!stats.isDirectory()) {
234398
- throw new Error(`Path is not a directory: ${targetPath}`);
234399
- }
234400
- } catch (error) {
234401
- if (isNodeError(error) && error.code !== "ENOENT") {
234402
- throw new Error(`Path does not exist: ${targetPath}`);
234403
- }
234404
- throw new Error(
234405
- `Failed to access path stats for ${targetPath}: ${error}`
234406
- );
234407
- }
234408
- return targetPath;
234409
- }
234410
234211
  /**
234411
234212
  * Validates the parameters for the tool
234412
234213
  * @param params Parameters to validate
@@ -234427,7 +234228,7 @@ var init_ripGrep = __esm({
234427
234228
  }
234428
234229
  if (params.path) {
234429
234230
  try {
234430
- this.resolveAndValidatePath(params.path);
234231
+ resolveAndValidatePath(this.config, params.path, { allowFiles: true });
234431
234232
  } catch (error) {
234432
234233
  return getErrorMessage(error);
234433
234234
  }
@@ -320370,7 +320171,7 @@ init_esbuild_shims();
320370
320171
 
320371
320172
  // packages/cli/src/generated/git-commit.ts
320372
320173
  init_esbuild_shims();
320373
- var GIT_COMMIT_INFO2 = "db4821fe";
320174
+ var GIT_COMMIT_INFO2 = "b7098a68";
320374
320175
 
320375
320176
  // packages/cli/src/ui/components/AboutBox.tsx
320376
320177
  var import_jsx_runtime43 = __toESM(require_jsx_runtime(), 1);
@@ -342283,7 +342084,7 @@ import { homedir as homedir16 } from "node:os";
342283
342084
  init_esbuild_shims();
342284
342085
  import * as os26 from "node:os";
342285
342086
  import * as path77 from "node:path";
342286
- function resolvePath(p) {
342087
+ function resolvePath2(p) {
342287
342088
  if (!p) {
342288
342089
  return "";
342289
342090
  }
@@ -342295,7 +342096,7 @@ function resolvePath(p) {
342295
342096
  }
342296
342097
  return path77.normalize(expandedPath);
342297
342098
  }
342298
- __name(resolvePath, "resolvePath");
342099
+ __name(resolvePath2, "resolvePath");
342299
342100
 
342300
342101
  // packages/cli/src/utils/version.ts
342301
342102
  init_esbuild_shims();
@@ -342531,7 +342332,7 @@ __name(getPackageJson, "getPackageJson");
342531
342332
  // packages/cli/src/utils/version.ts
342532
342333
  async function getCliVersion() {
342533
342334
  const pkgJson = await getPackageJson();
342534
- return "0.0.22-alpha.0";
342335
+ return "0.0.23-alpha.0";
342535
342336
  }
342536
342337
  __name(getCliVersion, "getCliVersion");
342537
342338
 
@@ -343333,7 +343134,7 @@ async function loadCliConfig(settings, extensions, extensionEnablementManager, s
343333
343134
  ...DEFAULT_MEMORY_FILE_FILTERING_OPTIONS,
343334
343135
  ...settings.context?.fileFiltering
343335
343136
  };
343336
- const includeDirectories = (settings.context?.includeDirectories || []).map(resolvePath).concat((argv.includeDirectories || []).map(resolvePath));
343137
+ const includeDirectories = (settings.context?.includeDirectories || []).map(resolvePath2).concat((argv.includeDirectories || []).map(resolvePath2));
343337
343138
  const { memoryContent, fileCount } = await loadHierarchicalGeminiMemory(
343338
343139
  cwd7,
343339
343140
  settings.context?.loadMemoryFromIncludeDirectories ? includeDirectories : [],