@probelabs/probe 0.6.0-rc270 → 0.6.0-rc272

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.",
@@ -9135,7 +9147,7 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
9135
9147
  "",
9136
9148
  "Strategy for complex queries:",
9137
9149
  "1. Analyze the query - identify key concepts, entities, and relationships",
9138
- '2. Run focused searches for each concept (e.g., "error handling" + "authentication" separately)',
9150
+ '2. Run focused searches for each independent concept (e.g., for "how do payments work and how are emails sent", search "payments" and "emails" separately since they are unrelated)',
9139
9151
  "3. Use extract to verify relevance of promising results",
9140
9152
  "4. Combine all relevant targets in your final response",
9141
9153
  "",
@@ -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.',
@@ -132,7 +145,7 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
132
145
  '',
133
146
  'Strategy for complex queries:',
134
147
  '1. Analyze the query - identify key concepts, entities, and relationships',
135
- '2. Run focused searches for each concept (e.g., "error handling" + "authentication" separately)',
148
+ '2. Run focused searches for each independent concept (e.g., for "how do payments work and how are emails sent", search "payments" and "emails" separately since they are unrelated)',
136
149
  '3. Use extract to verify relevance of promising results',
137
150
  '4. Combine all relevant targets in your final response',
138
151
  '',
@@ -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
  };