snow-ai 0.6.66 → 0.6.67

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/bundle/cli.mjs CHANGED
@@ -354477,11 +354477,6 @@ async function processWithConcurrency(items, processor, concurrency = 10) {
354477
354477
  await Promise.all(workers);
354478
354478
  return results;
354479
354479
  }
354480
- function createTimeoutPromise(ms, message) {
354481
- return new Promise((_3, reject2) => {
354482
- setTimeout(() => reject2(new Error(message)), ms);
354483
- });
354484
- }
354485
354480
  var init_search_utils = __esm({
354486
354481
  "dist/mcp/utils/aceCodeSearch/search.utils.js"() {
354487
354482
  "use strict";
@@ -354489,7 +354484,7 @@ var init_search_utils = __esm({
354489
354484
  });
354490
354485
 
354491
354486
  // dist/mcp/utils/aceCodeSearch/constants.utils.js
354492
- var INDEX_CACHE_DURATION, BATCH_SIZE, BINARY_EXTENSIONS, RECENT_FILE_THRESHOLD, MAX_INDEXED_FILES, MAX_SYMBOLS_PER_FILE, MAX_FZF_SYMBOL_NAMES, LARGE_FILE_THRESHOLD, FILE_READ_CHUNK_SIZE, TEXT_SEARCH_TIMEOUT_MS, MAX_CONCURRENT_FILE_READS, MAX_REGEX_COMPLEXITY_SCORE;
354487
+ var INDEX_CACHE_DURATION, BATCH_SIZE, BINARY_EXTENSIONS, GREP_EXCLUDE_DIRS, RECENT_FILE_THRESHOLD, MAX_FILE_STAT_CACHE_SIZE, ACE_IDLE_CLEANUP_MS, MAX_INDEXED_FILES, MAX_SYMBOLS_PER_FILE, MAX_FZF_SYMBOL_NAMES, LARGE_FILE_THRESHOLD, FILE_READ_CHUNK_SIZE, TEXT_SEARCH_TIMEOUT_MS, MAX_CONCURRENT_FILE_READS, MAX_REGEX_COMPLEXITY_SCORE;
354493
354488
  var init_constants_utils = __esm({
354494
354489
  "dist/mcp/utils/aceCodeSearch/constants.utils.js"() {
354495
354490
  "use strict";
@@ -354528,7 +354523,20 @@ var init_constants_utils = __esm({
354528
354523
  ".a",
354529
354524
  ".lib"
354530
354525
  ]);
354526
+ GREP_EXCLUDE_DIRS = [
354527
+ "node_modules",
354528
+ ".git",
354529
+ "dist",
354530
+ "build",
354531
+ "__pycache__",
354532
+ "target",
354533
+ ".next",
354534
+ ".nuxt",
354535
+ "coverage"
354536
+ ];
354531
354537
  RECENT_FILE_THRESHOLD = 24 * 60 * 60 * 1e3;
354538
+ MAX_FILE_STAT_CACHE_SIZE = 500;
354539
+ ACE_IDLE_CLEANUP_MS = 2 * 60 * 1e3;
354532
354540
  MAX_INDEXED_FILES = 2e3;
354533
354541
  MAX_SYMBOLS_PER_FILE = 100;
354534
354542
  MAX_FZF_SYMBOL_NAMES = 3e4;
@@ -354560,18 +354568,7 @@ var init_aceCodeSearch = __esm({
354560
354568
  init_search_utils();
354561
354569
  init_constants_utils();
354562
354570
  ACECodeSearchService = class _ACECodeSearchService {
354563
- async withIndexBuildLock(fn) {
354564
- const next = this.indexBuildQueue.then(fn, fn);
354565
- this.indexBuildQueue = next.then(() => void 0, () => void 0);
354566
- return next;
354567
- }
354568
- markIndexTruncated(message) {
354569
- if (!this.isIndexTruncated) {
354570
- logger.warn(message);
354571
- }
354572
- this.isIndexTruncated = true;
354573
- }
354574
- constructor(basePath = process.cwd()) {
354571
+ constructor(basePath = process.cwd(), options3) {
354575
354572
  Object.defineProperty(this, "basePath", {
354576
354573
  enumerable: true,
354577
354574
  configurable: true,
@@ -354662,7 +354659,106 @@ var init_aceCodeSearch = __esm({
354662
354659
  writable: true,
354663
354660
  value: /* @__PURE__ */ new Map()
354664
354661
  });
354662
+ Object.defineProperty(this, "idleCleanupTimer", {
354663
+ enumerable: true,
354664
+ configurable: true,
354665
+ writable: true,
354666
+ value: void 0
354667
+ });
354668
+ Object.defineProperty(this, "isDisposed", {
354669
+ enumerable: true,
354670
+ configurable: true,
354671
+ writable: true,
354672
+ value: false
354673
+ });
354674
+ Object.defineProperty(this, "idleCleanupMs", {
354675
+ enumerable: true,
354676
+ configurable: true,
354677
+ writable: true,
354678
+ value: void 0
354679
+ });
354665
354680
  this.basePath = path24.resolve(basePath);
354681
+ this.idleCleanupMs = (options3 == null ? void 0 : options3.idleCleanupMs) ?? ACE_IDLE_CLEANUP_MS;
354682
+ this.scheduleIdleCleanup();
354683
+ }
354684
+ async withIndexBuildLock(fn) {
354685
+ const next = this.indexBuildQueue.then(fn, fn);
354686
+ this.indexBuildQueue = next.then(() => void 0, () => void 0);
354687
+ return next;
354688
+ }
354689
+ markIndexTruncated(message) {
354690
+ if (!this.isIndexTruncated) {
354691
+ logger.warn(message);
354692
+ }
354693
+ this.isIndexTruncated = true;
354694
+ }
354695
+ ensureNotDisposed() {
354696
+ if (this.isDisposed) {
354697
+ throw new Error("ACECodeSearchService has been disposed");
354698
+ }
354699
+ }
354700
+ scheduleIdleCleanup() {
354701
+ var _a20, _b14;
354702
+ if (this.isDisposed || this.idleCleanupMs <= 0) {
354703
+ return;
354704
+ }
354705
+ if (this.idleCleanupTimer) {
354706
+ clearTimeout(this.idleCleanupTimer);
354707
+ }
354708
+ this.idleCleanupTimer = setTimeout(() => {
354709
+ if (this.isDisposed) {
354710
+ return;
354711
+ }
354712
+ logger.debug(`ACECodeSearchService idle cleanup triggered for ${this.basePath}`);
354713
+ this.clearCaches({ preserveExclusions: true, preserveCommandCache: true });
354714
+ }, this.idleCleanupMs);
354715
+ (_b14 = (_a20 = this.idleCleanupTimer).unref) == null ? void 0 : _b14.call(_a20);
354716
+ }
354717
+ markActivity() {
354718
+ this.ensureNotDisposed();
354719
+ this.scheduleIdleCleanup();
354720
+ }
354721
+ trimFileStatCache() {
354722
+ var _a20;
354723
+ const overflow = this.fileStatCache.size - MAX_FILE_STAT_CACHE_SIZE;
354724
+ if (overflow <= 0) {
354725
+ return;
354726
+ }
354727
+ const entries = Array.from(this.fileStatCache.entries()).sort((a, b) => a[1].cachedAt - b[1].cachedAt);
354728
+ for (let i = 0; i < overflow; i++) {
354729
+ const filePath = (_a20 = entries[i]) == null ? void 0 : _a20[0];
354730
+ if (filePath) {
354731
+ this.fileStatCache.delete(filePath);
354732
+ }
354733
+ }
354734
+ }
354735
+ clearCaches(options3) {
354736
+ this.indexCache.clear();
354737
+ this.fileModTimes.clear();
354738
+ this.allIndexedFiles.clear();
354739
+ this.fileContentCache.clear();
354740
+ this.fileStatCache.clear();
354741
+ this.fzfIndex = void 0;
354742
+ this.lastIndexTime = 0;
354743
+ this.isIndexTruncated = false;
354744
+ this.indexBuildQueue = Promise.resolve();
354745
+ if (!(options3 == null ? void 0 : options3.preserveExclusions)) {
354746
+ this.customExcludes = [];
354747
+ this.excludesLoaded = false;
354748
+ this.regexCache.clear();
354749
+ }
354750
+ if (!(options3 == null ? void 0 : options3.preserveCommandCache)) {
354751
+ this.commandAvailabilityCache.clear();
354752
+ this.isGitRepoCache = null;
354753
+ }
354754
+ }
354755
+ dispose() {
354756
+ if (this.idleCleanupTimer) {
354757
+ clearTimeout(this.idleCleanupTimer);
354758
+ this.idleCleanupTimer = void 0;
354759
+ }
354760
+ this.clearCaches();
354761
+ this.isDisposed = true;
354666
354762
  }
354667
354763
  /**
354668
354764
  * Check if a path is a remote SSH URL
@@ -354770,6 +354866,7 @@ var init_aceCodeSearch = __esm({
354770
354866
  * Build or refresh the code symbol index with incremental updates
354771
354867
  */
354772
354868
  async buildIndex(forceRefresh = false) {
354869
+ this.markActivity();
354773
354870
  return this.withIndexBuildLock(async () => {
354774
354871
  const now = Date.now();
354775
354872
  if (!forceRefresh && this.indexCache.size > 0 && now - this.lastIndexTime < INDEX_CACHE_DURATION) {
@@ -354777,12 +354874,10 @@ var init_aceCodeSearch = __esm({
354777
354874
  }
354778
354875
  await this.loadExclusionPatterns();
354779
354876
  if (forceRefresh) {
354780
- this.indexCache.clear();
354781
- this.fileModTimes.clear();
354782
- this.allIndexedFiles.clear();
354783
- this.fileContentCache.clear();
354784
- this.fzfIndex = void 0;
354785
- this.isIndexTruncated = false;
354877
+ this.clearCaches({
354878
+ preserveExclusions: true,
354879
+ preserveCommandCache: true
354880
+ });
354786
354881
  }
354787
354882
  const filesToProcess = [];
354788
354883
  const searchInDirectory = async (dirPath) => {
@@ -354849,6 +354944,7 @@ var init_aceCodeSearch = __esm({
354849
354944
  } catch {
354850
354945
  this.indexCache.delete(fullPath);
354851
354946
  this.fileModTimes.delete(fullPath);
354947
+ this.fileContentCache.delete(fullPath);
354852
354948
  }
354853
354949
  }));
354854
354950
  }
@@ -354893,6 +354989,7 @@ var init_aceCodeSearch = __esm({
354893
354989
  * Search for symbols by name with fuzzy matching using fzf
354894
354990
  */
354895
354991
  async searchSymbols(query, symbolType2, language, maxResults = 100) {
354992
+ this.markActivity();
354896
354993
  const startTime = Date.now();
354897
354994
  await this.buildIndex();
354898
354995
  await this.indexBuildQueue;
@@ -355009,6 +355106,7 @@ var init_aceCodeSearch = __esm({
355009
355106
  * Find all references to a symbol
355010
355107
  */
355011
355108
  async findReferences(symbolName, maxResults = 100) {
355109
+ this.markActivity();
355012
355110
  const references = [];
355013
355111
  await this.loadExclusionPatterns();
355014
355112
  const escapedSymbol = symbolName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -355089,6 +355187,7 @@ var init_aceCodeSearch = __esm({
355089
355187
  * Find symbol definition (go to definition)
355090
355188
  */
355091
355189
  async findDefinition(symbolName, contextFile) {
355190
+ this.markActivity();
355092
355191
  await this.buildIndex();
355093
355192
  await this.indexBuildQueue;
355094
355193
  if (contextFile) {
@@ -355112,8 +355211,10 @@ var init_aceCodeSearch = __esm({
355112
355211
  * Enhanced with timeout protection to prevent hanging
355113
355212
  */
355114
355213
  async gitGrepSearch(pattern, fileGlob, maxResults = 100, isRegex = true) {
355214
+ this.markActivity();
355115
355215
  const timeoutMs = 15e3;
355116
355216
  return new Promise((resolve12, reject2) => {
355217
+ var _a20;
355117
355218
  const args2 = ["grep", "--untracked", "-n", "--ignore-case"];
355118
355219
  if (isRegex) {
355119
355220
  args2.push("-E");
@@ -355122,7 +355223,7 @@ var init_aceCodeSearch = __esm({
355122
355223
  }
355123
355224
  args2.push(pattern);
355124
355225
  if (fileGlob) {
355125
- let gitGlob = fileGlob.replace(/\\\\/g, "/");
355226
+ let gitGlob = fileGlob.replace(/\\/g, "/");
355126
355227
  gitGlob = gitGlob.replace(/\*\*/g, "*");
355127
355228
  const expandedGlobs = expandGlobBraces(gitGlob);
355128
355229
  args2.push("--", ...expandedGlobs);
@@ -355135,29 +355236,41 @@ var init_aceCodeSearch = __esm({
355135
355236
  const stdoutChunks = [];
355136
355237
  const stderrChunks = [];
355137
355238
  let isCompleted = false;
355138
- const timeoutId = setTimeout(() => {
355139
- if (!isCompleted) {
355140
- isCompleted = true;
355239
+ const finalize = (handler, killProcess2 = false) => {
355240
+ if (isCompleted) {
355241
+ return;
355242
+ }
355243
+ isCompleted = true;
355244
+ clearTimeout(timeoutId);
355245
+ child.stdout.removeAllListeners();
355246
+ child.stderr.removeAllListeners();
355247
+ child.removeAllListeners("error");
355248
+ child.removeAllListeners("close");
355249
+ if (killProcess2 && !child.killed) {
355141
355250
  child.kill("SIGTERM");
355251
+ }
355252
+ handler();
355253
+ stdoutChunks.length = 0;
355254
+ stderrChunks.length = 0;
355255
+ };
355256
+ const timeoutId = setTimeout(() => {
355257
+ finalize(() => {
355142
355258
  logger.warn(`git grep timed out after ${timeoutMs}ms, killing process`);
355143
355259
  reject2(new Error(`git grep timed out after ${timeoutMs}ms`));
355144
- }
355260
+ }, true);
355145
355261
  }, timeoutMs);
355262
+ (_a20 = timeoutId.unref) == null ? void 0 : _a20.call(timeoutId);
355146
355263
  child.stdout.on("data", (chunk2) => stdoutChunks.push(chunk2));
355147
355264
  child.stderr.on("data", (chunk2) => stderrChunks.push(chunk2));
355148
- child.on("error", (err) => {
355149
- if (!isCompleted) {
355150
- isCompleted = true;
355151
- clearTimeout(timeoutId);
355265
+ child.once("error", (err) => {
355266
+ finalize(() => {
355152
355267
  reject2(new Error(`Failed to start git grep: ${err.message}`));
355153
- }
355268
+ });
355154
355269
  });
355155
- child.on("close", (code) => {
355156
- if (!isCompleted) {
355157
- isCompleted = true;
355158
- clearTimeout(timeoutId);
355159
- const stdoutData = Buffer.concat(stdoutChunks).toString("utf8");
355160
- const stderrData = Buffer.concat(stderrChunks).toString("utf8").trim();
355270
+ child.once("close", (code) => {
355271
+ const stdoutData = Buffer.concat(stdoutChunks).toString("utf8");
355272
+ const stderrData = Buffer.concat(stderrChunks).toString("utf8").trim();
355273
+ finalize(() => {
355161
355274
  if (code === 0) {
355162
355275
  const results = parseGrepOutput(stdoutData, this.basePath);
355163
355276
  resolve12(results.slice(0, maxResults));
@@ -355166,7 +355279,7 @@ var init_aceCodeSearch = __esm({
355166
355279
  } else {
355167
355280
  reject2(new Error(`git grep exited with code ${code}: ${stderrData}`));
355168
355281
  }
355169
- }
355282
+ });
355170
355283
  });
355171
355284
  });
355172
355285
  }
@@ -355175,30 +355288,21 @@ var init_aceCodeSearch = __esm({
355175
355288
  * Enhanced with timeout protection to prevent hanging on Windows
355176
355289
  */
355177
355290
  async systemGrepSearch(pattern, fileGlob, maxResults = 100, grepCommand = "grep") {
355291
+ this.markActivity();
355178
355292
  const isRipgrep = grepCommand === "rg";
355179
355293
  const timeoutMs = 15e3;
355180
355294
  return new Promise((resolve12, reject2) => {
355295
+ var _a20;
355181
355296
  const args2 = isRipgrep ? ["-n", "-i", "--no-heading"] : ["-r", "-n", "-H", "-E", "-i"];
355182
- const excludeDirs = [
355183
- "node_modules",
355184
- ".git",
355185
- "dist",
355186
- "build",
355187
- "__pycache__",
355188
- "target",
355189
- ".next",
355190
- ".nuxt",
355191
- "coverage"
355192
- ];
355193
355297
  if (isRipgrep) {
355194
- excludeDirs.forEach((dir) => args2.push("--glob", `!${dir}/`));
355298
+ GREP_EXCLUDE_DIRS.forEach((dir) => args2.push("--glob", `!${dir}/`));
355195
355299
  if (fileGlob) {
355196
355300
  const normalizedGlob = fileGlob.replace(/\\/g, "/");
355197
355301
  const expandedGlobs = expandGlobBraces(normalizedGlob);
355198
355302
  expandedGlobs.forEach((glob) => args2.push("--glob", glob));
355199
355303
  }
355200
355304
  } else {
355201
- excludeDirs.forEach((dir) => args2.push(`--exclude-dir=${dir}`));
355305
+ GREP_EXCLUDE_DIRS.forEach((dir) => args2.push(`--exclude-dir=${dir}`));
355202
355306
  if (fileGlob) {
355203
355307
  const normalizedGlob = fileGlob.replace(/\\/g, "/");
355204
355308
  const expandedGlobs = expandGlobBraces(normalizedGlob);
@@ -355215,14 +355319,30 @@ var init_aceCodeSearch = __esm({
355215
355319
  const stdoutChunks = [];
355216
355320
  const stderrChunks = [];
355217
355321
  let isCompleted = false;
355218
- const timeoutId = setTimeout(() => {
355219
- if (!isCompleted) {
355220
- isCompleted = true;
355322
+ const finalize = (handler, killProcess2 = false) => {
355323
+ if (isCompleted) {
355324
+ return;
355325
+ }
355326
+ isCompleted = true;
355327
+ clearTimeout(timeoutId);
355328
+ child.stdout.removeAllListeners();
355329
+ child.stderr.removeAllListeners();
355330
+ child.removeAllListeners("error");
355331
+ child.removeAllListeners("close");
355332
+ if (killProcess2 && !child.killed) {
355221
355333
  child.kill("SIGTERM");
355334
+ }
355335
+ handler();
355336
+ stdoutChunks.length = 0;
355337
+ stderrChunks.length = 0;
355338
+ };
355339
+ const timeoutId = setTimeout(() => {
355340
+ finalize(() => {
355222
355341
  logger.warn(`${grepCommand} timed out after ${timeoutMs}ms, killing process`);
355223
355342
  reject2(new Error(`${grepCommand} timed out after ${timeoutMs}ms`));
355224
- }
355343
+ }, true);
355225
355344
  }, timeoutMs);
355345
+ (_a20 = timeoutId.unref) == null ? void 0 : _a20.call(timeoutId);
355226
355346
  child.stdout.on("data", (chunk2) => stdoutChunks.push(chunk2));
355227
355347
  child.stderr.on("data", (chunk2) => {
355228
355348
  const stderrStr = chunk2.toString();
@@ -355230,19 +355350,15 @@ var init_aceCodeSearch = __esm({
355230
355350
  stderrChunks.push(chunk2);
355231
355351
  }
355232
355352
  });
355233
- child.on("error", (err) => {
355234
- if (!isCompleted) {
355235
- isCompleted = true;
355236
- clearTimeout(timeoutId);
355353
+ child.once("error", (err) => {
355354
+ finalize(() => {
355237
355355
  reject2(new Error(`Failed to start ${grepCommand}: ${err.message}`));
355238
- }
355356
+ });
355239
355357
  });
355240
- child.on("close", (code) => {
355241
- if (!isCompleted) {
355242
- isCompleted = true;
355243
- clearTimeout(timeoutId);
355244
- const stdoutData = Buffer.concat(stdoutChunks).toString("utf8");
355245
- const stderrData = Buffer.concat(stderrChunks).toString("utf8").trim();
355358
+ child.once("close", (code) => {
355359
+ const stdoutData = Buffer.concat(stdoutChunks).toString("utf8");
355360
+ const stderrData = Buffer.concat(stderrChunks).toString("utf8").trim();
355361
+ finalize(() => {
355246
355362
  if (code === 0) {
355247
355363
  const results = parseGrepOutput(stdoutData, this.basePath);
355248
355364
  resolve12(results.slice(0, maxResults));
@@ -355253,7 +355369,7 @@ var init_aceCodeSearch = __esm({
355253
355369
  } else {
355254
355370
  resolve12([]);
355255
355371
  }
355256
- }
355372
+ });
355257
355373
  });
355258
355374
  });
355259
355375
  }
@@ -355277,6 +355393,7 @@ var init_aceCodeSearch = __esm({
355277
355393
  * - Concurrent read limiting
355278
355394
  */
355279
355395
  async jsTextSearch(pattern, fileGlob, isRegex = true, maxResults = 100) {
355396
+ this.markActivity();
355280
355397
  const results = [];
355281
355398
  let isAborted2 = false;
355282
355399
  const startTime = Date.now();
@@ -355382,6 +355499,7 @@ var init_aceCodeSearch = __esm({
355382
355499
  * Processes the file line by line without loading entire content into memory.
355383
355500
  */
355384
355501
  async searchInLargeFile(fileInfo, searchRegex, results, maxResults, isAborted2) {
355502
+ this.markActivity();
355385
355503
  return new Promise((resolve12) => {
355386
355504
  const stream = createReadStream(fileInfo.fullPath, {
355387
355505
  highWaterMark: FILE_READ_CHUNK_SIZE,
@@ -355392,11 +355510,20 @@ var init_aceCodeSearch = __esm({
355392
355510
  crlfDelay: Infinity
355393
355511
  });
355394
355512
  let lineNumber = 0;
355395
- let hasError = false;
355513
+ let isResolved = false;
355514
+ const finalize = () => {
355515
+ if (isResolved) {
355516
+ return;
355517
+ }
355518
+ isResolved = true;
355519
+ rl.removeAllListeners();
355520
+ stream.removeAllListeners();
355521
+ stream.destroy();
355522
+ resolve12();
355523
+ };
355396
355524
  rl.on("line", (line) => {
355397
- if (hasError || isAborted2() || results.length >= maxResults) {
355525
+ if (isAborted2() || results.length >= maxResults) {
355398
355526
  rl.close();
355399
- stream.destroy();
355400
355527
  return;
355401
355528
  }
355402
355529
  lineNumber++;
@@ -355413,18 +355540,14 @@ var init_aceCodeSearch = __esm({
355413
355540
  });
355414
355541
  }
355415
355542
  });
355416
- rl.on("close", () => {
355417
- resolve12();
355418
- });
355419
- rl.on("error", (err) => {
355420
- hasError = true;
355543
+ rl.once("close", finalize);
355544
+ rl.once("error", (err) => {
355421
355545
  logger.info(`Error reading large file ${fileInfo.relativePath}: ${err.message}`);
355422
- resolve12();
355546
+ finalize();
355423
355547
  });
355424
- stream.on("error", (err) => {
355425
- hasError = true;
355548
+ stream.once("error", (err) => {
355426
355549
  logger.info(`Stream error for ${fileInfo.relativePath}: ${err.message}`);
355427
- resolve12();
355550
+ finalize();
355428
355551
  });
355429
355552
  });
355430
355553
  }
@@ -355438,11 +355561,22 @@ var init_aceCodeSearch = __esm({
355438
355561
  * Enhanced with global timeout protection to prevent runaway searches
355439
355562
  */
355440
355563
  async textSearch(pattern, fileGlob, isRegex = true, maxResults = 100) {
355441
- const searchPromise = this.executeTextSearch(pattern, fileGlob, isRegex, maxResults);
355442
- return Promise.race([
355443
- searchPromise,
355444
- createTimeoutPromise(TEXT_SEARCH_TIMEOUT_MS, `Text search exceeded ${TEXT_SEARCH_TIMEOUT_MS}ms timeout. Try using a more specific pattern or fileGlob filter.`)
355445
- ]);
355564
+ this.markActivity();
355565
+ const timeoutMs = TEXT_SEARCH_TIMEOUT_MS;
355566
+ return new Promise((resolve12, reject2) => {
355567
+ var _a20;
355568
+ const timeoutId = setTimeout(() => {
355569
+ reject2(new Error(`Text search exceeded ${timeoutMs}ms timeout. Try using a more specific pattern or fileGlob filter.`));
355570
+ }, timeoutMs);
355571
+ (_a20 = timeoutId.unref) == null ? void 0 : _a20.call(timeoutId);
355572
+ this.executeTextSearch(pattern, fileGlob, isRegex, maxResults).then((result2) => {
355573
+ clearTimeout(timeoutId);
355574
+ resolve12(result2);
355575
+ }).catch((error40) => {
355576
+ clearTimeout(timeoutId);
355577
+ reject2(error40);
355578
+ });
355579
+ });
355446
355580
  }
355447
355581
  /**
355448
355582
  * Internal text search implementation (separated for timeout wrapping)
@@ -355454,6 +355588,7 @@ var init_aceCodeSearch = __esm({
355454
355588
  * 4. JavaScript fallback (always works)
355455
355589
  */
355456
355590
  async executeTextSearch(pattern, fileGlob, isRegex = true, maxResults = 100) {
355591
+ this.markActivity();
355457
355592
  const [isGitRepo2, gitAvailable, rgAvailable, grepAvailable] = await Promise.all([
355458
355593
  this.isGitRepository(),
355459
355594
  this.isCommandAvailableCached("git"),
@@ -355498,7 +355633,7 @@ var init_aceCodeSearch = __esm({
355498
355633
  if (results.length === 0)
355499
355634
  return results;
355500
355635
  const now = Date.now();
355501
- const recentThreshold = 24 * 60 * 60 * 1e3;
355636
+ const recentThreshold = RECENT_FILE_THRESHOLD;
355502
355637
  const uniqueFiles = Array.from(new Set(results.map((r) => r.filePath)));
355503
355638
  const fileModTimes = /* @__PURE__ */ new Map();
355504
355639
  const uncachedFiles = [];
@@ -355522,6 +355657,7 @@ var init_aceCodeSearch = __esm({
355522
355657
  const mtimeMs = result2.value.mtimeMs;
355523
355658
  fileModTimes.set(filePath, mtimeMs);
355524
355659
  this.fileStatCache.set(filePath, { mtimeMs, cachedAt: now });
355660
+ this.trimFileStatCache();
355525
355661
  } else {
355526
355662
  fileModTimes.set(filePath, 0);
355527
355663
  }
@@ -355546,6 +355682,7 @@ var init_aceCodeSearch = __esm({
355546
355682
  * Supports both local files and remote SSH files (ssh://user@host:port/path)
355547
355683
  */
355548
355684
  async getFileOutline(filePath, options3) {
355685
+ this.markActivity();
355549
355686
  const isRemote = this.isSSHPath(filePath);
355550
355687
  let content;
355551
355688
  let effectivePath;
@@ -355592,6 +355729,7 @@ var init_aceCodeSearch = __esm({
355592
355729
  * Search with language-specific context (cross-reference search)
355593
355730
  */
355594
355731
  async semanticSearch(query, searchType = "all", language, symbolType2, maxResults = 50) {
355732
+ this.markActivity();
355595
355733
  const startTime = Date.now();
355596
355734
  const symbolResults = await this.searchSymbols(query, symbolType2, language, maxResults);
355597
355735
  let references = [];
@@ -435773,19 +435911,92 @@ Result: ${resultSummary}`
435773
435911
  let question = "Please select an option:";
435774
435912
  let options3 = ["Yes", "No"];
435775
435913
  let multiSelect = false;
435914
+ let parsedArgs = {};
435776
435915
  try {
435777
- const args2 = JSON.parse(askUserTool.function.arguments);
435778
- if (args2.question)
435779
- question = args2.question;
435780
- if (args2.options && Array.isArray(args2.options)) {
435781
- options3 = args2.options;
435916
+ parsedArgs = JSON.parse(askUserTool.function.arguments);
435917
+ if (parsedArgs["question"])
435918
+ question = parsedArgs["question"];
435919
+ if (parsedArgs["options"] && Array.isArray(parsedArgs["options"])) {
435920
+ options3 = parsedArgs["options"];
435782
435921
  }
435783
- if (args2.multiSelect === true) {
435922
+ if (parsedArgs["multiSelect"] === true) {
435784
435923
  multiSelect = true;
435785
435924
  }
435786
435925
  } catch (error40) {
435787
435926
  console.error("Failed to parse askuser tool arguments:", error40);
435788
435927
  }
435928
+ try {
435929
+ const hookResult = await unifiedHooksExecutor.executeHooks("beforeToolCall", {
435930
+ toolName: askUserTool.function.name,
435931
+ args: parsedArgs
435932
+ });
435933
+ if (hookResult && !hookResult.success) {
435934
+ const commandError = hookResult.results.find((r) => r.type === "command" && !r.success);
435935
+ if (commandError && commandError.type === "command") {
435936
+ const { exitCode, command, output: output2, error: error40 } = commandError;
435937
+ if (exitCode === 1) {
435938
+ const blockedContent = error40 || output2 || `[beforeToolCall Hook Warning] Command: ${command} exited with code 1`;
435939
+ const blockedResult = {
435940
+ role: "tool",
435941
+ tool_call_id: askUserTool.id,
435942
+ content: blockedContent
435943
+ };
435944
+ messages.push(blockedResult);
435945
+ if (onMessage) {
435946
+ onMessage({
435947
+ type: "sub_agent_message",
435948
+ agentId: agent.id,
435949
+ agentName: agent.name,
435950
+ message: {
435951
+ type: "tool_result",
435952
+ tool_call_id: askUserTool.id,
435953
+ tool_name: askUserTool.function.name,
435954
+ content: blockedContent
435955
+ }
435956
+ });
435957
+ }
435958
+ } else if (exitCode >= 2 || exitCode < 0) {
435959
+ const hookErrorDetails = {
435960
+ type: "error",
435961
+ exitCode,
435962
+ command,
435963
+ output: output2,
435964
+ error: error40
435965
+ };
435966
+ const hookFailedResult = {
435967
+ role: "tool",
435968
+ tool_call_id: askUserTool.id,
435969
+ content: "",
435970
+ hookFailed: true,
435971
+ hookErrorDetails
435972
+ };
435973
+ messages.push(hookFailedResult);
435974
+ if (onMessage) {
435975
+ onMessage({
435976
+ type: "sub_agent_message",
435977
+ agentId: agent.id,
435978
+ agentName: agent.name,
435979
+ message: {
435980
+ type: "tool_result",
435981
+ tool_call_id: askUserTool.id,
435982
+ tool_name: askUserTool.function.name,
435983
+ content: "",
435984
+ hookFailed: true,
435985
+ hookErrorDetails
435986
+ }
435987
+ });
435988
+ }
435989
+ }
435990
+ const remainingTools2 = toolCalls.filter((tc) => tc.id !== askUserTool.id);
435991
+ if (remainingTools2.length === 0) {
435992
+ continue;
435993
+ }
435994
+ toolCalls = remainingTools2;
435995
+ }
435996
+ }
435997
+ } catch (hookError) {
435998
+ console.warn("Failed to execute beforeToolCall hook for askuser in sub-agent:", hookError);
435999
+ }
435789
436000
  if (connectionManager.isConnected()) {
435790
436001
  await connectionManager.notifyUserInteractionNeeded(question, options3, askUserTool.id, multiSelect);
435791
436002
  }
@@ -435967,6 +436178,76 @@ Result: ${resultSummary}`
435967
436178
  }
435968
436179
  try {
435969
436180
  const args2 = JSON.parse(toolCall.function.arguments);
436181
+ try {
436182
+ const hookResult = await unifiedHooksExecutor.executeHooks("beforeToolCall", {
436183
+ toolName: toolCall.function.name,
436184
+ args: args2
436185
+ });
436186
+ if (hookResult && !hookResult.success) {
436187
+ const commandError = hookResult.results.find((r) => r.type === "command" && !r.success);
436188
+ if (commandError && commandError.type === "command") {
436189
+ const { exitCode, command, output: output2, error: error40 } = commandError;
436190
+ if (exitCode === 1) {
436191
+ const blockedContent = error40 || output2 || `[beforeToolCall Hook Warning] Command: ${command} exited with code 1`;
436192
+ const blockedResult = {
436193
+ role: "tool",
436194
+ tool_call_id: toolCall.id,
436195
+ content: blockedContent
436196
+ };
436197
+ toolResults.push(blockedResult);
436198
+ if (onMessage) {
436199
+ onMessage({
436200
+ type: "sub_agent_message",
436201
+ agentId: agent.id,
436202
+ agentName: agent.name,
436203
+ message: {
436204
+ type: "tool_result",
436205
+ tool_call_id: toolCall.id,
436206
+ tool_name: toolCall.function.name,
436207
+ content: blockedContent
436208
+ }
436209
+ });
436210
+ }
436211
+ continue;
436212
+ }
436213
+ if (exitCode >= 2 || exitCode < 0) {
436214
+ const hookErrorDetails = {
436215
+ type: "error",
436216
+ exitCode,
436217
+ command,
436218
+ output: output2,
436219
+ error: error40
436220
+ };
436221
+ const hookFailedResult = {
436222
+ role: "tool",
436223
+ tool_call_id: toolCall.id,
436224
+ content: "",
436225
+ hookFailed: true,
436226
+ hookErrorDetails
436227
+ };
436228
+ toolResults.push(hookFailedResult);
436229
+ if (onMessage) {
436230
+ onMessage({
436231
+ type: "sub_agent_message",
436232
+ agentId: agent.id,
436233
+ agentName: agent.name,
436234
+ message: {
436235
+ type: "tool_result",
436236
+ tool_call_id: toolCall.id,
436237
+ tool_name: toolCall.function.name,
436238
+ content: "",
436239
+ hookFailed: true,
436240
+ hookErrorDetails
436241
+ }
436242
+ });
436243
+ }
436244
+ continue;
436245
+ }
436246
+ }
436247
+ }
436248
+ } catch (hookError) {
436249
+ console.warn("Failed to execute beforeToolCall hook in sub-agent:", hookError);
436250
+ }
435970
436251
  const result2 = await executeMCPTool(toolCall.function.name, args2, abortSignal);
435971
436252
  const toolResult = {
435972
436253
  role: "tool",
@@ -440108,6 +440389,48 @@ var init_resourceMonitor = __esm({
440108
440389
  }
440109
440390
  });
440110
440391
 
440392
+ // dist/utils/execution/hookFailedError.js
440393
+ var HookFailedError;
440394
+ var init_hookFailedError = __esm({
440395
+ "dist/utils/execution/hookFailedError.js"() {
440396
+ "use strict";
440397
+ HookFailedError = class extends Error {
440398
+ constructor(hookName, exitCode, command, output2) {
440399
+ super(`${hookName} hook failed with exit code ${exitCode}`);
440400
+ Object.defineProperty(this, "hookName", {
440401
+ enumerable: true,
440402
+ configurable: true,
440403
+ writable: true,
440404
+ value: void 0
440405
+ });
440406
+ Object.defineProperty(this, "exitCode", {
440407
+ enumerable: true,
440408
+ configurable: true,
440409
+ writable: true,
440410
+ value: void 0
440411
+ });
440412
+ Object.defineProperty(this, "command", {
440413
+ enumerable: true,
440414
+ configurable: true,
440415
+ writable: true,
440416
+ value: void 0
440417
+ });
440418
+ Object.defineProperty(this, "output", {
440419
+ enumerable: true,
440420
+ configurable: true,
440421
+ writable: true,
440422
+ value: void 0
440423
+ });
440424
+ this.name = "HookFailedError";
440425
+ this.hookName = hookName;
440426
+ this.exitCode = exitCode;
440427
+ this.command = command;
440428
+ this.output = output2;
440429
+ }
440430
+ };
440431
+ }
440432
+ });
440433
+
440111
440434
  // dist/utils/execution/toolSearchService.js
440112
440435
  var toolSearchService_exports = {};
440113
440436
  __export(toolSearchService_exports, {
@@ -444637,6 +444960,7 @@ var init_HybridCodeSearchService = __esm({
444637
444960
  return this.regexSearch.semanticSearch(query, searchType, language, symbolType2, maxResults);
444638
444961
  }
444639
444962
  async dispose() {
444963
+ this.regexSearch.dispose();
444640
444964
  await this.lspManager.dispose();
444641
444965
  }
444642
444966
  };
@@ -446126,15 +446450,12 @@ error: ${error40 || "(empty)"}`);
446126
446450
  }
446127
446451
  } else if (exitCode >= 2 || exitCode < 0) {
446128
446452
  const combinedOutput = [output2, error40].filter(Boolean).join("\n\n") || "(no output)";
446129
- throw new Error(`afterToolCall hook failed with exit code ${exitCode}
446130
- Command: ${command}
446131
- Output:
446132
- ${combinedOutput}`);
446453
+ throw new HookFailedError("afterToolCall", exitCode, command, combinedOutput);
446133
446454
  }
446134
446455
  }
446135
446456
  }
446136
446457
  } catch (error40) {
446137
- if (error40 instanceof Error && error40.message.includes("afterToolCall hook failed")) {
446458
+ if (error40 instanceof HookFailedError) {
446138
446459
  throw error40;
446139
446460
  }
446140
446461
  logger.warn("Failed to execute afterToolCall hook:", error40);
@@ -446218,6 +446539,7 @@ var init_mcpToolsManager = __esm({
446218
446539
  init_disabledSkills();
446219
446540
  init_logger();
446220
446541
  init_resourceMonitor();
446542
+ init_hookFailedError();
446221
446543
  toolsCache = null;
446222
446544
  CACHE_DURATION = 5 * 60 * 1e3;
446223
446545
  todoService = null;
@@ -517777,8 +518099,8 @@ function DiffViewer({ oldContent = "", newContent, filename, completeOldContent,
517777
518099
  const { theme: theme14 } = useTheme();
517778
518100
  const { columns } = useTerminalSize();
517779
518101
  const codeLanguage = inferLanguageFromFilename(filename);
517780
- const diffAddedBackground = (0, import_react81.useMemo)(() => blendHexColors(theme14.colors.diffAdded, theme14.colors.background, 0.35), [theme14.colors.diffAdded, theme14.colors.background]);
517781
- const diffRemovedBackground = (0, import_react81.useMemo)(() => blendHexColors(theme14.colors.diffRemoved, theme14.colors.background, 0.35), [theme14.colors.diffRemoved, theme14.colors.background]);
518102
+ const diffAddedBackground = (0, import_react81.useMemo)(() => blendHexColors(theme14.colors.diffAdded, theme14.colors.background, 1), [theme14.colors.diffAdded, theme14.colors.background]);
518103
+ const diffRemovedBackground = (0, import_react81.useMemo)(() => blendHexColors(theme14.colors.diffRemoved, theme14.colors.background, 1), [theme14.colors.diffRemoved, theme14.colors.background]);
517782
518104
  const useSideBySide = columns >= MIN_SIDE_BY_SIDE_WIDTH;
517783
518105
  const useCompleteContent = completeOldContent && completeNewContent;
517784
518106
  const diffOldContent = useCompleteContent ? completeOldContent : stripLineNumbers(oldContent);
@@ -591645,7 +591967,7 @@ var require_package3 = __commonJS({
591645
591967
  "package.json"(exports2, module2) {
591646
591968
  module2.exports = {
591647
591969
  name: "snow-ai",
591648
- version: "0.6.66",
591970
+ version: "0.6.67",
591649
591971
  description: "Agentic coding in your terminal",
591650
591972
  license: "MIT",
591651
591973
  bin: {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "snow-ai",
3
- "version": "0.6.66",
3
+ "version": "0.6.67",
4
4
  "description": "Agentic coding in your terminal",
5
5
  "license": "MIT",
6
6
  "bin": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "snow-ai",
3
- "version": "0.6.66",
3
+ "version": "0.6.67",
4
4
  "description": "Agentic coding in your terminal",
5
5
  "license": "MIT",
6
6
  "bin": {