@probelabs/probe 0.6.0-rc225 → 0.6.0-rc226

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.
@@ -32675,6 +32675,25 @@ var init_error_types = __esm({
32675
32675
  });
32676
32676
 
32677
32677
  // src/utils/path-validation.js
32678
+ function safeRealpath(inputPath) {
32679
+ try {
32680
+ return (0, import_fs3.realpathSync)(inputPath);
32681
+ } catch (error2) {
32682
+ const normalized = import_path4.default.normalize(inputPath);
32683
+ const parts = normalized.split(import_path4.default.sep);
32684
+ for (let i5 = parts.length - 1; i5 >= 0; i5--) {
32685
+ const ancestorPath = parts.slice(0, i5).join(import_path4.default.sep) || import_path4.default.sep;
32686
+ try {
32687
+ const resolvedAncestor = (0, import_fs3.realpathSync)(ancestorPath);
32688
+ const remainingParts = parts.slice(i5);
32689
+ return import_path4.default.join(resolvedAncestor, ...remainingParts);
32690
+ } catch (ancestorError) {
32691
+ continue;
32692
+ }
32693
+ }
32694
+ return normalized;
32695
+ }
32696
+ }
32678
32697
  async function validateCwdPath(inputPath, defaultPath = process.cwd()) {
32679
32698
  const targetPath = inputPath || defaultPath;
32680
32699
  const normalizedPath = import_path4.default.normalize(import_path4.default.resolve(targetPath));
@@ -32707,6 +32726,53 @@ async function validateCwdPath(inputPath, defaultPath = process.cwd()) {
32707
32726
  }
32708
32727
  return normalizedPath;
32709
32728
  }
32729
+ function getCommonPrefix(folders) {
32730
+ if (!folders || folders.length === 0) {
32731
+ return process.cwd();
32732
+ }
32733
+ if (folders.length === 1) {
32734
+ return safeRealpath(folders[0]);
32735
+ }
32736
+ const normalized = folders.map((f5) => safeRealpath(f5));
32737
+ const segments = normalized.map((f5) => f5.split(import_path4.default.sep));
32738
+ const minLen = Math.min(...segments.map((s5) => s5.length));
32739
+ const commonSegments = [];
32740
+ for (let i5 = 0; i5 < minLen; i5++) {
32741
+ const segment = segments[0][i5];
32742
+ if (segments.every((s5) => s5[i5] === segment)) {
32743
+ commonSegments.push(segment);
32744
+ } else {
32745
+ break;
32746
+ }
32747
+ }
32748
+ if (commonSegments.length === 0) {
32749
+ return normalized[0];
32750
+ }
32751
+ if (commonSegments.length === 1 && /^[a-zA-Z]:$/.test(commonSegments[0])) {
32752
+ return normalized[0];
32753
+ }
32754
+ if (commonSegments.length === 1 && commonSegments[0] === "") {
32755
+ return normalized[0];
32756
+ }
32757
+ return commonSegments.join(import_path4.default.sep);
32758
+ }
32759
+ function toRelativePath(absolutePath, workspaceRoot) {
32760
+ if (!absolutePath || !workspaceRoot) {
32761
+ return absolutePath;
32762
+ }
32763
+ let normalized = safeRealpath(absolutePath);
32764
+ let normalizedRoot = safeRealpath(workspaceRoot);
32765
+ while (normalizedRoot.length > 1 && normalizedRoot.endsWith(import_path4.default.sep)) {
32766
+ normalizedRoot = normalizedRoot.slice(0, -1);
32767
+ }
32768
+ if (normalized === normalizedRoot) {
32769
+ return ".";
32770
+ }
32771
+ if (normalized.startsWith(normalizedRoot + import_path4.default.sep)) {
32772
+ return import_path4.default.relative(normalizedRoot, normalized);
32773
+ }
32774
+ return absolutePath;
32775
+ }
32710
32776
  var import_path4, import_fs3;
