@probelabs/probe 0.6.0-rc270 → 0.6.0-rc271

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.
@@ -9045,6 +9045,7 @@ var init_hashline = __esm({
9045
9045
 
9046
9046
  // src/tools/vercel.js
9047
9047
  import { tool } from "ai";
9048
+ import { existsSync } from "fs";
9048
9049
  function normalizeTargets(targets) {
9049
9050
  if (!Array.isArray(targets)) return [];
9050
9051
  const seen = /* @__PURE__ */ new Set();
@@ -9121,6 +9122,17 @@ function parseDelegatedTargets(rawResponse) {
9121
9122
  }
9122
9123
  return normalizeTargets(fallbackTargetsFromText(trimmed));
9123
9124
  }
9125
+ function splitTargetSuffix(target) {
9126
+ const searchStart = target.length > 2 && target[1] === ":" && /[a-zA-Z]/.test(target[0]) ? 2 : 0;
9127
+ const colonIdx = target.indexOf(":", searchStart);
9128
+ const hashIdx = target.indexOf("#");
9129
+ if (colonIdx !== -1 && (hashIdx === -1 || colonIdx < hashIdx)) {
9130
+ return { filePart: target.substring(0, colonIdx), suffix: target.substring(colonIdx) };
9131
+ } else if (hashIdx !== -1) {
9132
+ return { filePart: target.substring(0, hashIdx), suffix: target.substring(hashIdx) };
9133
+ }
9134
+ return { filePart: target, suffix: "" };
9135
+ }
9124
9136
  function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, allowTests }) {
9125
9137
  return [
9126
9138
  "You are a code-search subagent. Your job is to find ALL relevant code locations for the given query.",
@@ -9284,10 +9296,47 @@ var init_vercel = __esm({
9284
9296
  }
9285
9297
  return fallbackResult;
9286
9298
  }
9299
+ const delegateBase = options.allowedFolders?.[0] || options.cwd || ".";
9287
9300
  const resolutionBase = searchPaths[0] || options.cwd || ".";
9288
- const resolvedTargets = targets.map((target) => resolveTargetPath(target, resolutionBase));
9301
+ const resolvedTargets = targets.map((target) => resolveTargetPath(target, delegateBase));
9302
+ const validatedTargets = [];
9303
+ for (const target of resolvedTargets) {
9304
+ const { filePart, suffix } = splitTargetSuffix(target);
9305
+ if (existsSync(filePart)) {
9306
+ validatedTargets.push(target);
9307
+ continue;
9308
+ }
9309
+ let fixed = false;
9310
+ const parts = filePart.split("/").filter(Boolean);
9311
+ for (let i = 0; i < parts.length - 1; i++) {
9312
+ if (parts[i] === parts[i + 1]) {
9313
+ const candidate = "/" + [...parts.slice(0, i), ...parts.slice(i + 1)].join("/");
9314
+ if (existsSync(candidate)) {
9315
+ validatedTargets.push(candidate + suffix);
9316
+ if (debug) console.error(`[search-delegate] Fixed doubled path segment: ${filePart} \u2192 ${candidate}`);
9317
+ fixed = true;
9318
+ break;
9319
+ }
9320
+ }
9321
+ }
9322
+ if (fixed) continue;
9323
+ for (const altBase of [resolutionBase, options.cwd].filter(Boolean)) {
9324
+ if (altBase === delegateBase) continue;
9325
+ const altResolved = resolveTargetPath(target, altBase);
9326
+ const { filePart: altFile } = splitTargetSuffix(altResolved);
9327
+ if (existsSync(altFile)) {
9328
+ validatedTargets.push(altResolved);
9329
+ if (debug) console.error(`[search-delegate] Resolved with alt base: ${filePart} \u2192 ${altFile}`);
9330
+ fixed = true;
9331
+ break;
9332
+ }
9333
+ }
9334
+ if (fixed) continue;
9335
+ if (debug) console.error(`[search-delegate] Warning: target may not exist: ${filePart}`);
9336
+ validatedTargets.push(target);
9337
+ }
9289
9338
  const extractOptions = {
9290
- files: resolvedTargets,
9339
+ files: validatedTargets,
9291
9340
  cwd: resolutionBase,
9292
9341
  allowTests: allow_tests ?? true
9293
9342
  };
@@ -10805,7 +10854,7 @@ var init_bashPermissions = __esm({
10805
10854
  // src/agent/bashExecutor.js
10806
10855
  import { spawn as spawn2 } from "child_process";
10807
10856
  import { resolve as resolve2, join } from "path";
10808
- import { existsSync } from "fs";
10857
+ import { existsSync as existsSync2 } from "fs";
10809
10858
  function splitCommandComponents(command) {
10810
10859
  const parts = [];
10811
10860
  let current2 = "";
@@ -10935,7 +10984,7 @@ async function executeBashCommand(command, options = {}) {
10935
10984
  let cwd = workingDirectory;
10936
10985
  try {
10937
10986
  cwd = resolve2(cwd);
10938
- if (!existsSync(cwd)) {
10987
+ if (!existsSync2(cwd)) {
10939
10988
  throw new Error(`Working directory does not exist: ${cwd}`);
10940
10989
  }
10941
10990
  } catch (error) {
@@ -11191,7 +11240,7 @@ function validateExecutionOptions(options = {}) {
11191
11240
  if (options.workingDirectory) {
11192
11241
  if (typeof options.workingDirectory !== "string") {
11193
11242
  errors.push("workingDirectory must be a string");
11194
- } else if (!existsSync(options.workingDirectory)) {
11243
+ } else if (!existsSync2(options.workingDirectory)) {
11195
11244
  errors.push(`workingDirectory does not exist: ${options.workingDirectory}`);
11196
11245
  }
11197
11246
  }
@@ -11716,7 +11765,7 @@ var init_lineEditHeuristics = __esm({
11716
11765
  import { tool as tool3 } from "ai";
11717
11766
  import { promises as fs6 } from "fs";
11718
11767
  import { dirname, resolve as resolve4, isAbsolute as isAbsolute3, sep as sep2 } from "path";
11719
- import { existsSync as existsSync2 } from "fs";
11768
+ import { existsSync as existsSync3 } from "fs";
11720
11769
  function isPathAllowed(filePath, allowedFolders) {
11721
11770
  if (!allowedFolders || allowedFolders.length === 0) {
11722
11771
  const resolvedPath2 = safeRealpath(filePath);
@@ -11994,7 +12043,7 @@ Parameters:
11994
12043
  const relativePath = toRelativePath(resolvedPath, workspaceRoot);
11995
12044
  return `Error editing file: Permission denied - ${relativePath} is outside allowed directories. Use a file path within the project workspace.`;
11996
12045
  }
11997
- if (!existsSync2(resolvedPath)) {
12046
+ if (!existsSync3(resolvedPath)) {
11998
12047
  return `Error editing file: File not found - ${file_path}. Verify the path is correct and the file exists. Use 'search' to find files by name, or 'create' to make a new file.`;
11999
12048
  }
12000
12049
  if (options.fileTracker && !options.fileTracker.isFileSeen(resolvedPath)) {
@@ -12127,10 +12176,10 @@ Important:
12127
12176
  const relativePath = toRelativePath(resolvedPath, workspaceRoot);
12128
12177
  return `Error creating file: Permission denied - ${relativePath} is outside allowed directories. Use a file path within the project workspace.`;
12129
12178
  }
12130
- if (existsSync2(resolvedPath) && !overwrite) {
12179
+ if (existsSync3(resolvedPath) && !overwrite) {
12131
12180
  return `Error creating file: File already exists - ${file_path}. Use overwrite: true to replace it.`;
12132
12181
  }
12133
- const existed = existsSync2(resolvedPath);
12182
+ const existed = existsSync3(resolvedPath);
12134
12183
  const dir = dirname(resolvedPath);
12135
12184
  await fs6.mkdir(dir, { recursive: true });
12136
12185
  await fs6.writeFile(resolvedPath, content, "utf-8");
@@ -30374,7 +30423,7 @@ var init_fileTracker = __esm({
30374
30423
  });
30375
30424
 
30376
30425
  // src/agent/simpleTelemetry.js
30377
- import { existsSync as existsSync3, mkdirSync, createWriteStream } from "fs";
30426
+ import { existsSync as existsSync4, mkdirSync, createWriteStream } from "fs";
30378
30427
  import { dirname as dirname2 } from "path";
30379
30428
  function initializeSimpleTelemetryFromOptions(options) {
30380
30429
  const telemetry = new SimpleTelemetry({
@@ -30403,7 +30452,7 @@ var init_simpleTelemetry = __esm({
30403
30452
  initializeFileExporter() {
30404
30453
  try {
30405
30454
  const dir = dirname2(this.filePath);
30406
- if (!existsSync3(dir)) {
30455
+ if (!existsSync4(dir)) {
30407
30456
  mkdirSync(dir, { recursive: true });
30408
30457
  }
30409
30458
  this.stream = createWriteStream(this.filePath, { flags: "a" });
@@ -70834,7 +70883,7 @@ When troubleshooting:
70834
70883
  });
70835
70884
 
70836
70885
  // src/agent/mcp/config.js
70837
- import { readFileSync, existsSync as existsSync4, mkdirSync as mkdirSync2, writeFileSync } from "fs";
70886
+ import { readFileSync, existsSync as existsSync5, mkdirSync as mkdirSync2, writeFileSync } from "fs";
70838
70887
  import { join as join2, dirname as dirname3 } from "path";
70839
70888
  import { homedir } from "os";
70840
70889
  import { fileURLToPath as fileURLToPath6 } from "url";
@@ -70889,7 +70938,7 @@ function loadMCPConfigurationFromPath(configPath) {
70889
70938
  if (!configPath) {
70890
70939
  throw new Error("Config path is required");
70891
70940
  }
70892
- if (!existsSync4(configPath)) {
70941
+ if (!existsSync5(configPath)) {
70893
70942
  throw new Error(`MCP configuration file not found: ${configPath}`);
70894
70943
  }
70895
70944
  try {
@@ -70918,7 +70967,7 @@ function loadMCPConfiguration() {
70918
70967
  ].filter(Boolean);
70919
70968
  let config = null;
70920
70969
  for (const configPath of configPaths) {
70921
- if (existsSync4(configPath)) {
70970
+ if (existsSync5(configPath)) {
70922
70971
  try {
70923
70972
  const content = readFileSync(configPath, "utf8");
70924
70973
  config = JSON.parse(content);
@@ -79122,7 +79171,7 @@ var init_parser7 = __esm({
79122
79171
  });
79123
79172
 
79124
79173
  // src/agent/skills/registry.js
79125
- import { existsSync as existsSync5 } from "fs";
79174
+ import { existsSync as existsSync6 } from "fs";
79126
79175
  import { readdir as readdir2, readFile as readFile2, realpath as realpath2, lstat as lstat2 } from "fs/promises";
79127
79176
  import { resolve as resolve6, join as join3, isAbsolute as isAbsolute5, sep as sep4, relative } from "path";
79128
79177
  function isPathInside(basePath, targetPath) {
@@ -79215,7 +79264,7 @@ var init_registry = __esm({
79215
79264
  return resolvedReal;
79216
79265
  }
79217
79266
  async _scanSkillDir(dirPath) {
79218
- if (!existsSync5(dirPath)) return [];
79267
+ if (!existsSync6(dirPath)) return [];
79219
79268
  let entries;
79220
79269
  try {
79221
79270
  entries = await readdir2(dirPath, { withFileTypes: true });
@@ -79255,7 +79304,7 @@ var init_registry = __esm({
79255
79304
  }
79256
79305
  continue;
79257
79306
  }
79258
- if (!existsSync5(skillFilePath)) continue;
79307
+ if (!existsSync6(skillFilePath)) continue;
79259
79308
  const { skill, error } = await parseSkillFile(skillFilePath, entry.name);
79260
79309
  if (!skill) {
79261
79310
  if (error) {
@@ -81771,7 +81820,7 @@ import { createAmazonBedrock as createAmazonBedrock2 } from "@ai-sdk/amazon-bedr
81771
81820
  import { streamText as streamText2, tool as tool5, stepCountIs, jsonSchema } from "ai";
81772
81821
  import { randomUUID as randomUUID5 } from "crypto";
81773
81822
  import { EventEmitter as EventEmitter5 } from "events";
81774
- import { existsSync as existsSync6 } from "fs";
81823
+ import { existsSync as existsSync7 } from "fs";
81775
81824
  import { readFile as readFile3, stat, readdir as readdir3 } from "fs/promises";
81776
81825
  import { resolve as resolve7, isAbsolute as isAbsolute6, dirname as dirname5, basename, normalize as normalize2, sep as sep5 } from "path";
81777
81826
  var ENGINE_ACTIVITY_TIMEOUT_DEFAULT, ENGINE_ACTIVITY_TIMEOUT_MIN, ENGINE_ACTIVITY_TIMEOUT_MAX, MAX_TOOL_ITERATIONS, MAX_HISTORY_MESSAGES, MAX_IMAGE_FILE_SIZE, ProbeAgent;
@@ -83782,7 +83831,7 @@ var init_ProbeAgent = __esm({
83782
83831
  } else {
83783
83832
  guidanceCandidates = ["agents.md", "claude.md"];
83784
83833
  }
83785
- if (!existsSync6(rootDirectory)) {
83834
+ if (!existsSync7(rootDirectory)) {
83786
83835
  this._architectureContextLoaded = true;
83787
83836
  return null;
83788
83837
  }
@@ -85351,7 +85400,7 @@ import {
85351
85400
  ListToolsRequestSchema as ListToolsRequestSchema2,
85352
85401
  McpError
85353
85402
  } from "@modelcontextprotocol/sdk/types.js";
85354
- import { readFileSync as readFileSync2, existsSync as existsSync7 } from "fs";
85403
+ import { readFileSync as readFileSync2, existsSync as existsSync8 } from "fs";
85355
85404
  import { resolve as resolve8 } from "path";
85356
85405
 
85357
85406
  // src/agent/acp/server.js
@@ -86027,7 +86076,7 @@ function readInputContent(input) {
86027
86076
  if (!input) return null;
86028
86077
  try {
86029
86078
  const resolvedPath = resolve8(input);
86030
- if (existsSync7(resolvedPath)) {
86079
+ if (existsSync8(resolvedPath)) {
86031
86080
  return readFileSync2(resolvedPath, "utf-8").trim();
86032
86081
  }
86033
86082
  } catch (error) {
@@ -86715,7 +86764,7 @@ async function main() {
86715
86764
  bashConfig.timeout = timeout;
86716
86765
  }
86717
86766
  if (config.bashWorkingDir) {
86718
- if (!existsSync7(config.bashWorkingDir)) {
86767
+ if (!existsSync8(config.bashWorkingDir)) {
86719
86768
  console.error(`Error: Bash working directory does not exist: ${config.bashWorkingDir}`);
86720
86769
  process.exit(1);
86721
86770
  }
@@ -10,6 +10,7 @@ import { extract } from '../extract.js';
10
10
  import { delegate } from '../delegate.js';
11
11
  import { analyzeAll } from './analyzeAll.js';
12
12
  import { searchSchema, querySchema, extractSchema, delegateSchema, analyzeAllSchema, searchDescription, queryDescription, extractDescription, delegateDescription, analyzeAllDescription, parseTargets, parseAndResolvePaths, resolveTargetPath } from './common.js';
13
+ import { existsSync } from 'fs';
13
14
  import { formatErrorForAI } from '../utils/error-types.js';
14
15
  import { annotateOutputWithHashes } from './hashline.js';
15
16
 
@@ -118,6 +119,18 @@ function parseDelegatedTargets(rawResponse) {
118
119
  return normalizeTargets(fallbackTargetsFromText(trimmed));
119
120
  }
120
121
 
122
+ function splitTargetSuffix(target) {
123
+ const searchStart = (target.length > 2 && target[1] === ':' && /[a-zA-Z]/.test(target[0])) ? 2 : 0;
124
+ const colonIdx = target.indexOf(':', searchStart);
125
+ const hashIdx = target.indexOf('#');
126
+ if (colonIdx !== -1 && (hashIdx === -1 || colonIdx < hashIdx)) {
127
+ return { filePart: target.substring(0, colonIdx), suffix: target.substring(colonIdx) };
128
+ } else if (hashIdx !== -1) {
129
+ return { filePart: target.substring(0, hashIdx), suffix: target.substring(hashIdx) };
130
+ }
131
+ return { filePart: target, suffix: '' };
132
+ }
133
+
121
134
  function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, allowTests }) {
122
135
  return [
123
136
  'You are a code-search subagent. Your job is to find ALL relevant code locations for the given query.',
@@ -286,13 +299,61 @@ export const searchTool = (options = {}) => {
286
299
  return fallbackResult;
287
300
  }
288
301
 
289
- // Resolve relative paths against the actual search directory, not the general cwd.
290
- // The delegate returns paths relative to where the search was performed (searchPaths[0]),
291
- // which may differ from options.cwd when the user specifies a path parameter.
302
+ // The delegate runs from workspace root (allowedFolders[0] or cwd), NOT from searchPaths[0].
303
+ // It returns paths relative to that workspace root. Resolve against the same base.
304
+ const delegateBase = options.allowedFolders?.[0] || options.cwd || '.';
292
305
  const resolutionBase = searchPaths[0] || options.cwd || '.';
293
- const resolvedTargets = targets.map(target => resolveTargetPath(target, resolutionBase));
306
+ const resolvedTargets = targets.map(target => resolveTargetPath(target, delegateBase));
307
+
308
+ // Auto-fix: detect and repair invalid paths (doubled segments, AI hallucinations)
309
+ const validatedTargets = [];
310
+ for (const target of resolvedTargets) {
311
+ const { filePart, suffix } = splitTargetSuffix(target);
312
+
313
+ // 1. Path exists as-is
314
+ if (existsSync(filePart)) {
315
+ validatedTargets.push(target);
316
+ continue;
317
+ }
318
+
319
+ // 2. Detect doubled directory segments: /ws/proj/proj/src → /ws/proj/src
320
+ let fixed = false;
321
+ const parts = filePart.split('/').filter(Boolean);
322
+ for (let i = 0; i < parts.length - 1; i++) {
323
+ if (parts[i] === parts[i + 1]) {
324
+ const candidate = '/' + [...parts.slice(0, i), ...parts.slice(i + 1)].join('/');
325
+ if (existsSync(candidate)) {
326
+ validatedTargets.push(candidate + suffix);
327
+ if (debug) console.error(`[search-delegate] Fixed doubled path segment: ${filePart} → ${candidate}`);
328
+ fixed = true;
329
+ break;
330
+ }
331
+ }
332
+ }
333
+ if (fixed) continue;
334
+
335
+ // 3. Try resolving against alternative bases (searchPaths[0], cwd)
336
+ for (const altBase of [resolutionBase, options.cwd].filter(Boolean)) {
337
+ if (altBase === delegateBase) continue;
338
+ const altResolved = resolveTargetPath(target, altBase);
339
+ const { filePart: altFile } = splitTargetSuffix(altResolved);
340
+ if (existsSync(altFile)) {
341
+ validatedTargets.push(altResolved);
342
+ if (debug) console.error(`[search-delegate] Resolved with alt base: ${filePart} → ${altFile}`);
343
+ fixed = true;
344
+ break;
345
+ }
346
+ }
347
+ if (fixed) continue;
348
+
349
+ // 4. Keep target anyway (probe binary will report the error)
350
+ // but log a warning
351
+ if (debug) console.error(`[search-delegate] Warning: target may not exist: ${filePart}`);
352
+ validatedTargets.push(target);
353
+ }
354
+
294
355
  const extractOptions = {
295
- files: resolvedTargets,
356
+ files: validatedTargets,
296
357
  cwd: resolutionBase,
297
358
  allowTests: allow_tests ?? true
298
359
  };
@@ -36502,6 +36502,17 @@ function parseDelegatedTargets(rawResponse) {
36502
36502
  }
36503
36503
  return normalizeTargets(fallbackTargetsFromText(trimmed));
36504
36504
  }
36505
+ function splitTargetSuffix(target) {
36506
+ const searchStart = target.length > 2 && target[1] === ":" && /[a-zA-Z]/.test(target[0]) ? 2 : 0;
36507
+ const colonIdx = target.indexOf(":", searchStart);
36508
+ const hashIdx = target.indexOf("#");
36509
+ if (colonIdx !== -1 && (hashIdx === -1 || colonIdx < hashIdx)) {
36510
+ return { filePart: target.substring(0, colonIdx), suffix: target.substring(colonIdx) };
36511
+ } else if (hashIdx !== -1) {
36512
+ return { filePart: target.substring(0, hashIdx), suffix: target.substring(hashIdx) };
36513
+ }
36514
+ return { filePart: target, suffix: "" };
36515
+ }
36505
36516
  function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, allowTests }) {
36506
36517
  return [
36507
36518
  "You are a code-search subagent. Your job is to find ALL relevant code locations for the given query.",
@@ -36530,7 +36541,7 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
36530
36541
  "Deduplicate targets. Do NOT explain or answer - ONLY return the JSON targets."
36531
36542
  ].join("\n");
36532
36543
  }
36533
- var import_ai, CODE_SEARCH_SCHEMA, searchTool, queryTool, extractTool, delegateTool, analyzeAllTool;
36544
+ var import_ai, import_fs4, CODE_SEARCH_SCHEMA, searchTool, queryTool, extractTool, delegateTool, analyzeAllTool;
36534
36545
  var init_vercel = __esm({
36535
36546
  "src/tools/vercel.js"() {
36536
36547
  "use strict";
@@ -36541,6 +36552,7 @@ var init_vercel = __esm({
36541
36552
  init_delegate();
36542
36553
  init_analyzeAll();
36543
36554
  init_common2();
36555
+ import_fs4 = require("fs");
36544
36556
  init_error_types();
36545
36557
  init_hashline();
36546
36558
  CODE_SEARCH_SCHEMA = {
@@ -36666,10 +36678,47 @@ var init_vercel = __esm({
36666
36678
  }
36667
36679
  return fallbackResult;
36668
36680
  }
36681
+ const delegateBase = options.allowedFolders?.[0] || options.cwd || ".";
36669
36682
  const resolutionBase = searchPaths[0] || options.cwd || ".";
36670
- const resolvedTargets = targets.map((target) => resolveTargetPath(target, resolutionBase));
36683
+ const resolvedTargets = targets.map((target) => resolveTargetPath(target, delegateBase));
36684
+ const validatedTargets = [];
36685
+ for (const target of resolvedTargets) {
36686
+ const { filePart, suffix } = splitTargetSuffix(target);
36687
+ if ((0, import_fs4.existsSync)(filePart)) {
36688
+ validatedTargets.push(target);
36689
+ continue;
36690
+ }
36691
+ let fixed = false;
36692
+ const parts = filePart.split("/").filter(Boolean);
36693
+ for (let i5 = 0; i5 < parts.length - 1; i5++) {
36694
+ if (parts[i5] === parts[i5 + 1]) {
36695
+ const candidate = "/" + [...parts.slice(0, i5), ...parts.slice(i5 + 1)].join("/");
36696
+ if ((0, import_fs4.existsSync)(candidate)) {
36697
+ validatedTargets.push(candidate + suffix);
36698
+ if (debug) console.error(`[search-delegate] Fixed doubled path segment: ${filePart} \u2192 ${candidate}`);
36699
+ fixed = true;
36700
+ break;
36701
+ }
36702
+ }
36703
+ }
36704
+ if (fixed) continue;
36705
+ for (const altBase of [resolutionBase, options.cwd].filter(Boolean)) {
36706
+ if (altBase === delegateBase) continue;
36707
+ const altResolved = resolveTargetPath(target, altBase);
36708
+ const { filePart: altFile } = splitTargetSuffix(altResolved);
36709
+ if ((0, import_fs4.existsSync)(altFile)) {
36710
+ validatedTargets.push(altResolved);
36711
+ if (debug) console.error(`[search-delegate] Resolved with alt base: ${filePart} \u2192 ${altFile}`);
36712
+ fixed = true;
36713
+ break;
36714
+ }
36715
+ }
36716
+ if (fixed) continue;
36717
+ if (debug) console.error(`[search-delegate] Warning: target may not exist: ${filePart}`);
36718
+ validatedTargets.push(target);
36719
+ }
36671
36720
  const extractOptions = {
36672
- files: resolvedTargets,
36721
+ files: validatedTargets,
36673
36722
  cwd: resolutionBase,
36674
36723
  allowTests: allow_tests ?? true
36675
36724
  };
@@ -38314,7 +38363,7 @@ async function executeBashCommand(command, options = {}) {
38314
38363
  let cwd = workingDirectory;
38315
38364
  try {
38316
38365
  cwd = (0, import_path6.resolve)(cwd);
38317
- if (!(0, import_fs4.existsSync)(cwd)) {
38366
+ if (!(0, import_fs5.existsSync)(cwd)) {
38318
38367
  throw new Error(`Working directory does not exist: ${cwd}`);
38319
38368
  }
38320
38369
  } catch (error2) {
@@ -38570,7 +38619,7 @@ function validateExecutionOptions(options = {}) {
38570
38619
  if (options.workingDirectory) {
38571
38620
  if (typeof options.workingDirectory !== "string") {
38572
38621
  errors.push("workingDirectory must be a string");
38573
- } else if (!(0, import_fs4.existsSync)(options.workingDirectory)) {
38622
+ } else if (!(0, import_fs5.existsSync)(options.workingDirectory)) {
38574
38623
  errors.push(`workingDirectory does not exist: ${options.workingDirectory}`);
38575
38624
  }
38576
38625
  }
@@ -38583,13 +38632,13 @@ function validateExecutionOptions(options = {}) {
38583
38632
  warnings
38584
38633
  };
38585
38634
  }
38586
- var import_child_process6, import_path6, import_fs4;
38635
+ var import_child_process6, import_path6, import_fs5;
38587
38636
  var init_bashExecutor = __esm({
38588
38637
  "src/agent/bashExecutor.js"() {
38589
38638
  "use strict";
38590
38639
  import_child_process6 = require("child_process");
38591
38640
  import_path6 = require("path");
38592
- import_fs4 = require("fs");
38641
+ import_fs5 = require("fs");
38593
38642
  init_bashCommandUtils();
38594
38643
  }
38595
38644
  });
@@ -39147,7 +39196,7 @@ Example: <edit><file_path>${file_path}</file_path><symbol>${allMatches[0].qualif
39147
39196
  Example: <extract><targets>${file_path}#${symbol15}</targets></extract>`;
39148
39197
  }
39149
39198
  }
39150
- const content = await import_fs5.promises.readFile(resolvedPath2, "utf-8");
39199
+ const content = await import_fs6.promises.readFile(resolvedPath2, "utf-8");
39151
39200
  const lines = content.split("\n");
39152
39201
  if (position) {
39153
39202
  const refIndent = detectBaseIndent(symbolInfo.code);
@@ -39158,7 +39207,7 @@ Example: <extract><targets>${file_path}#${symbol15}</targets></extract>`;
39158
39207
  } else {
39159
39208
  lines.splice(symbolInfo.startLine - 1, 0, ...newLines, "");
39160
39209
  }
39161
- await import_fs5.promises.writeFile(resolvedPath2, lines.join("\n"), "utf-8");
39210
+ await import_fs6.promises.writeFile(resolvedPath2, lines.join("\n"), "utf-8");
39162
39211
  if (fileTracker) {
39163
39212
  const updated = await findSymbol(resolvedPath2, symbol15, cwd || process.cwd());
39164
39213
  if (updated) {
@@ -39176,7 +39225,7 @@ Example: <extract><targets>${file_path}#${symbol15}</targets></extract>`;
39176
39225
  const reindented = reindent(new_string, originalIndent);
39177
39226
  const newLines = reindented.split("\n");
39178
39227
  lines.splice(symbolInfo.startLine - 1, symbolInfo.endLine - symbolInfo.startLine + 1, ...newLines);
39179
- await import_fs5.promises.writeFile(resolvedPath2, lines.join("\n"), "utf-8");
39228
+ await import_fs6.promises.writeFile(resolvedPath2, lines.join("\n"), "utf-8");
39180
39229
  if (fileTracker) {
39181
39230
  const updated = await findSymbol(resolvedPath2, symbol15, cwd || process.cwd());
39182
39231
  if (updated) {
@@ -39231,7 +39280,7 @@ async function handleLineEdit({ resolvedPath: resolvedPath2, file_path, start_li
39231
39280
  if (position !== void 0 && position !== null && position !== "before" && position !== "after") {
39232
39281
  return 'Error editing file: Invalid position - must be "before" or "after". Use position="before" to insert before the line, or position="after" to insert after it.';
39233
39282
  }
39234
- const content = await import_fs5.promises.readFile(resolvedPath2, "utf-8");
39283
+ const content = await import_fs6.promises.readFile(resolvedPath2, "utf-8");
39235
39284
  const fileLines = content.split("\n");
39236
39285
  if (startLine > fileLines.length) {
39237
39286
  return `Error editing file: Line ${startLine} is beyond file length (${fileLines.length} lines). Use 'extract' to read the current file content.`;
@@ -39260,20 +39309,20 @@ async function handleLineEdit({ resolvedPath: resolvedPath2, file_path, start_li
39260
39309
  const newLines = cleaned === "" ? [] : cleaned.split("\n");
39261
39310
  if (position === "after") {
39262
39311
  fileLines.splice(startLine, 0, ...newLines);
39263
- await import_fs5.promises.writeFile(resolvedPath2, fileLines.join("\n"), "utf-8");
39312
+ await import_fs6.promises.writeFile(resolvedPath2, fileLines.join("\n"), "utf-8");
39264
39313
  if (fileTracker) await fileTracker.trackFileAfterWrite(resolvedPath2);
39265
39314
  const action = `${newLines.length} line${newLines.length !== 1 ? "s" : ""} inserted after line ${startLine}`;
39266
39315
  return buildLineEditResponse(file_path, startLine, startLine, newLines.length, fileLines, startLine, action, modifications);
39267
39316
  } else if (position === "before") {
39268
39317
  fileLines.splice(startLine - 1, 0, ...newLines);
39269
- await import_fs5.promises.writeFile(resolvedPath2, fileLines.join("\n"), "utf-8");
39318
+ await import_fs6.promises.writeFile(resolvedPath2, fileLines.join("\n"), "utf-8");
39270
39319
  if (fileTracker) await fileTracker.trackFileAfterWrite(resolvedPath2);
39271
39320
  const action = `${newLines.length} line${newLines.length !== 1 ? "s" : ""} inserted before line ${startLine}`;
39272
39321
  return buildLineEditResponse(file_path, startLine, startLine, newLines.length, fileLines, startLine - 1, action, modifications);
39273
39322
  } else {
39274
39323
  const replacedCount = endLine - startLine + 1;
39275
39324
  fileLines.splice(startLine - 1, replacedCount, ...newLines);
39276
- await import_fs5.promises.writeFile(resolvedPath2, fileLines.join("\n"), "utf-8");
39325
+ await import_fs6.promises.writeFile(resolvedPath2, fileLines.join("\n"), "utf-8");
39277
39326
  if (fileTracker) await fileTracker.trackFileAfterWrite(resolvedPath2);
39278
39327
  let action;
39279
39328
  if (newLines.length === 0) {
@@ -39286,14 +39335,14 @@ async function handleLineEdit({ resolvedPath: resolvedPath2, file_path, start_li
39286
39335
  return buildLineEditResponse(file_path, startLine, endLine, newLines.length, fileLines, startLine - 1, action, modifications);
39287
39336
  }
39288
39337
  }
39289
- var import_ai3, import_fs5, import_path8, import_fs6, editTool, createTool, multiEditTool, editSchema, createSchema, multiEditSchema, editDescription, createDescription, multiEditDescription, editToolDefinition, createToolDefinition, multiEditToolDefinition;
39338
+ var import_ai3, import_fs6, import_path8, import_fs7, editTool, createTool, multiEditTool, editSchema, createSchema, multiEditSchema, editDescription, createDescription, multiEditDescription, editToolDefinition, createToolDefinition, multiEditToolDefinition;
39290
39339
  var init_edit = __esm({
39291
39340
  "src/tools/edit.js"() {
39292
39341
  "use strict";
39293
39342
  import_ai3 = require("ai");
39294
- import_fs5 = require("fs");
39295
- import_path8 = require("path");
39296
39343
  import_fs6 = require("fs");
39344
+ import_path8 = require("path");
39345
+ import_fs7 = require("fs");
39297
39346
  init_path_validation();
39298
39347
  init_fuzzyMatch();
39299
39348
  init_symbolEdit();
@@ -39377,7 +39426,7 @@ Parameters:
39377
39426
  const relativePath = toRelativePath(resolvedPath2, workspaceRoot);
39378
39427
  return `Error editing file: Permission denied - ${relativePath} is outside allowed directories. Use a file path within the project workspace.`;
39379
39428
  }
39380
- if (!(0, import_fs6.existsSync)(resolvedPath2)) {
39429
+ if (!(0, import_fs7.existsSync)(resolvedPath2)) {
39381
39430
  return `Error editing file: File not found - ${file_path}. Verify the path is correct and the file exists. Use 'search' to find files by name, or 'create' to make a new file.`;
39382
39431
  }
39383
39432
  if (options.fileTracker && !options.fileTracker.isFileSeen(resolvedPath2)) {
@@ -39407,7 +39456,7 @@ Example: <extract><targets>${displayPath}</targets></extract>`;
39407
39456
  Example: <extract><targets>${displayPath}</targets></extract>`;
39408
39457
  }
39409
39458
  }
39410
- const content = await import_fs5.promises.readFile(resolvedPath2, "utf-8");
39459
+ const content = await import_fs6.promises.readFile(resolvedPath2, "utf-8");
39411
39460
  let matchTarget = old_string;
39412
39461
  let matchStrategy = "exact";
39413
39462
  if (!content.includes(old_string)) {
@@ -39439,7 +39488,7 @@ Example: <extract><targets>${displayPath}</targets></extract>`;
39439
39488
  if (newContent === content) {
39440
39489
  return `Error editing file: No changes made - the replacement result is identical to the original. Verify that old_string and new_string are actually different. If fuzzy matching was used, the matched text may already equal new_string.`;
39441
39490
  }
39442
- await import_fs5.promises.writeFile(resolvedPath2, newContent, "utf-8");
39491
+ await import_fs6.promises.writeFile(resolvedPath2, newContent, "utf-8");
39443
39492
  if (options.fileTracker) {
39444
39493
  await options.fileTracker.trackFileAfterWrite(resolvedPath2);
39445
39494
  options.fileTracker.recordTextEdit(resolvedPath2);
@@ -39510,13 +39559,13 @@ Important:
39510
39559
  const relativePath = toRelativePath(resolvedPath2, workspaceRoot);
39511
39560
  return `Error creating file: Permission denied - ${relativePath} is outside allowed directories. Use a file path within the project workspace.`;
39512
39561
  }
39513
- if ((0, import_fs6.existsSync)(resolvedPath2) && !overwrite) {
39562
+ if ((0, import_fs7.existsSync)(resolvedPath2) && !overwrite) {
39514
39563
  return `Error creating file: File already exists - ${file_path}. Use overwrite: true to replace it.`;
39515
39564
  }
39516
- const existed = (0, import_fs6.existsSync)(resolvedPath2);
39565
+ const existed = (0, import_fs7.existsSync)(resolvedPath2);
39517
39566
  const dir = (0, import_path8.dirname)(resolvedPath2);
39518
- await import_fs5.promises.mkdir(dir, { recursive: true });
39519
- await import_fs5.promises.writeFile(resolvedPath2, content, "utf-8");
39567
+ await import_fs6.promises.mkdir(dir, { recursive: true });
39568
+ await import_fs6.promises.writeFile(resolvedPath2, content, "utf-8");
39520
39569
  if (options.fileTracker) await options.fileTracker.trackFileAfterWrite(resolvedPath2);
39521
39570
  const action = existed && overwrite ? "overwrote" : "created";
39522
39571
  const bytes = Buffer.byteLength(content, "utf-8");
@@ -53822,22 +53871,22 @@ var init_esm3 = __esm({
53822
53871
  });
53823
53872
 
53824
53873
  // node_modules/path-scurry/dist/esm/index.js
53825
- var import_node_path, import_node_url, import_fs7, actualFS, import_promises, realpathSync2, defaultFS, fsFromOption, uncDriveRegexp, uncToDrive, eitherSep, UNKNOWN, IFIFO, IFCHR, IFDIR, IFBLK, IFREG, IFLNK, IFSOCK, IFMT, IFMT_UNKNOWN, READDIR_CALLED, LSTAT_CALLED, ENOTDIR, ENOENT, ENOREADLINK, ENOREALPATH, ENOCHILD, TYPEMASK, entToType, normalizeCache, normalize, normalizeNocaseCache, normalizeNocase, ResolveCache, ChildrenCache, setAsCwd, PathBase, PathWin32, PathPosix, PathScurryBase, PathScurryWin32, PathScurryPosix, PathScurryDarwin, Path, PathScurry;
53874
+ var import_node_path, import_node_url, import_fs8, actualFS, import_promises, realpathSync2, defaultFS, fsFromOption, uncDriveRegexp, uncToDrive, eitherSep, UNKNOWN, IFIFO, IFCHR, IFDIR, IFBLK, IFREG, IFLNK, IFSOCK, IFMT, IFMT_UNKNOWN, READDIR_CALLED, LSTAT_CALLED, ENOTDIR, ENOENT, ENOREADLINK, ENOREALPATH, ENOCHILD, TYPEMASK, entToType, normalizeCache, normalize, normalizeNocaseCache, normalizeNocase, ResolveCache, ChildrenCache, setAsCwd, PathBase, PathWin32, PathPosix, PathScurryBase, PathScurryWin32, PathScurryPosix, PathScurryDarwin, Path, PathScurry;
53826
53875
  var init_esm4 = __esm({
53827
53876
  "node_modules/path-scurry/dist/esm/index.js"() {
53828
53877
  init_esm2();
53829
53878
  import_node_path = require("node:path");
53830
53879
  import_node_url = require("node:url");
53831
- import_fs7 = require("fs");
53880
+ import_fs8 = require("fs");
53832
53881
  actualFS = __toESM(require("node:fs"), 1);
53833
53882
  import_promises = require("node:fs/promises");
53834
53883
  init_esm3();
53835
- realpathSync2 = import_fs7.realpathSync.native;
53884
+ realpathSync2 = import_fs8.realpathSync.native;
53836
53885
  defaultFS = {
53837
- lstatSync: import_fs7.lstatSync,
53838
- readdir: import_fs7.readdir,
53839
- readdirSync: import_fs7.readdirSync,
53840
- readlinkSync: import_fs7.readlinkSync,
53886
+ lstatSync: import_fs8.lstatSync,
53887
+ readdir: import_fs8.readdir,
53888
+ readdirSync: import_fs8.readdirSync,
53889
+ readlinkSync: import_fs8.readlinkSync,
53841
53890
  realpathSync: realpathSync2,
53842
53891
  promises: {
53843
53892
  lstat: import_promises.lstat,
@@ -57366,10 +57415,10 @@ async function listFilesByLevel(options) {
57366
57415
  maxFiles = 100,
57367
57416
  respectGitignore = true
57368
57417
  } = options;
57369
- if (!import_fs8.default.existsSync(directory)) {
57418
+ if (!import_fs9.default.existsSync(directory)) {
57370
57419
  throw new Error(`Directory does not exist: ${directory}`);
57371
57420
  }
57372
- const gitDirExists = import_fs8.default.existsSync(import_path9.default.join(directory, ".git"));
57421
+ const gitDirExists = import_fs9.default.existsSync(import_path9.default.join(directory, ".git"));
57373
57422
  if (gitDirExists && respectGitignore) {
57374
57423
  try {
57375
57424
  return await listFilesUsingGit(directory, maxFiles);
@@ -57400,7 +57449,7 @@ async function listFilesByLevelManually(directory, maxFiles, respectGitignore) {
57400
57449
  while (queue.length > 0 && result.length < maxFiles) {
57401
57450
  const { dir, level } = queue.shift();
57402
57451
  try {
57403
- const entries = import_fs8.default.readdirSync(dir, { withFileTypes: true });
57452
+ const entries = import_fs9.default.readdirSync(dir, { withFileTypes: true });
57404
57453
  const files = entries.filter((entry) => {
57405
57454
  const fullPath = import_path9.default.join(dir, entry.name);
57406
57455
  return getEntryTypeSync(entry, fullPath).isFile;
@@ -57431,11 +57480,11 @@ async function listFilesByLevelManually(directory, maxFiles, respectGitignore) {
57431
57480
  }
57432
57481
  function loadGitignorePatterns(directory) {
57433
57482
  const gitignorePath = import_path9.default.join(directory, ".gitignore");
57434
- if (!import_fs8.default.existsSync(gitignorePath)) {
57483
+ if (!import_fs9.default.existsSync(gitignorePath)) {
57435
57484
  return [];
57436
57485
  }
57437
57486
  try {
57438
- const content = import_fs8.default.readFileSync(gitignorePath, "utf8");
57487
+ const content = import_fs9.default.readFileSync(gitignorePath, "utf8");
57439
57488
  return content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
57440
57489
  } catch (error2) {
57441
57490
  console.error(`Warning: Could not read .gitignore: ${error2.message}`);
@@ -57453,11 +57502,11 @@ function shouldIgnore(filePath, ignorePatterns) {
57453
57502
  }
57454
57503
  return false;
57455
57504
  }
57456
- var import_fs8, import_path9, import_util11, import_child_process7, execAsync3;
57505
+ var import_fs9, import_path9, import_util11, import_child_process7, execAsync3;
57457
57506
  var init_file_lister = __esm({
57458
57507
  "src/utils/file-lister.js"() {
57459
57508
  "use strict";
57460
- import_fs8 = __toESM(require("fs"), 1);
57509
+ import_fs9 = __toESM(require("fs"), 1);
57461
57510
  import_path9 = __toESM(require("path"), 1);
57462
57511
  import_util11 = require("util");
57463
57512
  import_child_process7 = require("child_process");
@@ -57757,11 +57806,11 @@ var init_fileTracker = __esm({
57757
57806
  });
57758
57807
 
57759
57808
  // src/agent/simpleTelemetry.js
57760
- var import_fs9, import_path11;
57809
+ var import_fs10, import_path11;
57761
57810
  var init_simpleTelemetry = __esm({
57762
57811
  "src/agent/simpleTelemetry.js"() {
57763
57812
  "use strict";
57764
- import_fs9 = require("fs");
57813
+ import_fs10 = require("fs");
57765
57814
  import_path11 = require("path");
57766
57815
  }
57767
57816
  });
@@ -57868,7 +57917,7 @@ function createWrappedTools(baseTools) {
57868
57917
  }
57869
57918
  return wrappedTools;
57870
57919
  }
57871
- var import_child_process8, import_util12, import_crypto4, import_events, import_fs10, import_fs11, import_path12, toolCallEmitter, activeToolExecutions, wrapToolWithEmitter, listFilesTool, searchFilesTool, listFilesToolInstance, searchFilesToolInstance;
57920
+ var import_child_process8, import_util12, import_crypto4, import_events, import_fs11, import_fs12, import_path12, toolCallEmitter, activeToolExecutions, wrapToolWithEmitter, listFilesTool, searchFilesTool, listFilesToolInstance, searchFilesToolInstance;
57872
57921
  var init_probeTool = __esm({
57873
57922
  "src/agent/probeTool.js"() {
57874
57923
  "use strict";
@@ -57877,8 +57926,8 @@ var init_probeTool = __esm({
57877
57926
  import_util12 = require("util");
57878
57927
  import_crypto4 = require("crypto");
57879
57928
  import_events = require("events");
57880
- import_fs10 = __toESM(require("fs"), 1);
57881
- import_fs11 = require("fs");
57929
+ import_fs11 = __toESM(require("fs"), 1);
57930
+ import_fs12 = require("fs");
57882
57931
  import_path12 = __toESM(require("path"), 1);
57883
57932
  init_esm5();
57884
57933
  init_symlink_utils();
@@ -57987,7 +58036,7 @@ var init_probeTool = __esm({
57987
58036
  console.log(`[DEBUG] Listing files in directory: ${targetDir}`);
57988
58037
  }
57989
58038
  try {
57990
- const files = await import_fs11.promises.readdir(targetDir, { withFileTypes: true });
58039
+ const files = await import_fs12.promises.readdir(targetDir, { withFileTypes: true });
57991
58040
  const formatSize = (size) => {
57992
58041
  if (size < 1024) return `${size}B`;
57993
58042
  if (size < 1024 * 1024) return `${(size / 1024).toFixed(1)}K`;
@@ -97834,11 +97883,11 @@ function loadMCPConfigurationFromPath(configPath) {
97834
97883
  if (!configPath) {
97835
97884
  throw new Error("Config path is required");
97836
97885
  }
97837
- if (!(0, import_fs12.existsSync)(configPath)) {
97886
+ if (!(0, import_fs13.existsSync)(configPath)) {
97838
97887
  throw new Error(`MCP configuration file not found: ${configPath}`);
97839
97888
  }
97840
97889
  try {
97841
- const content = (0, import_fs12.readFileSync)(configPath, "utf8");
97890
+ const content = (0, import_fs13.readFileSync)(configPath, "utf8");
97842
97891
  const config = JSON.parse(content);
97843
97892
  if (process.env.DEBUG === "1" || process.env.DEBUG_MCP === "1") {
97844
97893
  console.error(`[MCP DEBUG] Loaded configuration from: ${configPath}`);
@@ -97863,9 +97912,9 @@ function loadMCPConfiguration() {
97863
97912
  ].filter(Boolean);
97864
97913
  let config = null;
97865
97914
  for (const configPath of configPaths) {
97866
- if ((0, import_fs12.existsSync)(configPath)) {
97915
+ if ((0, import_fs13.existsSync)(configPath)) {
97867
97916
  try {
97868
- const content = (0, import_fs12.readFileSync)(configPath, "utf8");
97917
+ const content = (0, import_fs13.readFileSync)(configPath, "utf8");
97869
97918
  config = JSON.parse(content);
97870
97919
  if (process.env.DEBUG === "1" || process.env.DEBUG_MCP === "1") {
97871
97920
  console.error(`[MCP DEBUG] Loaded configuration from: ${configPath}`);
@@ -97986,11 +98035,11 @@ function parseEnabledServers(config) {
97986
98035
  }
97987
98036
  return servers;
97988
98037
  }
97989
- var import_fs12, import_path13, import_os3, import_url4, __filename4, __dirname5, DEFAULT_TIMEOUT, MAX_TIMEOUT, DEFAULT_CONFIG;
98038
+ var import_fs13, import_path13, import_os3, import_url4, __filename4, __dirname5, DEFAULT_TIMEOUT, MAX_TIMEOUT, DEFAULT_CONFIG;
97990
98039
  var init_config = __esm({
97991
98040
  "src/agent/mcp/config.js"() {
97992
98041
  "use strict";
97993
- import_fs12 = require("fs");
98042
+ import_fs13 = require("fs");
97994
98043
  import_path13 = require("path");
97995
98044
  import_os3 = require("os");
97996
98045
  import_url4 = require("url");
@@ -106085,11 +106134,11 @@ function isSafeEntryName(name14) {
106085
106134
  if (name14.includes("\0")) return false;
106086
106135
  return !name14.includes("/") && !name14.includes("\\");
106087
106136
  }
106088
- var import_fs13, import_promises3, import_path15, DEFAULT_SKILL_DIRS, SKILL_FILE_NAME, SkillRegistry;
106137
+ var import_fs14, import_promises3, import_path15, DEFAULT_SKILL_DIRS, SKILL_FILE_NAME, SkillRegistry;
106089
106138
  var init_registry = __esm({
106090
106139
  "src/agent/skills/registry.js"() {
106091
106140
  "use strict";
106092
- import_fs13 = require("fs");
106141
+ import_fs14 = require("fs");
106093
106142
  import_promises3 = require("fs/promises");
106094
106143
  import_path15 = require("path");
106095
106144
  init_parser7();
@@ -106164,7 +106213,7 @@ var init_registry = __esm({
106164
106213
  return resolvedReal;
106165
106214
  }
106166
106215
  async _scanSkillDir(dirPath) {
106167
- if (!(0, import_fs13.existsSync)(dirPath)) return [];
106216
+ if (!(0, import_fs14.existsSync)(dirPath)) return [];
106168
106217
  let entries;
106169
106218
  try {
106170
106219
  entries = await (0, import_promises3.readdir)(dirPath, { withFileTypes: true });
@@ -106204,7 +106253,7 @@ var init_registry = __esm({
106204
106253
  }
106205
106254
  continue;
106206
106255
  }
106207
- if (!(0, import_fs13.existsSync)(skillFilePath)) continue;
106256
+ if (!(0, import_fs14.existsSync)(skillFilePath)) continue;
106208
106257
  const { skill, error: error2 } = await parseSkillFile(skillFilePath, entry.name);
106209
106258
  if (!skill) {
106210
106259
  if (error2) {
@@ -108712,7 +108761,7 @@ __export(ProbeAgent_exports, {
108712
108761
  ProbeAgent: () => ProbeAgent
108713
108762
  });
108714
108763
  module.exports = __toCommonJS(ProbeAgent_exports);
108715
- var import_dotenv2, import_anthropic2, import_openai2, import_google2, import_ai6, import_crypto9, import_events4, import_fs14, import_promises6, import_path18, ENGINE_ACTIVITY_TIMEOUT_DEFAULT, ENGINE_ACTIVITY_TIMEOUT_MIN, ENGINE_ACTIVITY_TIMEOUT_MAX, MAX_TOOL_ITERATIONS, MAX_HISTORY_MESSAGES, MAX_IMAGE_FILE_SIZE, ProbeAgent;
108764
+ var import_dotenv2, import_anthropic2, import_openai2, import_google2, import_ai6, import_crypto9, import_events4, import_fs15, import_promises6, import_path18, ENGINE_ACTIVITY_TIMEOUT_DEFAULT, ENGINE_ACTIVITY_TIMEOUT_MIN, ENGINE_ACTIVITY_TIMEOUT_MAX, MAX_TOOL_ITERATIONS, MAX_HISTORY_MESSAGES, MAX_IMAGE_FILE_SIZE, ProbeAgent;
108716
108765
  var init_ProbeAgent = __esm({
108717
108766
  "src/agent/ProbeAgent.js"() {
108718
108767
  import_dotenv2 = __toESM(require_main(), 1);
@@ -108723,7 +108772,7 @@ var init_ProbeAgent = __esm({
108723
108772
  import_ai6 = require("ai");
108724
108773
  import_crypto9 = require("crypto");
108725
108774
  import_events4 = require("events");
108726
- import_fs14 = require("fs");
108775
+ import_fs15 = require("fs");
108727
108776
  import_promises6 = require("fs/promises");
108728
108777
  import_path18 = require("path");
108729
108778
  init_tokenCounter();
@@ -110730,7 +110779,7 @@ var init_ProbeAgent = __esm({
110730
110779
  } else {
110731
110780
  guidanceCandidates = ["agents.md", "claude.md"];
110732
110781
  }
110733
- if (!(0, import_fs14.existsSync)(rootDirectory)) {
110782
+ if (!(0, import_fs15.existsSync)(rootDirectory)) {
110734
110783
  this._architectureContextLoaded = true;
110735
110784
  return null;
110736
110785
  }
package/cjs/index.cjs CHANGED
@@ -110630,6 +110630,17 @@ function parseDelegatedTargets(rawResponse) {
110630
110630
  }
110631
110631
  return normalizeTargets(fallbackTargetsFromText(trimmed));
110632
110632
  }
110633
+ function splitTargetSuffix(target) {
110634
+ const searchStart = target.length > 2 && target[1] === ":" && /[a-zA-Z]/.test(target[0]) ? 2 : 0;
110635
+ const colonIdx = target.indexOf(":", searchStart);
110636
+ const hashIdx = target.indexOf("#");
110637
+ if (colonIdx !== -1 && (hashIdx === -1 || colonIdx < hashIdx)) {
110638
+ return { filePart: target.substring(0, colonIdx), suffix: target.substring(colonIdx) };
110639
+ } else if (hashIdx !== -1) {
110640
+ return { filePart: target.substring(0, hashIdx), suffix: target.substring(hashIdx) };
110641
+ }
110642
+ return { filePart: target, suffix: "" };
110643
+ }
110633
110644
  function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, allowTests }) {
110634
110645
  return [
110635
110646
  "You are a code-search subagent. Your job is to find ALL relevant code locations for the given query.",
@@ -110658,7 +110669,7 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
110658
110669
  "Deduplicate targets. Do NOT explain or answer - ONLY return the JSON targets."
110659
110670
  ].join("\n");
110660
110671
  }
110661
- var import_ai5, CODE_SEARCH_SCHEMA, searchTool, queryTool, extractTool, delegateTool, analyzeAllTool;
110672
+ var import_ai5, import_fs11, CODE_SEARCH_SCHEMA, searchTool, queryTool, extractTool, delegateTool, analyzeAllTool;
110662
110673
  var init_vercel = __esm({
110663
110674
  "src/tools/vercel.js"() {
110664
110675
  "use strict";
@@ -110669,6 +110680,7 @@ var init_vercel = __esm({
110669
110680
  init_delegate();
110670
110681
  init_analyzeAll();
110671
110682
  init_common2();
110683
+ import_fs11 = require("fs");
110672
110684
  init_error_types();
110673
110685
  init_hashline();
110674
110686
  CODE_SEARCH_SCHEMA = {
@@ -110794,10 +110806,47 @@ var init_vercel = __esm({
110794
110806
  }
110795
110807
  return fallbackResult;
110796
110808
  }
110809
+ const delegateBase = options.allowedFolders?.[0] || options.cwd || ".";
110797
110810
  const resolutionBase = searchPaths[0] || options.cwd || ".";
110798
- const resolvedTargets = targets.map((target) => resolveTargetPath(target, resolutionBase));
110811
+ const resolvedTargets = targets.map((target) => resolveTargetPath(target, delegateBase));
110812
+ const validatedTargets = [];
110813
+ for (const target of resolvedTargets) {
110814
+ const { filePart, suffix } = splitTargetSuffix(target);
110815
+ if ((0, import_fs11.existsSync)(filePart)) {
110816
+ validatedTargets.push(target);
110817
+ continue;
110818
+ }
110819
+ let fixed = false;
110820
+ const parts = filePart.split("/").filter(Boolean);
110821
+ for (let i5 = 0; i5 < parts.length - 1; i5++) {
110822
+ if (parts[i5] === parts[i5 + 1]) {
110823
+ const candidate = "/" + [...parts.slice(0, i5), ...parts.slice(i5 + 1)].join("/");
110824
+ if ((0, import_fs11.existsSync)(candidate)) {
110825
+ validatedTargets.push(candidate + suffix);
110826
+ if (debug) console.error(`[search-delegate] Fixed doubled path segment: ${filePart} \u2192 ${candidate}`);
110827
+ fixed = true;
110828
+ break;
110829
+ }
110830
+ }
110831
+ }
110832
+ if (fixed) continue;
110833
+ for (const altBase of [resolutionBase, options.cwd].filter(Boolean)) {
110834
+ if (altBase === delegateBase) continue;
110835
+ const altResolved = resolveTargetPath(target, altBase);
110836
+ const { filePart: altFile } = splitTargetSuffix(altResolved);
110837
+ if ((0, import_fs11.existsSync)(altFile)) {
110838
+ validatedTargets.push(altResolved);
110839
+ if (debug) console.error(`[search-delegate] Resolved with alt base: ${filePart} \u2192 ${altFile}`);
110840
+ fixed = true;
110841
+ break;
110842
+ }
110843
+ }
110844
+ if (fixed) continue;
110845
+ if (debug) console.error(`[search-delegate] Warning: target may not exist: ${filePart}`);
110846
+ validatedTargets.push(target);
110847
+ }
110799
110848
  const extractOptions = {
110800
- files: resolvedTargets,
110849
+ files: validatedTargets,
110801
110850
  cwd: resolutionBase,
110802
110851
  allowTests: allow_tests ?? true
110803
110852
  };
@@ -111350,7 +111399,7 @@ Example: <edit><file_path>${file_path}</file_path><symbol>${allMatches[0].qualif
111350
111399
  Example: <extract><targets>${file_path}#${symbol15}</targets></extract>`;
111351
111400
  }
111352
111401
  }
111353
- const content = await import_fs11.promises.readFile(resolvedPath2, "utf-8");
111402
+ const content = await import_fs12.promises.readFile(resolvedPath2, "utf-8");
111354
111403
  const lines = content.split("\n");
111355
111404
  if (position) {
111356
111405
  const refIndent = detectBaseIndent(symbolInfo.code);
@@ -111361,7 +111410,7 @@ Example: <extract><targets>${file_path}#${symbol15}</targets></extract>`;
111361
111410
  } else {
111362
111411
  lines.splice(symbolInfo.startLine - 1, 0, ...newLines, "");
111363
111412
  }
111364
- await import_fs11.promises.writeFile(resolvedPath2, lines.join("\n"), "utf-8");
111413
+ await import_fs12.promises.writeFile(resolvedPath2, lines.join("\n"), "utf-8");
111365
111414
  if (fileTracker) {
111366
111415
  const updated = await findSymbol(resolvedPath2, symbol15, cwd || process.cwd());
111367
111416
  if (updated) {
@@ -111379,7 +111428,7 @@ Example: <extract><targets>${file_path}#${symbol15}</targets></extract>`;
111379
111428
  const reindented = reindent(new_string, originalIndent);
111380
111429
  const newLines = reindented.split("\n");
111381
111430
  lines.splice(symbolInfo.startLine - 1, symbolInfo.endLine - symbolInfo.startLine + 1, ...newLines);
111382
- await import_fs11.promises.writeFile(resolvedPath2, lines.join("\n"), "utf-8");
111431
+ await import_fs12.promises.writeFile(resolvedPath2, lines.join("\n"), "utf-8");
111383
111432
  if (fileTracker) {
111384
111433
  const updated = await findSymbol(resolvedPath2, symbol15, cwd || process.cwd());
111385
111434
  if (updated) {
@@ -111434,7 +111483,7 @@ async function handleLineEdit({ resolvedPath: resolvedPath2, file_path, start_li
111434
111483
  if (position !== void 0 && position !== null && position !== "before" && position !== "after") {
111435
111484
  return 'Error editing file: Invalid position - must be "before" or "after". Use position="before" to insert before the line, or position="after" to insert after it.';
111436
111485
  }
111437
- const content = await import_fs11.promises.readFile(resolvedPath2, "utf-8");
111486
+ const content = await import_fs12.promises.readFile(resolvedPath2, "utf-8");
111438
111487
  const fileLines = content.split("\n");
111439
111488
  if (startLine > fileLines.length) {
111440
111489
  return `Error editing file: Line ${startLine} is beyond file length (${fileLines.length} lines). Use 'extract' to read the current file content.`;
@@ -111463,20 +111512,20 @@ async function handleLineEdit({ resolvedPath: resolvedPath2, file_path, start_li
111463
111512
  const newLines = cleaned === "" ? [] : cleaned.split("\n");
111464
111513
  if (position === "after") {
111465
111514
  fileLines.splice(startLine, 0, ...newLines);
111466
- await import_fs11.promises.writeFile(resolvedPath2, fileLines.join("\n"), "utf-8");
111515
+ await import_fs12.promises.writeFile(resolvedPath2, fileLines.join("\n"), "utf-8");
111467
111516
  if (fileTracker) await fileTracker.trackFileAfterWrite(resolvedPath2);
111468
111517
  const action = `${newLines.length} line${newLines.length !== 1 ? "s" : ""} inserted after line ${startLine}`;
111469
111518
  return buildLineEditResponse(file_path, startLine, startLine, newLines.length, fileLines, startLine, action, modifications);
111470
111519
  } else if (position === "before") {
111471
111520
  fileLines.splice(startLine - 1, 0, ...newLines);
111472
- await import_fs11.promises.writeFile(resolvedPath2, fileLines.join("\n"), "utf-8");
111521
+ await import_fs12.promises.writeFile(resolvedPath2, fileLines.join("\n"), "utf-8");
111473
111522
  if (fileTracker) await fileTracker.trackFileAfterWrite(resolvedPath2);
111474
111523
  const action = `${newLines.length} line${newLines.length !== 1 ? "s" : ""} inserted before line ${startLine}`;
111475
111524
  return buildLineEditResponse(file_path, startLine, startLine, newLines.length, fileLines, startLine - 1, action, modifications);
111476
111525
  } else {
111477
111526
  const replacedCount = endLine - startLine + 1;
111478
111527
  fileLines.splice(startLine - 1, replacedCount, ...newLines);
111479
- await import_fs11.promises.writeFile(resolvedPath2, fileLines.join("\n"), "utf-8");
111528
+ await import_fs12.promises.writeFile(resolvedPath2, fileLines.join("\n"), "utf-8");
111480
111529
  if (fileTracker) await fileTracker.trackFileAfterWrite(resolvedPath2);
111481
111530
  let action;
111482
111531
  if (newLines.length === 0) {
@@ -111489,14 +111538,14 @@ async function handleLineEdit({ resolvedPath: resolvedPath2, file_path, start_li
111489
111538
  return buildLineEditResponse(file_path, startLine, endLine, newLines.length, fileLines, startLine - 1, action, modifications);
111490
111539
  }
111491
111540
  }
111492
- var import_ai6, import_fs11, import_path16, import_fs12, editTool, createTool, multiEditTool, editSchema, createSchema, multiEditSchema, editDescription, createDescription, multiEditDescription, editToolDefinition, createToolDefinition, multiEditToolDefinition;
111541
+ var import_ai6, import_fs12, import_path16, import_fs13, editTool, createTool, multiEditTool, editSchema, createSchema, multiEditSchema, editDescription, createDescription, multiEditDescription, editToolDefinition, createToolDefinition, multiEditToolDefinition;
111493
111542
  var init_edit = __esm({
111494
111543
  "src/tools/edit.js"() {
111495
111544
  "use strict";
111496
111545
  import_ai6 = require("ai");
111497
- import_fs11 = require("fs");
111498
- import_path16 = require("path");
111499
111546
  import_fs12 = require("fs");
111547
+ import_path16 = require("path");
111548
+ import_fs13 = require("fs");
111500
111549
  init_path_validation();
111501
111550
  init_fuzzyMatch();
111502
111551
  init_symbolEdit();
@@ -111580,7 +111629,7 @@ Parameters:
111580
111629
  const relativePath = toRelativePath(resolvedPath2, workspaceRoot);
111581
111630
  return `Error editing file: Permission denied - ${relativePath} is outside allowed directories. Use a file path within the project workspace.`;
111582
111631
  }
111583
- if (!(0, import_fs12.existsSync)(resolvedPath2)) {
111632
+ if (!(0, import_fs13.existsSync)(resolvedPath2)) {
111584
111633
  return `Error editing file: File not found - ${file_path}. Verify the path is correct and the file exists. Use 'search' to find files by name, or 'create' to make a new file.`;
111585
111634
  }
111586
111635
  if (options.fileTracker && !options.fileTracker.isFileSeen(resolvedPath2)) {
@@ -111610,7 +111659,7 @@ Example: <extract><targets>${displayPath}</targets></extract>`;
111610
111659
  Example: <extract><targets>${displayPath}</targets></extract>`;
111611
111660
  }
111612
111661
  }
111613
- const content = await import_fs11.promises.readFile(resolvedPath2, "utf-8");
111662
+ const content = await import_fs12.promises.readFile(resolvedPath2, "utf-8");
111614
111663
  let matchTarget = old_string;
111615
111664
  let matchStrategy = "exact";
111616
111665
  if (!content.includes(old_string)) {
@@ -111642,7 +111691,7 @@ Example: <extract><targets>${displayPath}</targets></extract>`;
111642
111691
  if (newContent === content) {
111643
111692
  return `Error editing file: No changes made - the replacement result is identical to the original. Verify that old_string and new_string are actually different. If fuzzy matching was used, the matched text may already equal new_string.`;
111644
111693
  }
111645
- await import_fs11.promises.writeFile(resolvedPath2, newContent, "utf-8");
111694
+ await import_fs12.promises.writeFile(resolvedPath2, newContent, "utf-8");
111646
111695
  if (options.fileTracker) {
111647
111696
  await options.fileTracker.trackFileAfterWrite(resolvedPath2);
111648
111697
  options.fileTracker.recordTextEdit(resolvedPath2);
@@ -111713,13 +111762,13 @@ Important:
111713
111762
  const relativePath = toRelativePath(resolvedPath2, workspaceRoot);
111714
111763
  return `Error creating file: Permission denied - ${relativePath} is outside allowed directories. Use a file path within the project workspace.`;
111715
111764
  }
111716
- if ((0, import_fs12.existsSync)(resolvedPath2) && !overwrite) {
111765
+ if ((0, import_fs13.existsSync)(resolvedPath2) && !overwrite) {
111717
111766
  return `Error creating file: File already exists - ${file_path}. Use overwrite: true to replace it.`;
111718
111767
  }
111719
- const existed = (0, import_fs12.existsSync)(resolvedPath2);
111768
+ const existed = (0, import_fs13.existsSync)(resolvedPath2);
111720
111769
  const dir = (0, import_path16.dirname)(resolvedPath2);
111721
- await import_fs11.promises.mkdir(dir, { recursive: true });
111722
- await import_fs11.promises.writeFile(resolvedPath2, content, "utf-8");
111770
+ await import_fs12.promises.mkdir(dir, { recursive: true });
111771
+ await import_fs12.promises.writeFile(resolvedPath2, content, "utf-8");
111723
111772
  if (options.fileTracker) await options.fileTracker.trackFileAfterWrite(resolvedPath2);
111724
111773
  const action = existed && overwrite ? "overwrote" : "created";
111725
111774
  const bytes = Buffer.byteLength(content, "utf-8");
@@ -112361,10 +112410,10 @@ async function listFilesByLevel(options) {
112361
112410
  maxFiles = 100,
112362
112411
  respectGitignore = true
112363
112412
  } = options;
112364
- if (!import_fs13.default.existsSync(directory)) {
112413
+ if (!import_fs14.default.existsSync(directory)) {
112365
112414
  throw new Error(`Directory does not exist: ${directory}`);
112366
112415
  }
112367
- const gitDirExists = import_fs13.default.existsSync(import_path17.default.join(directory, ".git"));
112416
+ const gitDirExists = import_fs14.default.existsSync(import_path17.default.join(directory, ".git"));
112368
112417
  if (gitDirExists && respectGitignore) {
112369
112418
  try {
112370
112419
  return await listFilesUsingGit(directory, maxFiles);
@@ -112395,7 +112444,7 @@ async function listFilesByLevelManually(directory, maxFiles, respectGitignore) {
112395
112444
  while (queue.length > 0 && result.length < maxFiles) {
112396
112445
  const { dir, level } = queue.shift();
112397
112446
  try {
112398
- const entries = import_fs13.default.readdirSync(dir, { withFileTypes: true });
112447
+ const entries = import_fs14.default.readdirSync(dir, { withFileTypes: true });
112399
112448
  const files = entries.filter((entry) => {
112400
112449
  const fullPath = import_path17.default.join(dir, entry.name);
112401
112450
  return getEntryTypeSync(entry, fullPath).isFile;
@@ -112426,11 +112475,11 @@ async function listFilesByLevelManually(directory, maxFiles, respectGitignore) {
112426
112475
  }
112427
112476
  function loadGitignorePatterns(directory) {
112428
112477
  const gitignorePath = import_path17.default.join(directory, ".gitignore");
112429
- if (!import_fs13.default.existsSync(gitignorePath)) {
112478
+ if (!import_fs14.default.existsSync(gitignorePath)) {
112430
112479
  return [];
112431
112480
  }
112432
112481
  try {
112433
- const content = import_fs13.default.readFileSync(gitignorePath, "utf8");
112482
+ const content = import_fs14.default.readFileSync(gitignorePath, "utf8");
112434
112483
  return content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
112435
112484
  } catch (error2) {
112436
112485
  console.error(`Warning: Could not read .gitignore: ${error2.message}`);
@@ -112448,11 +112497,11 @@ function shouldIgnore(filePath, ignorePatterns) {
112448
112497
  }
112449
112498
  return false;
112450
112499
  }
112451
- var import_fs13, import_path17, import_util12, import_child_process10, execAsync3;
112500
+ var import_fs14, import_path17, import_util12, import_child_process10, execAsync3;
112452
112501
  var init_file_lister = __esm({
112453
112502
  "src/utils/file-lister.js"() {
112454
112503
  "use strict";
112455
- import_fs13 = __toESM(require("fs"), 1);
112504
+ import_fs14 = __toESM(require("fs"), 1);
112456
112505
  import_path17 = __toESM(require("path"), 1);
112457
112506
  import_util12 = require("util");
112458
112507
  import_child_process10 = require("child_process");
@@ -112471,11 +112520,11 @@ function initializeSimpleTelemetryFromOptions(options) {
112471
112520
  });
112472
112521
  return telemetry;
112473
112522
  }
112474
- var import_fs14, import_path18, SimpleTelemetry, SimpleAppTracer;
112523
+ var import_fs15, import_path18, SimpleTelemetry, SimpleAppTracer;
112475
112524
  var init_simpleTelemetry = __esm({
112476
112525
  "src/agent/simpleTelemetry.js"() {
112477
112526
  "use strict";
112478
- import_fs14 = require("fs");
112527
+ import_fs15 = require("fs");
112479
112528
  import_path18 = require("path");
112480
112529
  SimpleTelemetry = class {
112481
112530
  constructor(options = {}) {
@@ -112491,10 +112540,10 @@ var init_simpleTelemetry = __esm({
112491
112540
  initializeFileExporter() {
112492
112541
  try {
112493
112542
  const dir = (0, import_path18.dirname)(this.filePath);
112494
- if (!(0, import_fs14.existsSync)(dir)) {
112495
- (0, import_fs14.mkdirSync)(dir, { recursive: true });
112543
+ if (!(0, import_fs15.existsSync)(dir)) {
112544
+ (0, import_fs15.mkdirSync)(dir, { recursive: true });
112496
112545
  }
112497
- this.stream = (0, import_fs14.createWriteStream)(this.filePath, { flags: "a" });
112546
+ this.stream = (0, import_fs15.createWriteStream)(this.filePath, { flags: "a" });
112498
112547
  this.stream.on("error", (error2) => {
112499
112548
  console.error(`[SimpleTelemetry] Stream error: ${error2.message}`);
112500
112549
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@probelabs/probe",
3
- "version": "0.6.0-rc270",
3
+ "version": "0.6.0-rc271",
4
4
  "description": "Node.js wrapper for the probe code search tool",
5
5
  "main": "src/index.js",
6
6
  "module": "src/index.js",
@@ -10,6 +10,7 @@ import { extract } from '../extract.js';
10
10
  import { delegate } from '../delegate.js';
11
11
  import { analyzeAll } from './analyzeAll.js';
12
12
  import { searchSchema, querySchema, extractSchema, delegateSchema, analyzeAllSchema, searchDescription, queryDescription, extractDescription, delegateDescription, analyzeAllDescription, parseTargets, parseAndResolvePaths, resolveTargetPath } from './common.js';
13
+ import { existsSync } from 'fs';
13
14
  import { formatErrorForAI } from '../utils/error-types.js';
14
15
  import { annotateOutputWithHashes } from './hashline.js';
15
16
 
@@ -118,6 +119,18 @@ function parseDelegatedTargets(rawResponse) {
118
119
  return normalizeTargets(fallbackTargetsFromText(trimmed));
119
120
  }
120
121
 
122
+ function splitTargetSuffix(target) {
123
+ const searchStart = (target.length > 2 && target[1] === ':' && /[a-zA-Z]/.test(target[0])) ? 2 : 0;
124
+ const colonIdx = target.indexOf(':', searchStart);
125
+ const hashIdx = target.indexOf('#');
126
+ if (colonIdx !== -1 && (hashIdx === -1 || colonIdx < hashIdx)) {
127
+ return { filePart: target.substring(0, colonIdx), suffix: target.substring(colonIdx) };
128
+ } else if (hashIdx !== -1) {
129
+ return { filePart: target.substring(0, hashIdx), suffix: target.substring(hashIdx) };
130
+ }
131
+ return { filePart: target, suffix: '' };
132
+ }
133
+
121
134
  function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, allowTests }) {
122
135
  return [
123
136
  'You are a code-search subagent. Your job is to find ALL relevant code locations for the given query.',
@@ -286,13 +299,61 @@ export const searchTool = (options = {}) => {
286
299
  return fallbackResult;
287
300
  }
288
301
 
289
- // Resolve relative paths against the actual search directory, not the general cwd.
290
- // The delegate returns paths relative to where the search was performed (searchPaths[0]),
291
- // which may differ from options.cwd when the user specifies a path parameter.
302
+ // The delegate runs from workspace root (allowedFolders[0] or cwd), NOT from searchPaths[0].
303
+ // It returns paths relative to that workspace root. Resolve against the same base.
304
+ const delegateBase = options.allowedFolders?.[0] || options.cwd || '.';
292
305
  const resolutionBase = searchPaths[0] || options.cwd || '.';
293
- const resolvedTargets = targets.map(target => resolveTargetPath(target, resolutionBase));
306
+ const resolvedTargets = targets.map(target => resolveTargetPath(target, delegateBase));
307
+
308
+ // Auto-fix: detect and repair invalid paths (doubled segments, AI hallucinations)
309
+ const validatedTargets = [];
310
+ for (const target of resolvedTargets) {
311
+ const { filePart, suffix } = splitTargetSuffix(target);
312
+
313
+ // 1. Path exists as-is
314
+ if (existsSync(filePart)) {
315
+ validatedTargets.push(target);
316
+ continue;
317
+ }
318
+
319
+ // 2. Detect doubled directory segments: /ws/proj/proj/src → /ws/proj/src
320
+ let fixed = false;
321
+ const parts = filePart.split('/').filter(Boolean);
322
+ for (let i = 0; i < parts.length - 1; i++) {
323
+ if (parts[i] === parts[i + 1]) {
324
+ const candidate = '/' + [...parts.slice(0, i), ...parts.slice(i + 1)].join('/');
325
+ if (existsSync(candidate)) {
326
+ validatedTargets.push(candidate + suffix);
327
+ if (debug) console.error(`[search-delegate] Fixed doubled path segment: ${filePart} → ${candidate}`);
328
+ fixed = true;
329
+ break;
330
+ }
331
+ }
332
+ }
333
+ if (fixed) continue;
334
+
335
+ // 3. Try resolving against alternative bases (searchPaths[0], cwd)
336
+ for (const altBase of [resolutionBase, options.cwd].filter(Boolean)) {
337
+ if (altBase === delegateBase) continue;
338
+ const altResolved = resolveTargetPath(target, altBase);
339
+ const { filePart: altFile } = splitTargetSuffix(altResolved);
340
+ if (existsSync(altFile)) {
341
+ validatedTargets.push(altResolved);
342
+ if (debug) console.error(`[search-delegate] Resolved with alt base: ${filePart} → ${altFile}`);
343
+ fixed = true;
344
+ break;
345
+ }
346
+ }
347
+ if (fixed) continue;
348
+
349
+ // 4. Keep target anyway (probe binary will report the error)
350
+ // but log a warning
351
+ if (debug) console.error(`[search-delegate] Warning: target may not exist: ${filePart}`);
352
+ validatedTargets.push(target);
353
+ }
354
+
294
355
  const extractOptions = {
295
- files: resolvedTargets,
356
+ files: validatedTargets,
296
357
  cwd: resolutionBase,
297
358
  allowTests: allow_tests ?? true
298
359
  };