32711
32777
  var init_path_validation = __esm({
32712
32778
  "src/utils/path-validation.js"() {
@@ -33904,6 +33970,7 @@ async function analyzeAll(options) {
33904
33970
  sessionId,
33905
33971
  debug = false,
33906
33972
  cwd,
33973
+ workspaceRoot,
33907
33974
  allowedFolders,
33908
33975
  provider,
33909
33976
  model,
@@ -33916,10 +33983,11 @@ async function analyzeAll(options) {
33916
33983
  if (!question) {
33917
33984
  throw new Error('The "question" parameter is required.');
33918
33985
  }
33986
+ const effectiveWorkspaceRoot = workspaceRoot || cwd || allowedFolders?.[0] || path9;
33919
33987
  const delegateOptions = {
33920
33988
  debug,
33921
33989
  sessionId,
33922
- path: allowedFolders?.[0] || cwd || path9,
33990
+ path: effectiveWorkspaceRoot,
33923
33991
  allowedFolders,
33924
33992
  provider,
33925
33993
  model,
@@ -38132,21 +38200,24 @@ var init_zod = __esm({
38132
38200
  // src/tools/edit.js
38133
38201
  function isPathAllowed(filePath, allowedFolders) {
38134
38202
  if (!allowedFolders || allowedFolders.length === 0) {
38135
- const resolvedPath3 = (0, import_path5.resolve)(filePath);
38136
- const cwd = (0, import_path5.resolve)(process.cwd());
38203
+ const resolvedPath3 = safeRealpath(filePath);
38204
+ const cwd = safeRealpath(process.cwd());
38137
38205
  return resolvedPath3 === cwd || resolvedPath3.startsWith(cwd + import_path5.sep);
38138
38206
  }
38139
- const resolvedPath2 = (0, import_path5.resolve)(filePath);
38207
+ const resolvedPath2 = safeRealpath(filePath);
38140
38208
  return allowedFolders.some((folder) => {
38141
- const allowedPath = (0, import_path5.resolve)(folder);
38209
+ const allowedPath = safeRealpath(folder);
38142
38210
  return resolvedPath2 === allowedPath || resolvedPath2.startsWith(allowedPath + import_path5.sep);
38143
38211
  });
38144
38212
  }
38145
38213
  function parseFileToolOptions(options = {}) {
38214
+ const allowedFolders = options.allowedFolders || [];
38146
38215
  return {
38147
38216
  debug: options.debug || false,
38148
- allowedFolders: options.allowedFolders || [],
38149
- cwd: options.cwd
38217
+ allowedFolders,
38218
+ cwd: options.cwd,
38219
+ // Consistent fallback chain: workspaceRoot > cwd > allowedFolders[0] > process.cwd()
38220
+ workspaceRoot: options.workspaceRoot || options.cwd || allowedFolders.length > 0 && allowedFolders[0] || process.cwd()
38150
38221
  };
38151
38222
  }
38152
38223
  var import_ai, import_fs4, import_path5, import_fs5, editTool, createTool, editSchema, createSchema, editDescription, createDescription, editToolDefinition, createToolDefinition;
@@ -38157,8 +38228,9 @@ var init_edit = __esm({
38157
38228
  import_fs4 = require("fs");
38158
38229
  import_path5 = require("path");
38159
38230
  import_fs5 = require("fs");
38231
+ init_path_validation();
38160
38232
  editTool = (options = {}) => {
38161
- const { debug, allowedFolders, cwd } = parseFileToolOptions(options);
38233
+ const { debug, allowedFolders, cwd, workspaceRoot } = parseFileToolOptions(options);
38162
38234
  return (0, import_ai.tool)({
38163
38235
  name: "edit",
38164
38236
  description: `Edit files using exact string replacement (Claude Code style).
@@ -38214,7 +38286,8 @@ Important:
38214
38286
  console.error(`[Edit] Attempting to edit file: ${resolvedPath2}`);
38215
38287
  }
38216
38288
  if (!isPathAllowed(resolvedPath2, allowedFolders)) {
38217
- return `Error editing file: Permission denied - ${file_path} is outside allowed directories`;
38289
+ const relativePath = toRelativePath(resolvedPath2, workspaceRoot);
38290
+ return `Error editing file: Permission denied - ${relativePath} is outside allowed directories`;
38218
38291
  }
38219
38292
  if (!(0, import_fs5.existsSync)(resolvedPath2)) {
38220
38293
  return `Error editing file: File not found - ${file_path}`;
@@ -38250,7 +38323,7 @@ Important:
38250
38323
  });
38251
38324
  };
38252
38325
  createTool = (options = {}) => {
38253
- const { debug, allowedFolders, cwd } = parseFileToolOptions(options);
38326
+ const { debug, allowedFolders, cwd, workspaceRoot } = parseFileToolOptions(options);
38254
38327
  return (0, import_ai.tool)({
38255
38328
  name: "create",
38256
38329
  description: `Create new files with specified content.
@@ -38298,7 +38371,8 @@ Important:
38298
38371
  console.error(`[Create] Attempting to create file: ${resolvedPath2}`);
38299
38372
  }
38300
38373
  if (!isPathAllowed(resolvedPath2, allowedFolders)) {
38301
- return `Error creating file: Permission denied - ${file_path} is outside allowed directories`;
38374
+ const relativePath = toRelativePath(resolvedPath2, workspaceRoot);
38375
+ return `Error creating file: Permission denied - ${relativePath} is outside allowed directories`;
38302
38376
  }
38303
38377
  if ((0, import_fs5.existsSync)(resolvedPath2) && !overwrite) {
38304
38378
  return `Error creating file: File already exists - ${file_path}. Use overwrite: true to replace it.`;
@@ -39860,7 +39934,7 @@ var init_vercel = __esm({
39860
39934
  });
39861
39935
  };
39862
39936
  delegateTool = (options = {}) => {
39863
- const { debug = false, timeout = 300, cwd, allowedFolders, enableBash = false, bashConfig, architectureFileName, enableMcp = false, mcpConfig = null, mcpConfigPath = null, delegationManager = null } = options;
39937
+ const { debug = false, timeout = 300, cwd, allowedFolders, workspaceRoot, enableBash = false, bashConfig, architectureFileName, enableMcp = false, mcpConfig = null, mcpConfigPath = null, delegationManager = null } = options;
39864
39938
  return (0, import_ai2.tool)({
39865
39939
  name: "delegate",
39866
39940
  description: delegateDescription,
@@ -39893,8 +39967,8 @@ var init_vercel = __esm({
39893
39967
  if (searchDelegate !== void 0 && typeof searchDelegate !== "boolean") {
39894
39968
  throw new TypeError("searchDelegate must be a boolean if provided");
39895
39969
  }
39896
- const workspaceRoot = allowedFolders && allowedFolders[0];
39897
- const effectivePath = path9 || workspaceRoot || cwd;
39970
+ const effectiveWorkspaceRoot = workspaceRoot || allowedFolders && allowedFolders[0];
39971
+ const effectivePath = path9 || effectiveWorkspaceRoot || cwd;
39898
39972
  if (debug) {
39899
39973
  console.error(`Executing delegate with task: "${task.substring(0, 100)}${task.length > 100 ? "..." : ""}"`);
39900
39974
  if (parentSessionId) {
@@ -39931,7 +40005,7 @@ var init_vercel = __esm({
39931
40005
  });
39932
40006
  };
39933
40007
  analyzeAllTool = (options = {}) => {
39934
- const { sessionId, debug = false, delegationManager = null } = options;
40008
+ const { sessionId, debug = false, delegationManager = null, workspaceRoot } = options;
39935
40009
  return (0, import_ai2.tool)({
39936
40010
  name: "analyze_all",
39937
40011
  description: analyzeAllDescription,
@@ -39950,12 +40024,14 @@ var init_vercel = __esm({
39950
40024
  console.error(`[analyze_all] Question: ${question}`);
39951
40025
  console.error(`[analyze_all] Path: ${searchPath}`);
39952
40026
  }
40027
+ const effectiveWorkspaceRoot = workspaceRoot || options.cwd || options.allowedFolders && options.allowedFolders[0];
39953
40028
  const result = await analyzeAll({
39954
40029
  question,
39955
40030
  path: searchPath,
39956
40031
  sessionId,
39957
40032
  debug,
39958
40033
  cwd: options.cwd,
40034
+ workspaceRoot: effectiveWorkspaceRoot,
39959
40035
  allowedFolders: options.allowedFolders,
39960
40036
  provider: options.provider,
39961
40037
  model: options.model,
@@ -41432,14 +41508,17 @@ var init_bash = __esm({
41432
41508
  import_path8 = require("path");
41433
41509
  init_bashPermissions();
41434
41510
  init_bashExecutor();
41511
+ init_path_validation();
41435
41512
  bashTool = (options = {}) => {
41436
41513
  const {
41437
41514
  bashConfig = {},
41438
41515
  debug = false,
41439
41516
  cwd,
41440
41517
  allowedFolders = [],
41518
+ workspaceRoot: providedWorkspaceRoot,
41441
41519
  tracer = null
41442
41520
  } = options;
41521
+ const workspaceRoot = providedWorkspaceRoot || cwd || allowedFolders.length > 0 && allowedFolders[0] || process.cwd();
41443
41522
  const permissionChecker = new BashPermissionChecker({
41444
41523
  allow: bashConfig.allow,
41445
41524
  deny: bashConfig.deny,
@@ -41455,6 +41534,9 @@ var init_bash = __esm({
41455
41534
  if (cwd) {
41456
41535
  return cwd;
41457
41536
  }
41537
+ if (workspaceRoot) {
41538
+ return workspaceRoot;
41539
+ }
41458
41540
  if (allowedFolders && allowedFolders.length > 0) {
41459
41541
  return allowedFolders[0];
41460
41542
  }
@@ -41542,13 +41624,15 @@ For code exploration, try these safe alternatives:
41542
41624
  const defaultDir = getDefaultWorkingDirectory();
41543
41625
  const workingDir = workingDirectory ? (0, import_path8.isAbsolute)(workingDirectory) ? (0, import_path8.resolve)(workingDirectory) : (0, import_path8.resolve)(defaultDir, workingDirectory) : defaultDir;
41544
41626
  if (allowedFolders && allowedFolders.length > 0) {
41545
- const resolvedWorkingDir = (0, import_path8.resolve)(workingDir);
41627
+ const resolvedWorkingDir = safeRealpath(workingDir);
41546
41628
  const isAllowed = allowedFolders.some((folder) => {
41547
- const resolvedFolder = (0, import_path8.resolve)(folder);
41629
+ const resolvedFolder = safeRealpath(folder);
41548
41630
  return resolvedWorkingDir === resolvedFolder || resolvedWorkingDir.startsWith(resolvedFolder + import_path8.sep);
41549
41631
  });
41550
41632
  if (!isAllowed) {
41551
- return `Error: Working directory "${workingDir}" is not within allowed folders: ${allowedFolders.join(", ")}`;
41633
+ const relativeDir = toRelativePath(workingDir, workspaceRoot);
41634
+ const relativeAllowed = allowedFolders.map((f5) => toRelativePath(f5, workspaceRoot));
41635
+ return `Error: Working directory "${relativeDir}" is not within allowed folders: ${relativeAllowed.join(", ")}`;
41552
41636
  }
41553
41637
  }
41554
41638
  const executionOptions = {
@@ -45715,7 +45799,7 @@ var init_esm3 = __esm({
45715
45799
  });
45716
45800
 
45717
45801
  // node_modules/path-scurry/dist/esm/index.js
45718
- var import_node_path, import_node_url, import_fs9, actualFS, import_promises, realpathSync, 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;
45802
+ var import_node_path, import_node_url, import_fs9, 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;
45719
45803
  var init_esm4 = __esm({
45720
45804
  "node_modules/path-scurry/dist/esm/index.js"() {
45721
45805
  init_esm2();
@@ -45725,13 +45809,13 @@ var init_esm4 = __esm({
45725
45809
  actualFS = __toESM(require("node:fs"), 1);
45726
45810
  import_promises = require("node:fs/promises");
45727
45811
  init_esm3();
45728
- realpathSync = import_fs9.realpathSync.native;
45812
+ realpathSync2 = import_fs9.realpathSync.native;
45729
45813
  defaultFS = {
45730
45814
  lstatSync: import_fs9.lstatSync,
45731
45815
  readdir: import_fs9.readdir,
45732
45816
  readdirSync: import_fs9.readdirSync,
45733
45817
  readlinkSync: import_fs9.readlinkSync,
45734
- realpathSync,
45818
+ realpathSync: realpathSync2,
45735
45819
  promises: {
45736
45820
  lstat: import_promises.lstat,
45737
45821
  readdir: import_promises.readdir,
@@ -99126,6 +99210,7 @@ var init_ProbeAgent = __esm({
99126
99210
  init_FallbackManager();
99127
99211
  init_contextCompactor();
99128
99212
  init_error_types();
99213
+ init_path_validation();
99129
99214
  init_outputTruncator();
99130
99215
  init_delegate();
99131
99216
  init_tasks();
@@ -99243,7 +99328,8 @@ var init_ProbeAgent = __esm({
99243
99328
  } else {
99244
99329
  this.allowedFolders = [process.cwd()];
99245
99330
  }
99246
- this.cwd = options.cwd || null;
99331
+ this.workspaceRoot = getCommonPrefix(this.allowedFolders);
99332
+ this.cwd = options.cwd || this.workspaceRoot;
99247
99333
  this.clientApiProvider = options.provider || null;
99248
99334
  this.clientApiModel = options.model || null;
99249
99335
  this.clientApiKey = null;
@@ -99255,6 +99341,8 @@ var init_ProbeAgent = __esm({
99255
99341
  console.log(`[DEBUG] Maximum tool iterations configured: ${MAX_TOOL_ITERATIONS}`);
99256
99342
  console.log(`[DEBUG] Allow Edit (implement tool): ${this.allowEdit}`);
99257
99343
  console.log(`[DEBUG] Search delegation enabled: ${this.searchDelegate}`);
99344
+ console.log(`[DEBUG] Workspace root: ${this.workspaceRoot}`);
99345
+ console.log(`[DEBUG] Working directory (cwd): ${this.cwd}`);
99258
99346
  }
99259
99347
  this.initializeTools();
99260
99348
  this.history = [];
@@ -99602,8 +99690,9 @@ var init_ProbeAgent = __esm({
99602
99690
  const configOptions = {
99603
99691
  sessionId: this.sessionId,
99604
99692
  debug: this.debug,
99605
- // Use explicit cwd if set, otherwise fall back to first allowed folder
99606
- cwd: this.cwd || (this.allowedFolders.length > 0 ? this.allowedFolders[0] : process.cwd()),
99693
+ // Use cwd (which defaults to workspaceRoot in constructor)
99694
+ cwd: this.cwd,
99695
+ workspaceRoot: this.workspaceRoot,
99607
99696
  allowedFolders: this.allowedFolders,
99608
99697
  outline: this.outline,
99609
99698
  searchDelegate: this.searchDelegate,
@@ -100290,16 +100379,16 @@ var init_ProbeAgent = __esm({
100290
100379
  let absolutePath;
100291
100380
  let isPathAllowed2 = false;
100292
100381
  if ((0, import_path17.isAbsolute)(imagePath)) {
100293
- absolutePath = (0, import_path17.normalize)((0, import_path17.resolve)(imagePath));
100382
+ absolutePath = safeRealpath((0, import_path17.resolve)(imagePath));
100294
100383
  isPathAllowed2 = allowedDirs.some((dir) => {
100295
- const normalizedDir = (0, import_path17.normalize)((0, import_path17.resolve)(dir));
100296
- return absolutePath === normalizedDir || absolutePath.startsWith(normalizedDir + import_path17.sep);
100384
+ const resolvedDir = safeRealpath(dir);
100385
+ return absolutePath === resolvedDir || absolutePath.startsWith(resolvedDir + import_path17.sep);
100297
100386
  });
100298
100387
  } else {
100299
100388
  for (const dir of allowedDirs) {
100300
- const normalizedDir = (0, import_path17.normalize)((0, import_path17.resolve)(dir));
100301
- const resolvedPath2 = (0, import_path17.normalize)((0, import_path17.resolve)(dir, imagePath));
100302
- if (resolvedPath2 === normalizedDir || resolvedPath2.startsWith(normalizedDir + import_path17.sep)) {
100389
+ const resolvedDir = safeRealpath(dir);
100390
+ const resolvedPath2 = safeRealpath((0, import_path17.resolve)(dir, imagePath));
100391
+ if (resolvedPath2 === resolvedDir || resolvedPath2.startsWith(resolvedDir + import_path17.sep)) {
100303
100392
  absolutePath = resolvedPath2;
100304
100393
  isPathAllowed2 = true;
100305
100394
  break;
@@ -100482,7 +100571,7 @@ var init_ProbeAgent = __esm({
100482
100571
  if (this._architectureContextLoaded) {
100483
100572
  return this.architectureContext;
100484
100573
  }
100485
- const rootDirectory = this.allowedFolders.length > 0 ? this.allowedFolders[0] : process.cwd();
100574
+ const rootDirectory = this.workspaceRoot || (this.allowedFolders.length > 0 ? this.allowedFolders[0] : process.cwd());
100486
100575
  const configuredName = typeof this.architectureFileName === "string" ? this.architectureFileName.trim() : "";
100487
100576
  const hasConfiguredName = !!configuredName;
100488
100577
  let guidanceCandidates = [];
@@ -100619,6 +100708,9 @@ ${this.architectureContext.content}
100619
100708
  `;
100620
100709
  }
100621
100710
  _getSkillsRepoRoot() {
100711
+ if (this.workspaceRoot) {
100712
+ return (0, import_path17.resolve)(this.workspaceRoot);
100713
+ }
100622
100714
  if (this.allowedFolders && this.allowedFolders.length > 0) {
100623
100715
  return (0, import_path17.resolve)(this.allowedFolders[0]);
100624
100716
  }
@@ -100686,7 +100778,7 @@ Workspace: ${this.allowedFolders.join(", ")}`;
100686
100778
 
100687
100779
  # Repository Structure
100688
100780
  `;
100689
- systemPrompt += `You are working with a repository located at: ${this.allowedFolders[0]}
100781
+ systemPrompt += `You are working with a repository located at: ${this.workspaceRoot}
100690
100782
 
100691
100783
  `;
100692
100784
  systemPrompt += `Here's an overview of the repository structure (showing up to 100 most relevant files):
@@ -100739,7 +100831,7 @@ Workspace: ${this.allowedFolders.join(", ")}`;
100739
100831
 
100740
100832
  # Repository Structure
100741
100833
  `;
100742
- systemPrompt += `You are working with a repository located at: ${this.allowedFolders[0]}
100834
+ systemPrompt += `You are working with a repository located at: ${this.workspaceRoot}
100743
100835
 
100744
100836
  `;
100745
100837
  systemPrompt += `Here's an overview of the repository structure (showing up to 100 most relevant files):
@@ -101038,21 +101130,34 @@ For MCP tools, use JSON format within the params tag, e.g.:
101038
101130
  `;
101039
101131
  }
101040
101132
  }
101041
- const searchDirectory = this.allowedFolders.length > 0 ? this.allowedFolders[0] : process.cwd();
101133
+ const searchDirectory = this.workspaceRoot;
101042
101134
  if (this.debug) {
101043
- console.log(`[DEBUG] Generating file list for base directory: ${searchDirectory}...`);
101135
+ console.log(`[DEBUG] Generating file list for workspace root: ${searchDirectory}...`);
101136
+ }
101137
+ const relativeWorkspaces = this.allowedFolders.map((f5) => {
101138
+ const rel = toRelativePath(f5, this.workspaceRoot);
101139
+ if (rel && rel !== "." && !rel.startsWith(".") && !rel.startsWith("/")) {
101140
+ return "./" + rel;
101141
+ }
101142
+ return rel;
101143
+ }).filter((f5) => f5 && f5 !== ".");
101144
+ let workspaceDesc;
101145
+ if (relativeWorkspaces.length === 0) {
101146
+ workspaceDesc = ". (current directory)";
101147
+ } else {
101148
+ workspaceDesc = relativeWorkspaces.join(", ");
101044
101149
  }
101045
101150
  try {
101046
101151
  const files = await listFilesByLevel({
101047
101152
  directory: searchDirectory,
101048
101153
  maxFiles: 100,
101049
101154
  respectGitignore: !process.env.PROBE_NO_GITIGNORE || process.env.PROBE_NO_GITIGNORE === "",
101050
- cwd: process.cwd()
101155
+ cwd: this.workspaceRoot
101051
101156
  });
101052
101157
  systemMessage += `
101053
101158
  # Repository Structure
101054
101159
 
101055
- You are working with a repository located at: ${searchDirectory}
101160
+ You are working with a workspace. Available paths: ${workspaceDesc}
101056
101161
 
101057
101162
  Here's an overview of the repository structure (showing up to 100 most relevant files):
101058
101163
 
@@ -101068,15 +101173,22 @@ ${files}
101068
101173
  systemMessage += `
101069
101174
  # Repository Structure
101070
101175
 
101071
- You are working with a repository located at: ${searchDirectory}
101176
+ You are working with a workspace. Available paths: ${workspaceDesc}
101072
101177
 
101073
101178
  `;
101074
101179
  }
101075
101180
  await this.loadArchitectureContext();
101076
101181
  systemMessage += this.getArchitectureSection();
101077
101182
  if (this.allowedFolders.length > 0) {
101183
+ const relativeAllowed = this.allowedFolders.map((f5) => {
101184
+ const rel = toRelativePath(f5, this.workspaceRoot);
101185
+ if (rel && rel !== "." && !rel.startsWith(".") && !rel.startsWith("/")) {
101186
+ return "./" + rel;
101187
+ }
101188
+ return rel;
101189
+ });
101078
101190
  systemMessage += `
101079
- **Important**: For security reasons, you can only search within these allowed folders: ${this.allowedFolders.join(", ")}
101191
+ **Important**: For security reasons, you can only access these paths: ${relativeAllowed.join(", ")}
101080
101192
 
101081
101193
  `;
101082
101194
  }
@@ -101590,6 +101702,7 @@ You are working with a repository located at: ${searchDirectory}
101590
101702
  console.error(`[DEBUG] ========================================
101591
101703
  `);
101592
101704
  }
101705
+ currentMessages.push({ role: "assistant", content: assistantResponseContent });
101593
101706
  currentMessages.push({ role: "user", content: `<tool_result>
101594
101707
  ${toolResultContent}
101595
101708
  </tool_result>` });
@@ -101610,17 +101723,18 @@ ${toolResultContent}
101610
101723
  `);
101611
101724
  }
101612
101725
  const errorXml = formatErrorForAI(error2);
101726
+ currentMessages.push({ role: "assistant", content: assistantResponseContent });
101613
101727
  currentMessages.push({ role: "user", content: `<tool_result>
101614
101728
  ${errorXml}
101615
101729
  </tool_result>` });
101616
101730
  }
101617
101731
  } else if (this.toolImplementations[toolName]) {
101618
101732
  try {
101619
- let resolvedWorkingDirectory = this.cwd || this.allowedFolders && this.allowedFolders[0] || process.cwd();
101733
+ let resolvedWorkingDirectory = this.workspaceRoot || this.cwd || this.allowedFolders && this.allowedFolders[0] || process.cwd();
101620
101734
  if (params.workingDirectory) {
101621
- const requestedDir = (0, import_path17.isAbsolute)(params.workingDirectory) ? (0, import_path17.resolve)(params.workingDirectory) : (0, import_path17.resolve)(resolvedWorkingDirectory, params.workingDirectory);
101735
+ const requestedDir = safeRealpath((0, import_path17.isAbsolute)(params.workingDirectory) ? (0, import_path17.resolve)(params.workingDirectory) : (0, import_path17.resolve)(resolvedWorkingDirectory, params.workingDirectory));
101622
101736
  const isWithinAllowed = !this.allowedFolders || this.allowedFolders.length === 0 || this.allowedFolders.some((folder) => {
101623
- const resolvedFolder = (0, import_path17.resolve)(folder);
101737
+ const resolvedFolder = safeRealpath(folder);
101624
101738
  return requestedDir === resolvedFolder || requestedDir.startsWith(resolvedFolder + import_path17.sep);
101625
101739
  });
101626
101740
  if (isWithinAllowed) {
@@ -102089,7 +102203,7 @@ Convert your previous response content into actual JSON data that follows this s
102089
102203
  }
102090
102204
  const mermaidValidation = await validateAndFixMermaidResponse(finalResult, {
102091
102205
  debug: this.debug,
102092
- path: this.allowedFolders[0],
102206
+ path: this.workspaceRoot || this.allowedFolders[0],
102093
102207
  provider: this.clientApiProvider,
102094
102208
  model: this.model,
102095
102209
  tracer: this.tracer
@@ -102162,7 +102276,7 @@ Convert your previous response content into actual JSON data that follows this s
102162
102276
  }
102163
102277
  const { JsonFixingAgent: JsonFixingAgent2 } = await Promise.resolve().then(() => (init_schemaUtils(), schemaUtils_exports));
102164
102278
  const jsonFixer = new JsonFixingAgent2({
102165
- path: this.allowedFolders[0],
102279
+ path: this.workspaceRoot || this.allowedFolders[0],
102166
102280
  provider: this.clientApiProvider,
102167
102281
  model: this.model,
102168
102282
  debug: this.debug,
@@ -102231,7 +102345,7 @@ Convert your previous response content into actual JSON data that follows this s
102231
102345
  }
102232
102346
  const mermaidValidation = await validateAndFixMermaidResponse(finalResult, {
102233
102347
  debug: this.debug,
102234
- path: this.allowedFolders[0],
102348
+ path: this.workspaceRoot || this.allowedFolders[0],
102235
102349
  provider: this.clientApiProvider,
102236
102350
  model: this.model,
102237
102351
  tracer: this.tracer
@@ -102363,7 +102477,7 @@ Convert your previous response content into actual JSON data that follows this s
102363
102477
  }
102364
102478
  const finalMermaidValidation = await validateAndFixMermaidResponse(finalResult, {
102365
102479
  debug: this.debug,
102366
- path: this.allowedFolders[0],
102480
+ path: this.workspaceRoot || this.allowedFolders[0],
102367
102481
  provider: this.clientApiProvider,
102368
102482
  model: this.model,
102369
102483
  tracer: this.tracer
@@ -102513,8 +102627,7 @@ Convert your previous response content into actual JSON data that follows this s
102513
102627
  allowEdit: this.allowEdit,
102514
102628
  enableDelegate: this.enableDelegate,
102515
102629
  architectureFileName: this.architectureFileName,
102516
- path: this.allowedFolders[0],
102517
- // Use first allowed folder as primary path
102630
+ // Pass allowedFolders which will recompute workspaceRoot correctly
102518
102631
  allowedFolders: [...this.allowedFolders],
102519
102632
  cwd: this.cwd,
102520
102633
  // Preserve explicit working directory