@probelabs/probe 0.6.0-rc224 → 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.
- package/bin/binaries/probe-v0.6.0-rc226-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc226-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc226-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc226-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc226-x86_64-unknown-linux-musl.tar.gz +0 -0
- package/build/agent/ProbeAgent.js +361 -36
- package/build/agent/index.js +570 -57
- package/build/agent/mcp/xmlBridge.js +10 -7
- package/build/agent/simpleTelemetry.js +198 -0
- package/build/agent/tools.js +8 -5
- package/build/tools/analyzeAll.js +6 -1
- package/build/tools/bash.js +18 -3
- package/build/tools/edit.js +19 -10
- package/build/tools/vercel.js +17 -7
- package/build/utils/path-validation.js +148 -1
- package/cjs/agent/ProbeAgent.cjs +392 -56
- package/cjs/agent/simpleTelemetry.cjs +177 -0
- package/cjs/index.cjs +569 -56
- package/package.json +1 -1
- package/src/agent/ProbeAgent.js +361 -36
- package/src/agent/mcp/xmlBridge.js +10 -7
- package/src/agent/simpleTelemetry.js +198 -0
- package/src/agent/tools.js +8 -5
- package/src/tools/analyzeAll.js +6 -1
- package/src/tools/bash.js +18 -3
- package/src/tools/edit.js +19 -10
- package/src/tools/vercel.js +17 -7
- package/src/utils/path-validation.js +148 -1
- package/bin/binaries/probe-v0.6.0-rc224-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc224-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc224-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc224-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc224-x86_64-unknown-linux-musl.tar.gz +0 -0
package/build/agent/index.js
CHANGED
|
@@ -3288,7 +3288,26 @@ var init_error_types = __esm({
|
|
|
3288
3288
|
|
|
3289
3289
|
// src/utils/path-validation.js
|
|
3290
3290
|
import path4 from "path";
|
|
3291
|
-
import { promises as fs5 } from "fs";
|
|
3291
|
+
import { promises as fs5, realpathSync } from "fs";
|
|
3292
|
+
function safeRealpath(inputPath) {
|
|
3293
|
+
try {
|
|
3294
|
+
return realpathSync(inputPath);
|
|
3295
|
+
} catch (error) {
|
|
3296
|
+
const normalized = path4.normalize(inputPath);
|
|
3297
|
+
const parts = normalized.split(path4.sep);
|
|
3298
|
+
for (let i = parts.length - 1; i >= 0; i--) {
|
|
3299
|
+
const ancestorPath = parts.slice(0, i).join(path4.sep) || path4.sep;
|
|
3300
|
+
try {
|
|
3301
|
+
const resolvedAncestor = realpathSync(ancestorPath);
|
|
3302
|
+
const remainingParts = parts.slice(i);
|
|
3303
|
+
return path4.join(resolvedAncestor, ...remainingParts);
|
|
3304
|
+
} catch (ancestorError) {
|
|
3305
|
+
continue;
|
|
3306
|
+
}
|
|
3307
|
+
}
|
|
3308
|
+
return normalized;
|
|
3309
|
+
}
|
|
3310
|
+
}
|
|
3292
3311
|
async function validateCwdPath(inputPath, defaultPath = process.cwd()) {
|
|
3293
3312
|
const targetPath = inputPath || defaultPath;
|
|
3294
3313
|
const normalizedPath = path4.normalize(path4.resolve(targetPath));
|
|
@@ -3321,6 +3340,53 @@ async function validateCwdPath(inputPath, defaultPath = process.cwd()) {
|
|
|
3321
3340
|
}
|
|
3322
3341
|
return normalizedPath;
|
|
3323
3342
|
}
|
|
3343
|
+
function getCommonPrefix(folders) {
|
|
3344
|
+
if (!folders || folders.length === 0) {
|
|
3345
|
+
return process.cwd();
|
|
3346
|
+
}
|
|
3347
|
+
if (folders.length === 1) {
|
|
3348
|
+
return safeRealpath(folders[0]);
|
|
3349
|
+
}
|
|
3350
|
+
const normalized = folders.map((f) => safeRealpath(f));
|
|
3351
|
+
const segments = normalized.map((f) => f.split(path4.sep));
|
|
3352
|
+
const minLen = Math.min(...segments.map((s) => s.length));
|
|
3353
|
+
const commonSegments = [];
|
|
3354
|
+
for (let i = 0; i < minLen; i++) {
|
|
3355
|
+
const segment = segments[0][i];
|
|
3356
|
+
if (segments.every((s) => s[i] === segment)) {
|
|
3357
|
+
commonSegments.push(segment);
|
|
3358
|
+
} else {
|
|
3359
|
+
break;
|
|
3360
|
+
}
|
|
3361
|
+
}
|
|
3362
|
+
if (commonSegments.length === 0) {
|
|
3363
|
+
return normalized[0];
|
|
3364
|
+
}
|
|
3365
|
+
if (commonSegments.length === 1 && /^[a-zA-Z]:$/.test(commonSegments[0])) {
|
|
3366
|
+
return normalized[0];
|
|
3367
|
+
}
|
|
3368
|
+
if (commonSegments.length === 1 && commonSegments[0] === "") {
|
|
3369
|
+
return normalized[0];
|
|
3370
|
+
}
|
|
3371
|
+
return commonSegments.join(path4.sep);
|
|
3372
|
+
}
|
|
3373
|
+
function toRelativePath(absolutePath, workspaceRoot) {
|
|
3374
|
+
if (!absolutePath || !workspaceRoot) {
|
|
3375
|
+
return absolutePath;
|
|
3376
|
+
}
|
|
3377
|
+
let normalized = safeRealpath(absolutePath);
|
|
3378
|
+
let normalizedRoot = safeRealpath(workspaceRoot);
|
|
3379
|
+
while (normalizedRoot.length > 1 && normalizedRoot.endsWith(path4.sep)) {
|
|
3380
|
+
normalizedRoot = normalizedRoot.slice(0, -1);
|
|
3381
|
+
}
|
|
3382
|
+
if (normalized === normalizedRoot) {
|
|
3383
|
+
return ".";
|
|
3384
|
+
}
|
|
3385
|
+
if (normalized.startsWith(normalizedRoot + path4.sep)) {
|
|
3386
|
+
return path4.relative(normalizedRoot, normalized);
|
|
3387
|
+
}
|
|
3388
|
+
return absolutePath;
|
|
3389
|
+
}
|
|
3324
3390
|
var init_path_validation = __esm({
|
|
3325
3391
|
"src/utils/path-validation.js"() {
|
|
3326
3392
|
"use strict";
|
|
@@ -4515,6 +4581,7 @@ async function analyzeAll(options) {
|
|
|
4515
4581
|
sessionId,
|
|
4516
4582
|
debug = false,
|
|
4517
4583
|
cwd,
|
|
4584
|
+
workspaceRoot,
|
|
4518
4585
|
allowedFolders,
|
|
4519
4586
|
provider,
|
|
4520
4587
|
model,
|
|
@@ -4527,10 +4594,11 @@ async function analyzeAll(options) {
|
|
|
4527
4594
|
if (!question) {
|
|
4528
4595
|
throw new Error('The "question" parameter is required.');
|
|
4529
4596
|
}
|
|
4597
|
+
const effectiveWorkspaceRoot = workspaceRoot || cwd || allowedFolders?.[0] || path9;
|
|
4530
4598
|
const delegateOptions = {
|
|
4531
4599
|
debug,
|
|
4532
4600
|
sessionId,
|
|
4533
|
-
path:
|
|
4601
|
+
path: effectiveWorkspaceRoot,
|
|
4534
4602
|
allowedFolders,
|
|
4535
4603
|
provider,
|
|
4536
4604
|
model,
|
|
@@ -8747,29 +8815,33 @@ import { dirname, resolve, isAbsolute, sep } from "path";
|
|
|
8747
8815
|
import { existsSync } from "fs";
|
|
8748
8816
|
function isPathAllowed(filePath, allowedFolders) {
|
|
8749
8817
|
if (!allowedFolders || allowedFolders.length === 0) {
|
|
8750
|
-
const resolvedPath2 =
|
|
8751
|
-
const cwd =
|
|
8818
|
+
const resolvedPath2 = safeRealpath(filePath);
|
|
8819
|
+
const cwd = safeRealpath(process.cwd());
|
|
8752
8820
|
return resolvedPath2 === cwd || resolvedPath2.startsWith(cwd + sep);
|
|
8753
8821
|
}
|
|
8754
|
-
const resolvedPath =
|
|
8822
|
+
const resolvedPath = safeRealpath(filePath);
|
|
8755
8823
|
return allowedFolders.some((folder) => {
|
|
8756
|
-
const allowedPath =
|
|
8824
|
+
const allowedPath = safeRealpath(folder);
|
|
8757
8825
|
return resolvedPath === allowedPath || resolvedPath.startsWith(allowedPath + sep);
|
|
8758
8826
|
});
|
|
8759
8827
|
}
|
|
8760
8828
|
function parseFileToolOptions(options = {}) {
|
|
8829
|
+
const allowedFolders = options.allowedFolders || [];
|
|
8761
8830
|
return {
|
|
8762
8831
|
debug: options.debug || false,
|
|
8763
|
-
allowedFolders
|
|
8764
|
-
cwd: options.cwd
|
|
8832
|
+
allowedFolders,
|
|
8833
|
+
cwd: options.cwd,
|
|
8834
|
+
// Consistent fallback chain: workspaceRoot > cwd > allowedFolders[0] > process.cwd()
|
|
8835
|
+
workspaceRoot: options.workspaceRoot || options.cwd || allowedFolders.length > 0 && allowedFolders[0] || process.cwd()
|
|
8765
8836
|
};
|
|
8766
8837
|
}
|
|
8767
8838
|
var editTool, createTool, editSchema, createSchema, editDescription, createDescription, editToolDefinition, createToolDefinition;
|
|
8768
8839
|
var init_edit = __esm({
|
|
8769
8840
|
"src/tools/edit.js"() {
|
|
8770
8841
|
"use strict";
|
|
8842
|
+
init_path_validation();
|
|
8771
8843
|
editTool = (options = {}) => {
|
|
8772
|
-
const { debug, allowedFolders, cwd } = parseFileToolOptions(options);
|
|
8844
|
+
const { debug, allowedFolders, cwd, workspaceRoot } = parseFileToolOptions(options);
|
|
8773
8845
|
return tool({
|
|
8774
8846
|
name: "edit",
|
|
8775
8847
|
description: `Edit files using exact string replacement (Claude Code style).
|
|
@@ -8825,7 +8897,8 @@ Important:
|
|
|
8825
8897
|
console.error(`[Edit] Attempting to edit file: ${resolvedPath}`);
|
|
8826
8898
|
}
|
|
8827
8899
|
if (!isPathAllowed(resolvedPath, allowedFolders)) {
|
|
8828
|
-
|
|
8900
|
+
const relativePath = toRelativePath(resolvedPath, workspaceRoot);
|
|
8901
|
+
return `Error editing file: Permission denied - ${relativePath} is outside allowed directories`;
|
|
8829
8902
|
}
|
|
8830
8903
|
if (!existsSync(resolvedPath)) {
|
|
8831
8904
|
return `Error editing file: File not found - ${file_path}`;
|
|
@@ -8861,7 +8934,7 @@ Important:
|
|
|
8861
8934
|
});
|
|
8862
8935
|
};
|
|
8863
8936
|
createTool = (options = {}) => {
|
|
8864
|
-
const { debug, allowedFolders, cwd } = parseFileToolOptions(options);
|
|
8937
|
+
const { debug, allowedFolders, cwd, workspaceRoot } = parseFileToolOptions(options);
|
|
8865
8938
|
return tool({
|
|
8866
8939
|
name: "create",
|
|
8867
8940
|
description: `Create new files with specified content.
|
|
@@ -8909,7 +8982,8 @@ Important:
|
|
|
8909
8982
|
console.error(`[Create] Attempting to create file: ${resolvedPath}`);
|
|
8910
8983
|
}
|
|
8911
8984
|
if (!isPathAllowed(resolvedPath, allowedFolders)) {
|
|
8912
|
-
|
|
8985
|
+
const relativePath = toRelativePath(resolvedPath, workspaceRoot);
|
|
8986
|
+
return `Error creating file: Permission denied - ${relativePath} is outside allowed directories`;
|
|
8913
8987
|
}
|
|
8914
8988
|
if (existsSync(resolvedPath) && !overwrite) {
|
|
8915
8989
|
return `Error creating file: File already exists - ${file_path}. Use overwrite: true to replace it.`;
|
|
@@ -10471,7 +10545,7 @@ var init_vercel = __esm({
|
|
|
10471
10545
|
});
|
|
10472
10546
|
};
|
|
10473
10547
|
delegateTool = (options = {}) => {
|
|
10474
|
-
const { debug = false, timeout = 300, cwd, allowedFolders, enableBash = false, bashConfig, architectureFileName, enableMcp = false, mcpConfig = null, mcpConfigPath = null, delegationManager = null } = options;
|
|
10548
|
+
const { debug = false, timeout = 300, cwd, allowedFolders, workspaceRoot, enableBash = false, bashConfig, architectureFileName, enableMcp = false, mcpConfig = null, mcpConfigPath = null, delegationManager = null } = options;
|
|
10475
10549
|
return tool2({
|
|
10476
10550
|
name: "delegate",
|
|
10477
10551
|
description: delegateDescription,
|
|
@@ -10504,8 +10578,8 @@ var init_vercel = __esm({
|
|
|
10504
10578
|
if (searchDelegate !== void 0 && typeof searchDelegate !== "boolean") {
|
|
10505
10579
|
throw new TypeError("searchDelegate must be a boolean if provided");
|
|
10506
10580
|
}
|
|
10507
|
-
const
|
|
10508
|
-
const effectivePath = path9 ||
|
|
10581
|
+
const effectiveWorkspaceRoot = workspaceRoot || allowedFolders && allowedFolders[0];
|
|
10582
|
+
const effectivePath = path9 || effectiveWorkspaceRoot || cwd;
|
|
10509
10583
|
if (debug) {
|
|
10510
10584
|
console.error(`Executing delegate with task: "${task.substring(0, 100)}${task.length > 100 ? "..." : ""}"`);
|
|
10511
10585
|
if (parentSessionId) {
|
|
@@ -10542,7 +10616,7 @@ var init_vercel = __esm({
|
|
|
10542
10616
|
});
|
|
10543
10617
|
};
|
|
10544
10618
|
analyzeAllTool = (options = {}) => {
|
|
10545
|
-
const { sessionId, debug = false, delegationManager = null } = options;
|
|
10619
|
+
const { sessionId, debug = false, delegationManager = null, workspaceRoot } = options;
|
|
10546
10620
|
return tool2({
|
|
10547
10621
|
name: "analyze_all",
|
|
10548
10622
|
description: analyzeAllDescription,
|
|
@@ -10561,12 +10635,14 @@ var init_vercel = __esm({
|
|
|
10561
10635
|
console.error(`[analyze_all] Question: ${question}`);
|
|
10562
10636
|
console.error(`[analyze_all] Path: ${searchPath}`);
|
|
10563
10637
|
}
|
|
10638
|
+
const effectiveWorkspaceRoot = workspaceRoot || options.cwd || options.allowedFolders && options.allowedFolders[0];
|
|
10564
10639
|
const result = await analyzeAll({
|
|
10565
10640
|
question,
|
|
10566
10641
|
path: searchPath,
|
|
10567
10642
|
sessionId,
|
|
10568
10643
|
debug,
|
|
10569
10644
|
cwd: options.cwd,
|
|
10645
|
+
workspaceRoot: effectiveWorkspaceRoot,
|
|
10570
10646
|
allowedFolders: options.allowedFolders,
|
|
10571
10647
|
provider: options.provider,
|
|
10572
10648
|
model: options.model,
|
|
@@ -12042,14 +12118,17 @@ var init_bash = __esm({
|
|
|
12042
12118
|
"use strict";
|
|
12043
12119
|
init_bashPermissions();
|
|
12044
12120
|
init_bashExecutor();
|
|
12121
|
+
init_path_validation();
|
|
12045
12122
|
bashTool = (options = {}) => {
|
|
12046
12123
|
const {
|
|
12047
12124
|
bashConfig = {},
|
|
12048
12125
|
debug = false,
|
|
12049
12126
|
cwd,
|
|
12050
12127
|
allowedFolders = [],
|
|
12128
|
+
workspaceRoot: providedWorkspaceRoot,
|
|
12051
12129
|
tracer = null
|
|
12052
12130
|
} = options;
|
|
12131
|
+
const workspaceRoot = providedWorkspaceRoot || cwd || allowedFolders.length > 0 && allowedFolders[0] || process.cwd();
|
|
12053
12132
|
const permissionChecker = new BashPermissionChecker({
|
|
12054
12133
|
allow: bashConfig.allow,
|
|
12055
12134
|
deny: bashConfig.deny,
|
|
@@ -12065,6 +12144,9 @@ var init_bash = __esm({
|
|
|
12065
12144
|
if (cwd) {
|
|
12066
12145
|
return cwd;
|
|
12067
12146
|
}
|
|
12147
|
+
if (workspaceRoot) {
|
|
12148
|
+
return workspaceRoot;
|
|
12149
|
+
}
|
|
12068
12150
|
if (allowedFolders && allowedFolders.length > 0) {
|
|
12069
12151
|
return allowedFolders[0];
|
|
12070
12152
|
}
|
|
@@ -12152,13 +12234,15 @@ For code exploration, try these safe alternatives:
|
|
|
12152
12234
|
const defaultDir = getDefaultWorkingDirectory();
|
|
12153
12235
|
const workingDir = workingDirectory ? isAbsolute3(workingDirectory) ? resolve4(workingDirectory) : resolve4(defaultDir, workingDirectory) : defaultDir;
|
|
12154
12236
|
if (allowedFolders && allowedFolders.length > 0) {
|
|
12155
|
-
const resolvedWorkingDir =
|
|
12237
|
+
const resolvedWorkingDir = safeRealpath(workingDir);
|
|
12156
12238
|
const isAllowed = allowedFolders.some((folder) => {
|
|
12157
|
-
const resolvedFolder =
|
|
12239
|
+
const resolvedFolder = safeRealpath(folder);
|
|
12158
12240
|
return resolvedWorkingDir === resolvedFolder || resolvedWorkingDir.startsWith(resolvedFolder + sep2);
|
|
12159
12241
|
});
|
|
12160
12242
|
if (!isAllowed) {
|
|
12161
|
-
|
|
12243
|
+
const relativeDir = toRelativePath(workingDir, workspaceRoot);
|
|
12244
|
+
const relativeAllowed = allowedFolders.map((f) => toRelativePath(f, workspaceRoot));
|
|
12245
|
+
return `Error: Working directory "${relativeDir}" is not within allowed folders: ${relativeAllowed.join(", ")}`;
|
|
12162
12246
|
}
|
|
12163
12247
|
}
|
|
12164
12248
|
const executionOptions = {
|
|
@@ -12713,6 +12797,183 @@ var init_simpleTelemetry = __esm({
|
|
|
12713
12797
|
console.log("[Attributes]", attributes);
|
|
12714
12798
|
}
|
|
12715
12799
|
}
|
|
12800
|
+
/**
|
|
12801
|
+
* Hash content for deduplication/comparison purposes
|
|
12802
|
+
* @param {string} content - The content to hash
|
|
12803
|
+
* @returns {string} - Hex string hash
|
|
12804
|
+
*/
|
|
12805
|
+
hashContent(content) {
|
|
12806
|
+
let hash = 0;
|
|
12807
|
+
const len = Math.min(content.length, 1e3);
|
|
12808
|
+
for (let i = 0; i < len; i++) {
|
|
12809
|
+
hash = (hash << 5) - hash + content.charCodeAt(i);
|
|
12810
|
+
hash |= 0;
|
|
12811
|
+
}
|
|
12812
|
+
return hash.toString(16);
|
|
12813
|
+
}
|
|
12814
|
+
/**
|
|
12815
|
+
* Record a conversation turn (assistant response or tool result)
|
|
12816
|
+
* @param {string} role - The role (assistant, tool_result)
|
|
12817
|
+
* @param {string} content - The turn content
|
|
12818
|
+
* @param {Object} metadata - Additional metadata
|
|
12819
|
+
*/
|
|
12820
|
+
recordConversationTurn(role, content, metadata = {}) {
|
|
12821
|
+
if (!this.isEnabled()) return;
|
|
12822
|
+
this.addEvent(`conversation.turn.${role}`, {
|
|
12823
|
+
"session.id": this.sessionId,
|
|
12824
|
+
"conversation.role": role,
|
|
12825
|
+
"conversation.content": content.substring(0, 1e4),
|
|
12826
|
+
"conversation.content.length": content.length,
|
|
12827
|
+
"conversation.content.hash": this.hashContent(content),
|
|
12828
|
+
...metadata
|
|
12829
|
+
});
|
|
12830
|
+
}
|
|
12831
|
+
/**
|
|
12832
|
+
* Record error events with classification
|
|
12833
|
+
* @param {string} errorType - The type of error (wrapped_tool, unrecognized_tool, no_tool_call, circuit_breaker, etc.)
|
|
12834
|
+
* @param {Object} errorDetails - Error details including message, stack, context
|
|
12835
|
+
*/
|
|
12836
|
+
recordErrorEvent(errorType, errorDetails = {}) {
|
|
12837
|
+
if (!this.isEnabled()) return;
|
|
12838
|
+
this.addEvent(`error.${errorType}`, {
|
|
12839
|
+
"session.id": this.sessionId,
|
|
12840
|
+
"error.type": errorType,
|
|
12841
|
+
"error.message": errorDetails.message?.substring(0, 1e3) || null,
|
|
12842
|
+
"error.stack": errorDetails.stack?.substring(0, 2e3) || null,
|
|
12843
|
+
"error.recoverable": errorDetails.recoverable ?? true,
|
|
12844
|
+
"error.context": JSON.stringify(errorDetails.context || {}).substring(0, 1e3),
|
|
12845
|
+
...Object.fromEntries(
|
|
12846
|
+
Object.entries(errorDetails).filter(([k]) => !["message", "stack", "context", "recoverable"].includes(k)).map(([k, v]) => [`error.${k}`, v])
|
|
12847
|
+
)
|
|
12848
|
+
});
|
|
12849
|
+
}
|
|
12850
|
+
/**
|
|
12851
|
+
* Record AI thinking/reasoning content
|
|
12852
|
+
* @param {string} thinkingContent - The thinking content from AI response
|
|
12853
|
+
* @param {Object} metadata - Additional metadata
|
|
12854
|
+
*/
|
|
12855
|
+
recordThinkingContent(thinkingContent, metadata = {}) {
|
|
12856
|
+
if (!this.isEnabled() || !thinkingContent) return;
|
|
12857
|
+
this.addEvent("ai.thinking", {
|
|
12858
|
+
"session.id": this.sessionId,
|
|
12859
|
+
"ai.thinking.content": thinkingContent.substring(0, 5e4),
|
|
12860
|
+
"ai.thinking.length": thinkingContent.length,
|
|
12861
|
+
"ai.thinking.hash": this.hashContent(thinkingContent),
|
|
12862
|
+
...metadata
|
|
12863
|
+
});
|
|
12864
|
+
}
|
|
12865
|
+
/**
|
|
12866
|
+
* Record AI tool call decision
|
|
12867
|
+
* @param {string} toolName - The tool name AI decided to call
|
|
12868
|
+
* @param {Object} params - The parameters AI provided
|
|
12869
|
+
* @param {Object} metadata - Additional metadata
|
|
12870
|
+
*/
|
|
12871
|
+
recordToolDecision(toolName, params, metadata = {}) {
|
|
12872
|
+
if (!this.isEnabled()) return;
|
|
12873
|
+
this.addEvent("ai.tool_decision", {
|
|
12874
|
+
"session.id": this.sessionId,
|
|
12875
|
+
"ai.tool_decision.name": toolName,
|
|
12876
|
+
"ai.tool_decision.params": JSON.stringify(params || {}).substring(0, 2e3),
|
|
12877
|
+
...metadata
|
|
12878
|
+
});
|
|
12879
|
+
}
|
|
12880
|
+
/**
|
|
12881
|
+
* Record tool result after execution
|
|
12882
|
+
* @param {string} toolName - The tool that was executed
|
|
12883
|
+
* @param {string|Object} result - The tool result
|
|
12884
|
+
* @param {boolean} success - Whether the tool succeeded
|
|
12885
|
+
* @param {number} durationMs - Execution duration in milliseconds
|
|
12886
|
+
* @param {Object} metadata - Additional metadata
|
|
12887
|
+
*/
|
|
12888
|
+
recordToolResult(toolName, result, success, durationMs, metadata = {}) {
|
|
12889
|
+
if (!this.isEnabled()) return;
|
|
12890
|
+
const resultStr = typeof result === "string" ? result : JSON.stringify(result);
|
|
12891
|
+
this.addEvent("tool.result", {
|
|
12892
|
+
"session.id": this.sessionId,
|
|
12893
|
+
"tool.name": toolName,
|
|
12894
|
+
"tool.result": resultStr.substring(0, 1e4),
|
|
12895
|
+
"tool.result.length": resultStr.length,
|
|
12896
|
+
"tool.result.hash": this.hashContent(resultStr),
|
|
12897
|
+
"tool.duration_ms": durationMs,
|
|
12898
|
+
"tool.success": success,
|
|
12899
|
+
...metadata
|
|
12900
|
+
});
|
|
12901
|
+
}
|
|
12902
|
+
/**
|
|
12903
|
+
* Record MCP tool execution start
|
|
12904
|
+
* @param {string} toolName - MCP tool name
|
|
12905
|
+
* @param {string} serverName - MCP server name
|
|
12906
|
+
* @param {Object} params - Tool parameters
|
|
12907
|
+
* @param {Object} metadata - Additional metadata
|
|
12908
|
+
*/
|
|
12909
|
+
recordMcpToolStart(toolName, serverName, params, metadata = {}) {
|
|
12910
|
+
if (!this.isEnabled()) return;
|
|
12911
|
+
this.addEvent("mcp.tool.start", {
|
|
12912
|
+
"session.id": this.sessionId,
|
|
12913
|
+
"mcp.tool.name": toolName,
|
|
12914
|
+
"mcp.tool.server": serverName || "unknown",
|
|
12915
|
+
"mcp.tool.params": JSON.stringify(params || {}).substring(0, 2e3),
|
|
12916
|
+
...metadata
|
|
12917
|
+
});
|
|
12918
|
+
}
|
|
12919
|
+
/**
|
|
12920
|
+
* Record MCP tool execution end
|
|
12921
|
+
* @param {string} toolName - MCP tool name
|
|
12922
|
+
* @param {string} serverName - MCP server name
|
|
12923
|
+
* @param {string|Object} result - Tool result
|
|
12924
|
+
* @param {boolean} success - Whether succeeded
|
|
12925
|
+
* @param {number} durationMs - Execution duration
|
|
12926
|
+
* @param {string} errorMessage - Error message if failed
|
|
12927
|
+
* @param {Object} metadata - Additional metadata
|
|
12928
|
+
*/
|
|
12929
|
+
recordMcpToolEnd(toolName, serverName, result, success, durationMs, errorMessage = null, metadata = {}) {
|
|
12930
|
+
if (!this.isEnabled()) return;
|
|
12931
|
+
const resultStr = typeof result === "string" ? result : JSON.stringify(result || "");
|
|
12932
|
+
this.addEvent("mcp.tool.end", {
|
|
12933
|
+
"session.id": this.sessionId,
|
|
12934
|
+
"mcp.tool.name": toolName,
|
|
12935
|
+
"mcp.tool.server": serverName || "unknown",
|
|
12936
|
+
"mcp.tool.result": resultStr.substring(0, 1e4),
|
|
12937
|
+
"mcp.tool.result.length": resultStr.length,
|
|
12938
|
+
"mcp.tool.duration_ms": durationMs,
|
|
12939
|
+
"mcp.tool.success": success,
|
|
12940
|
+
"mcp.tool.error": errorMessage,
|
|
12941
|
+
...metadata
|
|
12942
|
+
});
|
|
12943
|
+
}
|
|
12944
|
+
/**
|
|
12945
|
+
* Record iteration lifecycle event
|
|
12946
|
+
* @param {string} eventType - start or end
|
|
12947
|
+
* @param {number} iteration - Iteration number
|
|
12948
|
+
* @param {Object} data - Additional data
|
|
12949
|
+
*/
|
|
12950
|
+
recordIterationEvent(eventType, iteration, data = {}) {
|
|
12951
|
+
if (!this.isEnabled()) return;
|
|
12952
|
+
this.addEvent(`iteration.${eventType}`, {
|
|
12953
|
+
"session.id": this.sessionId,
|
|
12954
|
+
"iteration": iteration,
|
|
12955
|
+
...data
|
|
12956
|
+
});
|
|
12957
|
+
}
|
|
12958
|
+
/**
|
|
12959
|
+
* Record per-turn token breakdown
|
|
12960
|
+
* @param {number} iteration - Iteration number
|
|
12961
|
+
* @param {Object} tokenData - Token metrics
|
|
12962
|
+
*/
|
|
12963
|
+
recordTokenTurn(iteration, tokenData = {}) {
|
|
12964
|
+
if (!this.isEnabled()) return;
|
|
12965
|
+
this.addEvent("tokens.turn", {
|
|
12966
|
+
"session.id": this.sessionId,
|
|
12967
|
+
"iteration": iteration,
|
|
12968
|
+
"tokens.input": tokenData.inputTokens || 0,
|
|
12969
|
+
"tokens.output": tokenData.outputTokens || 0,
|
|
12970
|
+
"tokens.total": (tokenData.inputTokens || 0) + (tokenData.outputTokens || 0),
|
|
12971
|
+
"tokens.cache_read": tokenData.cacheReadTokens || 0,
|
|
12972
|
+
"tokens.cache_write": tokenData.cacheWriteTokens || 0,
|
|
12973
|
+
"tokens.context_used": tokenData.contextTokens || 0,
|
|
12974
|
+
"tokens.context_remaining": tokenData.maxContextTokens ? tokenData.maxContextTokens - (tokenData.contextTokens || 0) : null
|
|
12975
|
+
});
|
|
12976
|
+
}
|
|
12716
12977
|
async withSpan(spanName, fn, attributes = {}) {
|
|
12717
12978
|
if (!this.isEnabled()) {
|
|
12718
12979
|
return fn();
|
|
@@ -16588,18 +16849,18 @@ import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
|
16588
16849
|
import { lstatSync, readdir as readdirCB, readdirSync, readlinkSync, realpathSync as rps } from "fs";
|
|
16589
16850
|
import * as actualFS from "node:fs";
|
|
16590
16851
|
import { lstat, readdir, readlink, realpath } from "node:fs/promises";
|
|
16591
|
-
var
|
|
16852
|
+
var 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;
|
|
16592
16853
|
var init_esm4 = __esm({
|
|
16593
16854
|
"node_modules/path-scurry/dist/esm/index.js"() {
|
|
16594
16855
|
init_esm2();
|
|
16595
16856
|
init_esm3();
|
|
16596
|
-
|
|
16857
|
+
realpathSync2 = rps.native;
|
|
16597
16858
|
defaultFS = {
|
|
16598
16859
|
lstatSync,
|
|
16599
16860
|
readdir: readdirCB,
|
|
16600
16861
|
readdirSync,
|
|
16601
16862
|
readlinkSync,
|
|
16602
|
-
realpathSync,
|
|
16863
|
+
realpathSync: realpathSync2,
|
|
16603
16864
|
promises: {
|
|
16604
16865
|
lstat,
|
|
16605
16866
|
readdir,
|
|
@@ -20419,11 +20680,12 @@ function createTools(configOptions) {
|
|
|
20419
20680
|
return tools2;
|
|
20420
20681
|
}
|
|
20421
20682
|
function parseXmlToolCallWithThinking(xmlString, validTools) {
|
|
20422
|
-
const { cleanedXmlString, recoveryResult } = processXmlWithThinkingAndRecovery(xmlString, validTools);
|
|
20683
|
+
const { cleanedXmlString, recoveryResult, thinkingContent } = processXmlWithThinkingAndRecovery(xmlString, validTools);
|
|
20423
20684
|
if (recoveryResult) {
|
|
20424
|
-
return recoveryResult;
|
|
20685
|
+
return { ...recoveryResult, thinkingContent };
|
|
20425
20686
|
}
|
|
20426
|
-
|
|
20687
|
+
const toolCall = parseXmlToolCall(cleanedXmlString, validTools);
|
|
20688
|
+
return toolCall ? { ...toolCall, thinkingContent } : null;
|
|
20427
20689
|
}
|
|
20428
20690
|
var implementToolDefinition, listFilesToolDefinition, searchFilesToolDefinition, listSkillsToolDefinition, useSkillToolDefinition, readImageToolDefinition;
|
|
20429
20691
|
var init_tools2 = __esm({
|
|
@@ -59717,25 +59979,27 @@ function parseXmlMcpToolCall(xmlString, mcpToolNames = []) {
|
|
|
59717
59979
|
function parseHybridXmlToolCall(xmlString, nativeTools = [], mcpBridge = null) {
|
|
59718
59980
|
const nativeResult = parseNativeXmlToolWithThinking(xmlString, nativeTools);
|
|
59719
59981
|
if (nativeResult) {
|
|
59720
|
-
|
|
59982
|
+
const { thinkingContent, ...rest } = nativeResult;
|
|
59983
|
+
return { ...rest, type: "native", thinkingContent };
|
|
59721
59984
|
}
|
|
59722
59985
|
if (mcpBridge) {
|
|
59723
59986
|
const mcpResult = parseXmlMcpToolCall(xmlString, mcpBridge.getToolNames());
|
|
59724
59987
|
if (mcpResult) {
|
|
59725
|
-
|
|
59988
|
+
const { thinkingContent } = processXmlWithThinkingAndRecovery(xmlString, []);
|
|
59989
|
+
return { ...mcpResult, type: "mcp", thinkingContent };
|
|
59726
59990
|
}
|
|
59727
59991
|
}
|
|
59728
59992
|
return null;
|
|
59729
59993
|
}
|
|
59730
59994
|
function parseNativeXmlToolWithThinking(xmlString, validTools) {
|
|
59731
|
-
const { cleanedXmlString, recoveryResult } = processXmlWithThinkingAndRecovery(xmlString, validTools);
|
|
59995
|
+
const { cleanedXmlString, recoveryResult, thinkingContent } = processXmlWithThinkingAndRecovery(xmlString, validTools);
|
|
59732
59996
|
if (recoveryResult) {
|
|
59733
|
-
return recoveryResult;
|
|
59997
|
+
return { ...recoveryResult, thinkingContent };
|
|
59734
59998
|
}
|
|
59735
59999
|
for (const toolName of validTools) {
|
|
59736
60000
|
const result = parseNativeXmlTool(cleanedXmlString, toolName);
|
|
59737
60001
|
if (result) {
|
|
59738
|
-
return result;
|
|
60002
|
+
return { ...result, thinkingContent };
|
|
59739
60003
|
}
|
|
59740
60004
|
}
|
|
59741
60005
|
return null;
|
|
@@ -69991,6 +70255,7 @@ var init_ProbeAgent = __esm({
|
|
|
69991
70255
|
init_FallbackManager();
|
|
69992
70256
|
init_contextCompactor();
|
|
69993
70257
|
init_error_types();
|
|
70258
|
+
init_path_validation();
|
|
69994
70259
|
init_outputTruncator();
|
|
69995
70260
|
init_delegate();
|
|
69996
70261
|
init_tasks();
|
|
@@ -70108,7 +70373,8 @@ var init_ProbeAgent = __esm({
|
|
|
70108
70373
|
} else {
|
|
70109
70374
|
this.allowedFolders = [process.cwd()];
|
|
70110
70375
|
}
|
|
70111
|
-
this.
|
|
70376
|
+
this.workspaceRoot = getCommonPrefix(this.allowedFolders);
|
|
70377
|
+
this.cwd = options.cwd || this.workspaceRoot;
|
|
70112
70378
|
this.clientApiProvider = options.provider || null;
|
|
70113
70379
|
this.clientApiModel = options.model || null;
|
|
70114
70380
|
this.clientApiKey = null;
|
|
@@ -70120,6 +70386,8 @@ var init_ProbeAgent = __esm({
|
|
|
70120
70386
|
console.log(`[DEBUG] Maximum tool iterations configured: ${MAX_TOOL_ITERATIONS}`);
|
|
70121
70387
|
console.log(`[DEBUG] Allow Edit (implement tool): ${this.allowEdit}`);
|
|
70122
70388
|
console.log(`[DEBUG] Search delegation enabled: ${this.searchDelegate}`);
|
|
70389
|
+
console.log(`[DEBUG] Workspace root: ${this.workspaceRoot}`);
|
|
70390
|
+
console.log(`[DEBUG] Working directory (cwd): ${this.cwd}`);
|
|
70123
70391
|
}
|
|
70124
70392
|
this.initializeTools();
|
|
70125
70393
|
this.history = [];
|
|
@@ -70197,6 +70465,181 @@ var init_ProbeAgent = __esm({
|
|
|
70197
70465
|
_filterMcpTools(mcpToolNames) {
|
|
70198
70466
|
return mcpToolNames.filter((toolName) => this._isMcpToolAllowed(toolName));
|
|
70199
70467
|
}
|
|
70468
|
+
/**
|
|
70469
|
+
* Check if tracer is AppTracer (expects sessionId as first param) vs SimpleAppTracer
|
|
70470
|
+
* @returns {boolean} - True if tracer is AppTracer style (requires sessionId)
|
|
70471
|
+
* @private
|
|
70472
|
+
*/
|
|
70473
|
+
_isAppTracerStyle() {
|
|
70474
|
+
return this.tracer && typeof this.tracer.sessionSpans !== "undefined";
|
|
70475
|
+
}
|
|
70476
|
+
/**
|
|
70477
|
+
* Record an error classification event for telemetry
|
|
70478
|
+
* Provides unified error recording across all error types
|
|
70479
|
+
* @param {string} errorType - Error type (wrapped_tool, unrecognized_tool, no_tool_call, circuit_breaker)
|
|
70480
|
+
* @param {string} message - Error message
|
|
70481
|
+
* @param {Object} context - Additional context data
|
|
70482
|
+
* @param {number} iteration - Current iteration number
|
|
70483
|
+
* @private
|
|
70484
|
+
*/
|
|
70485
|
+
_recordErrorTelemetry(errorType, message, context, iteration) {
|
|
70486
|
+
if (!this.tracer) return;
|
|
70487
|
+
if (this._isAppTracerStyle() && typeof this.tracer.recordErrorClassification === "function") {
|
|
70488
|
+
this.tracer.recordErrorClassification(this.sessionId, iteration, errorType, {
|
|
70489
|
+
message,
|
|
70490
|
+
context
|
|
70491
|
+
});
|
|
70492
|
+
} else if (typeof this.tracer.recordErrorEvent === "function") {
|
|
70493
|
+
this.tracer.recordErrorEvent(errorType, {
|
|
70494
|
+
message,
|
|
70495
|
+
context: { ...context, iteration }
|
|
70496
|
+
});
|
|
70497
|
+
} else {
|
|
70498
|
+
this.tracer.addEvent(`error.${errorType}`, {
|
|
70499
|
+
"error.type": errorType,
|
|
70500
|
+
"error.message": message,
|
|
70501
|
+
"error.recoverable": errorType !== "circuit_breaker",
|
|
70502
|
+
"error.context": JSON.stringify(context).substring(0, 1e3),
|
|
70503
|
+
"iteration": iteration
|
|
70504
|
+
});
|
|
70505
|
+
}
|
|
70506
|
+
}
|
|
70507
|
+
/**
|
|
70508
|
+
* Record AI thinking content for telemetry
|
|
70509
|
+
* @param {string} thinkingContent - The thinking content
|
|
70510
|
+
* @param {number} iteration - Current iteration number
|
|
70511
|
+
* @private
|
|
70512
|
+
*/
|
|
70513
|
+
_recordThinkingTelemetry(thinkingContent, iteration) {
|
|
70514
|
+
if (!this.tracer || !thinkingContent) return;
|
|
70515
|
+
if (this._isAppTracerStyle() && typeof this.tracer.recordThinkingContent === "function") {
|
|
70516
|
+
this.tracer.recordThinkingContent(this.sessionId, iteration, thinkingContent);
|
|
70517
|
+
} else if (typeof this.tracer.recordThinkingContent === "function") {
|
|
70518
|
+
this.tracer.recordThinkingContent(thinkingContent, { iteration });
|
|
70519
|
+
} else {
|
|
70520
|
+
this.tracer.addEvent("ai.thinking", {
|
|
70521
|
+
"ai.thinking.content": thinkingContent.substring(0, 5e4),
|
|
70522
|
+
"ai.thinking.length": thinkingContent.length,
|
|
70523
|
+
"iteration": iteration
|
|
70524
|
+
});
|
|
70525
|
+
}
|
|
70526
|
+
}
|
|
70527
|
+
/**
|
|
70528
|
+
* Record AI tool decision for telemetry
|
|
70529
|
+
* @param {string} toolName - The tool name
|
|
70530
|
+
* @param {Object} params - Tool parameters
|
|
70531
|
+
* @param {number} responseLength - Length of AI response
|
|
70532
|
+
* @param {number} iteration - Current iteration number
|
|
70533
|
+
* @private
|
|
70534
|
+
*/
|
|
70535
|
+
_recordToolDecisionTelemetry(toolName, params, responseLength, iteration) {
|
|
70536
|
+
if (!this.tracer) return;
|
|
70537
|
+
if (this._isAppTracerStyle() && typeof this.tracer.recordAIToolDecision === "function") {
|
|
70538
|
+
this.tracer.recordAIToolDecision(this.sessionId, iteration, toolName, params);
|
|
70539
|
+
} else if (typeof this.tracer.recordToolDecision === "function") {
|
|
70540
|
+
this.tracer.recordToolDecision(toolName, params, {
|
|
70541
|
+
iteration,
|
|
70542
|
+
"ai.tool_decision.raw_response_length": responseLength
|
|
70543
|
+
});
|
|
70544
|
+
} else {
|
|
70545
|
+
this.tracer.addEvent("ai.tool_decision", {
|
|
70546
|
+
"ai.tool_decision.name": toolName,
|
|
70547
|
+
"ai.tool_decision.params": JSON.stringify(params || {}).substring(0, 2e3),
|
|
70548
|
+
"ai.tool_decision.raw_response_length": responseLength,
|
|
70549
|
+
"iteration": iteration
|
|
70550
|
+
});
|
|
70551
|
+
}
|
|
70552
|
+
}
|
|
70553
|
+
/**
|
|
70554
|
+
* Record tool result for telemetry
|
|
70555
|
+
* @param {string} toolName - The tool name
|
|
70556
|
+
* @param {string|Object} result - Tool result
|
|
70557
|
+
* @param {boolean} success - Whether tool succeeded
|
|
70558
|
+
* @param {number} durationMs - Execution duration in milliseconds
|
|
70559
|
+
* @param {number} iteration - Current iteration number
|
|
70560
|
+
* @private
|
|
70561
|
+
*/
|
|
70562
|
+
_recordToolResultTelemetry(toolName, result, success, durationMs, iteration) {
|
|
70563
|
+
if (!this.tracer) return;
|
|
70564
|
+
if (this._isAppTracerStyle() && typeof this.tracer.recordToolResult === "function") {
|
|
70565
|
+
this.tracer.recordToolResult(this.sessionId, iteration, toolName, result, success, durationMs);
|
|
70566
|
+
} else if (typeof this.tracer.recordToolResult === "function") {
|
|
70567
|
+
this.tracer.recordToolResult(toolName, result, success, durationMs, { iteration });
|
|
70568
|
+
} else {
|
|
70569
|
+
const resultStr = typeof result === "string" ? result : JSON.stringify(result || "");
|
|
70570
|
+
this.tracer.addEvent("tool.result", {
|
|
70571
|
+
"tool.name": toolName,
|
|
70572
|
+
"tool.result": resultStr.substring(0, 1e4),
|
|
70573
|
+
"tool.result.length": resultStr.length,
|
|
70574
|
+
"tool.duration_ms": durationMs,
|
|
70575
|
+
"tool.success": success,
|
|
70576
|
+
"iteration": iteration
|
|
70577
|
+
});
|
|
70578
|
+
}
|
|
70579
|
+
}
|
|
70580
|
+
/**
|
|
70581
|
+
* Record MCP tool lifecycle event for telemetry
|
|
70582
|
+
* @param {string} phase - 'start' or 'end'
|
|
70583
|
+
* @param {string} toolName - MCP tool name
|
|
70584
|
+
* @param {Object} params - Tool parameters (for start) or null (for end)
|
|
70585
|
+
* @param {number} iteration - Current iteration number
|
|
70586
|
+
* @param {Object} [endData] - Additional data for end phase (result, success, durationMs, error)
|
|
70587
|
+
* @private
|
|
70588
|
+
*/
|
|
70589
|
+
_recordMcpToolTelemetry(phase, toolName, params, iteration, endData = null) {
|
|
70590
|
+
if (!this.tracer) return;
|
|
70591
|
+
if (phase === "start") {
|
|
70592
|
+
if (this._isAppTracerStyle() && typeof this.tracer.recordMcpToolStart === "function") {
|
|
70593
|
+
this.tracer.recordMcpToolStart(this.sessionId, iteration, toolName, "mcp", params);
|
|
70594
|
+
} else if (typeof this.tracer.recordMcpToolStart === "function") {
|
|
70595
|
+
this.tracer.recordMcpToolStart(toolName, "mcp", params, { iteration });
|
|
70596
|
+
} else {
|
|
70597
|
+
this.tracer.addEvent("mcp.tool.start", {
|
|
70598
|
+
"mcp.tool.name": toolName,
|
|
70599
|
+
"mcp.tool.server": "mcp",
|
|
70600
|
+
"mcp.tool.params": JSON.stringify(params || {}).substring(0, 2e3),
|
|
70601
|
+
"iteration": iteration
|
|
70602
|
+
});
|
|
70603
|
+
}
|
|
70604
|
+
} else if (phase === "end" && endData) {
|
|
70605
|
+
const { result, success, durationMs, error } = endData;
|
|
70606
|
+
if (this._isAppTracerStyle() && typeof this.tracer.recordMcpToolEnd === "function") {
|
|
70607
|
+
this.tracer.recordMcpToolEnd(this.sessionId, iteration, toolName, "mcp", result, success, durationMs, error);
|
|
70608
|
+
} else if (typeof this.tracer.recordMcpToolEnd === "function") {
|
|
70609
|
+
this.tracer.recordMcpToolEnd(toolName, "mcp", result, success, durationMs, error, { iteration });
|
|
70610
|
+
} else {
|
|
70611
|
+
const resultStr = typeof result === "string" ? result : JSON.stringify(result || "");
|
|
70612
|
+
this.tracer.addEvent("mcp.tool.end", {
|
|
70613
|
+
"mcp.tool.name": toolName,
|
|
70614
|
+
"mcp.tool.server": "mcp",
|
|
70615
|
+
"mcp.tool.result": resultStr.substring(0, 1e4),
|
|
70616
|
+
"mcp.tool.result.length": resultStr.length,
|
|
70617
|
+
"mcp.tool.duration_ms": durationMs,
|
|
70618
|
+
"mcp.tool.success": success,
|
|
70619
|
+
"mcp.tool.error": error,
|
|
70620
|
+
"iteration": iteration
|
|
70621
|
+
});
|
|
70622
|
+
}
|
|
70623
|
+
}
|
|
70624
|
+
}
|
|
70625
|
+
/**
|
|
70626
|
+
* Record iteration lifecycle event for telemetry
|
|
70627
|
+
* @param {string} phase - 'end' (start is already handled elsewhere)
|
|
70628
|
+
* @param {number} iteration - Current iteration number
|
|
70629
|
+
* @param {Object} data - Additional iteration data
|
|
70630
|
+
* @private
|
|
70631
|
+
*/
|
|
70632
|
+
_recordIterationTelemetry(phase, iteration, data = {}) {
|
|
70633
|
+
if (!this.tracer) return;
|
|
70634
|
+
if (typeof this.tracer.recordIterationEvent === "function") {
|
|
70635
|
+
this.tracer.recordIterationEvent(phase, iteration, data);
|
|
70636
|
+
} else {
|
|
70637
|
+
this.tracer.addEvent(`iteration.${phase}`, {
|
|
70638
|
+
"iteration": iteration,
|
|
70639
|
+
...data
|
|
70640
|
+
});
|
|
70641
|
+
}
|
|
70642
|
+
}
|
|
70200
70643
|
/**
|
|
70201
70644
|
* Initialize the agent asynchronously (must be called after constructor)
|
|
70202
70645
|
* This method initializes MCP and merges MCP tools into the tool list, and loads history from storage
|
|
@@ -70292,8 +70735,9 @@ var init_ProbeAgent = __esm({
|
|
|
70292
70735
|
const configOptions = {
|
|
70293
70736
|
sessionId: this.sessionId,
|
|
70294
70737
|
debug: this.debug,
|
|
70295
|
-
// Use
|
|
70296
|
-
cwd: this.cwd
|
|
70738
|
+
// Use cwd (which defaults to workspaceRoot in constructor)
|
|
70739
|
+
cwd: this.cwd,
|
|
70740
|
+
workspaceRoot: this.workspaceRoot,
|
|
70297
70741
|
allowedFolders: this.allowedFolders,
|
|
70298
70742
|
outline: this.outline,
|
|
70299
70743
|
searchDelegate: this.searchDelegate,
|
|
@@ -70980,16 +71424,16 @@ var init_ProbeAgent = __esm({
|
|
|
70980
71424
|
let absolutePath;
|
|
70981
71425
|
let isPathAllowed2 = false;
|
|
70982
71426
|
if (isAbsolute5(imagePath)) {
|
|
70983
|
-
absolutePath =
|
|
71427
|
+
absolutePath = safeRealpath(resolve6(imagePath));
|
|
70984
71428
|
isPathAllowed2 = allowedDirs.some((dir) => {
|
|
70985
|
-
const
|
|
70986
|
-
return absolutePath ===
|
|
71429
|
+
const resolvedDir = safeRealpath(dir);
|
|
71430
|
+
return absolutePath === resolvedDir || absolutePath.startsWith(resolvedDir + sep5);
|
|
70987
71431
|
});
|
|
70988
71432
|
} else {
|
|
70989
71433
|
for (const dir of allowedDirs) {
|
|
70990
|
-
const
|
|
70991
|
-
const resolvedPath =
|
|
70992
|
-
if (resolvedPath ===
|
|
71434
|
+
const resolvedDir = safeRealpath(dir);
|
|
71435
|
+
const resolvedPath = safeRealpath(resolve6(dir, imagePath));
|
|
71436
|
+
if (resolvedPath === resolvedDir || resolvedPath.startsWith(resolvedDir + sep5)) {
|
|
70993
71437
|
absolutePath = resolvedPath;
|
|
70994
71438
|
isPathAllowed2 = true;
|
|
70995
71439
|
break;
|
|
@@ -71172,7 +71616,7 @@ var init_ProbeAgent = __esm({
|
|
|
71172
71616
|
if (this._architectureContextLoaded) {
|
|
71173
71617
|
return this.architectureContext;
|
|
71174
71618
|
}
|
|
71175
|
-
const rootDirectory = this.allowedFolders.length > 0 ? this.allowedFolders[0] : process.cwd();
|
|
71619
|
+
const rootDirectory = this.workspaceRoot || (this.allowedFolders.length > 0 ? this.allowedFolders[0] : process.cwd());
|
|
71176
71620
|
const configuredName = typeof this.architectureFileName === "string" ? this.architectureFileName.trim() : "";
|
|
71177
71621
|
const hasConfiguredName = !!configuredName;
|
|
71178
71622
|
let guidanceCandidates = [];
|
|
@@ -71309,6 +71753,9 @@ ${this.architectureContext.content}
|
|
|
71309
71753
|
`;
|
|
71310
71754
|
}
|
|
71311
71755
|
_getSkillsRepoRoot() {
|
|
71756
|
+
if (this.workspaceRoot) {
|
|
71757
|
+
return resolve6(this.workspaceRoot);
|
|
71758
|
+
}
|
|
71312
71759
|
if (this.allowedFolders && this.allowedFolders.length > 0) {
|
|
71313
71760
|
return resolve6(this.allowedFolders[0]);
|
|
71314
71761
|
}
|
|
@@ -71376,7 +71823,7 @@ Workspace: ${this.allowedFolders.join(", ")}`;
|
|
|
71376
71823
|
|
|
71377
71824
|
# Repository Structure
|
|
71378
71825
|
`;
|
|
71379
|
-
systemPrompt += `You are working with a repository located at: ${this.
|
|
71826
|
+
systemPrompt += `You are working with a repository located at: ${this.workspaceRoot}
|
|
71380
71827
|
|
|
71381
71828
|
`;
|
|
71382
71829
|
systemPrompt += `Here's an overview of the repository structure (showing up to 100 most relevant files):
|
|
@@ -71429,7 +71876,7 @@ Workspace: ${this.allowedFolders.join(", ")}`;
|
|
|
71429
71876
|
|
|
71430
71877
|
# Repository Structure
|
|
71431
71878
|
`;
|
|
71432
|
-
systemPrompt += `You are working with a repository located at: ${this.
|
|
71879
|
+
systemPrompt += `You are working with a repository located at: ${this.workspaceRoot}
|
|
71433
71880
|
|
|
71434
71881
|
`;
|
|
71435
71882
|
systemPrompt += `Here's an overview of the repository structure (showing up to 100 most relevant files):
|
|
@@ -71728,21 +72175,34 @@ For MCP tools, use JSON format within the params tag, e.g.:
|
|
|
71728
72175
|
`;
|
|
71729
72176
|
}
|
|
71730
72177
|
}
|
|
71731
|
-
const searchDirectory = this.
|
|
72178
|
+
const searchDirectory = this.workspaceRoot;
|
|
71732
72179
|
if (this.debug) {
|
|
71733
|
-
console.log(`[DEBUG] Generating file list for
|
|
72180
|
+
console.log(`[DEBUG] Generating file list for workspace root: ${searchDirectory}...`);
|
|
72181
|
+
}
|
|
72182
|
+
const relativeWorkspaces = this.allowedFolders.map((f) => {
|
|
72183
|
+
const rel = toRelativePath(f, this.workspaceRoot);
|
|
72184
|
+
if (rel && rel !== "." && !rel.startsWith(".") && !rel.startsWith("/")) {
|
|
72185
|
+
return "./" + rel;
|
|
72186
|
+
}
|
|
72187
|
+
return rel;
|
|
72188
|
+
}).filter((f) => f && f !== ".");
|
|
72189
|
+
let workspaceDesc;
|
|
72190
|
+
if (relativeWorkspaces.length === 0) {
|
|
72191
|
+
workspaceDesc = ". (current directory)";
|
|
72192
|
+
} else {
|
|
72193
|
+
workspaceDesc = relativeWorkspaces.join(", ");
|
|
71734
72194
|
}
|
|
71735
72195
|
try {
|
|
71736
72196
|
const files = await listFilesByLevel({
|
|
71737
72197
|
directory: searchDirectory,
|
|
71738
72198
|
maxFiles: 100,
|
|
71739
72199
|
respectGitignore: !process.env.PROBE_NO_GITIGNORE || process.env.PROBE_NO_GITIGNORE === "",
|
|
71740
|
-
cwd:
|
|
72200
|
+
cwd: this.workspaceRoot
|
|
71741
72201
|
});
|
|
71742
72202
|
systemMessage += `
|
|
71743
72203
|
# Repository Structure
|
|
71744
72204
|
|
|
71745
|
-
You are working with a
|
|
72205
|
+
You are working with a workspace. Available paths: ${workspaceDesc}
|
|
71746
72206
|
|
|
71747
72207
|
Here's an overview of the repository structure (showing up to 100 most relevant files):
|
|
71748
72208
|
|
|
@@ -71758,15 +72218,22 @@ ${files}
|
|
|
71758
72218
|
systemMessage += `
|
|
71759
72219
|
# Repository Structure
|
|
71760
72220
|
|
|
71761
|
-
You are working with a
|
|
72221
|
+
You are working with a workspace. Available paths: ${workspaceDesc}
|
|
71762
72222
|
|
|
71763
72223
|
`;
|
|
71764
72224
|
}
|
|
71765
72225
|
await this.loadArchitectureContext();
|
|
71766
72226
|
systemMessage += this.getArchitectureSection();
|
|
71767
72227
|
if (this.allowedFolders.length > 0) {
|
|
72228
|
+
const relativeAllowed = this.allowedFolders.map((f) => {
|
|
72229
|
+
const rel = toRelativePath(f, this.workspaceRoot);
|
|
72230
|
+
if (rel && rel !== "." && !rel.startsWith(".") && !rel.startsWith("/")) {
|
|
72231
|
+
return "./" + rel;
|
|
72232
|
+
}
|
|
72233
|
+
return rel;
|
|
72234
|
+
});
|
|
71768
72235
|
systemMessage += `
|
|
71769
|
-
**Important**: For security reasons, you can only
|
|
72236
|
+
**Important**: For security reasons, you can only access these paths: ${relativeAllowed.join(", ")}
|
|
71770
72237
|
|
|
71771
72238
|
`;
|
|
71772
72239
|
}
|
|
@@ -72151,8 +72618,12 @@ You are working with a repository located at: ${searchDirectory}
|
|
|
72151
72618
|
}
|
|
72152
72619
|
const nativeTools = validTools;
|
|
72153
72620
|
const parsedTool = this.mcpBridge && !options._disableTools ? parseHybridXmlToolCall(assistantResponseContent, nativeTools, this.mcpBridge) : parseXmlToolCallWithThinking(assistantResponseContent, validTools);
|
|
72621
|
+
if (parsedTool?.thinkingContent) {
|
|
72622
|
+
this._recordThinkingTelemetry(parsedTool.thinkingContent, currentIteration);
|
|
72623
|
+
}
|
|
72154
72624
|
if (parsedTool) {
|
|
72155
72625
|
const { toolName, params } = parsedTool;
|
|
72626
|
+
this._recordToolDecisionTelemetry(toolName, params, assistantResponseContent.length, currentIteration);
|
|
72156
72627
|
if (this.debug) console.log(`[DEBUG] Parsed tool call: ${toolName} with params:`, params);
|
|
72157
72628
|
if (toolName === "attempt_completion") {
|
|
72158
72629
|
completionAttempted = true;
|
|
@@ -72229,6 +72700,8 @@ You are working with a repository located at: ${searchDirectory}
|
|
|
72229
72700
|
} else {
|
|
72230
72701
|
const { type } = parsedTool;
|
|
72231
72702
|
if (type === "mcp" && this.mcpBridge && this.mcpBridge.isMcpTool(toolName)) {
|
|
72703
|
+
const mcpStartTime = Date.now();
|
|
72704
|
+
this._recordMcpToolTelemetry("start", toolName, params, currentIteration);
|
|
72232
72705
|
try {
|
|
72233
72706
|
if (this.debug) {
|
|
72234
72707
|
console.error(`
|
|
@@ -72258,6 +72731,13 @@ You are working with a repository located at: ${searchDirectory}
|
|
|
72258
72731
|
} catch (truncateError) {
|
|
72259
72732
|
console.error(`[WARN] Tool output truncation failed: ${truncateError.message}`);
|
|
72260
72733
|
}
|
|
72734
|
+
const mcpDurationMs = Date.now() - mcpStartTime;
|
|
72735
|
+
this._recordMcpToolTelemetry("end", toolName, null, currentIteration, {
|
|
72736
|
+
result: toolResultContent,
|
|
72737
|
+
success: true,
|
|
72738
|
+
durationMs: mcpDurationMs,
|
|
72739
|
+
error: null
|
|
72740
|
+
});
|
|
72261
72741
|
if (this.debug) {
|
|
72262
72742
|
const preview = toolResultContent.length > 500 ? toolResultContent.substring(0, 500) + "..." : toolResultContent;
|
|
72263
72743
|
console.error(`[DEBUG] ========================================`);
|
|
@@ -72267,10 +72747,18 @@ You are working with a repository located at: ${searchDirectory}
|
|
|
72267
72747
|
console.error(`[DEBUG] ========================================
|
|
72268
72748
|
`);
|
|
72269
72749
|
}
|
|
72750
|
+
currentMessages.push({ role: "assistant", content: assistantResponseContent });
|
|
72270
72751
|
currentMessages.push({ role: "user", content: `<tool_result>
|
|
72271
72752
|
${toolResultContent}
|
|
72272
72753
|
</tool_result>` });
|
|
72273
72754
|
} catch (error) {
|
|
72755
|
+
const mcpDurationMs = Date.now() - mcpStartTime;
|
|
72756
|
+
this._recordMcpToolTelemetry("end", toolName, null, currentIteration, {
|
|
72757
|
+
result: null,
|
|
72758
|
+
success: false,
|
|
72759
|
+
durationMs: mcpDurationMs,
|
|
72760
|
+
error: error.message
|
|
72761
|
+
});
|
|
72274
72762
|
console.error(`Error executing MCP tool ${toolName}:`, error);
|
|
72275
72763
|
if (this.debug) {
|
|
72276
72764
|
console.error(`[DEBUG] ========================================`);
|
|
@@ -72280,17 +72768,18 @@ ${toolResultContent}
|
|
|
72280
72768
|
`);
|
|
72281
72769
|
}
|
|
72282
72770
|
const errorXml = formatErrorForAI(error);
|
|
72771
|
+
currentMessages.push({ role: "assistant", content: assistantResponseContent });
|
|
72283
72772
|
currentMessages.push({ role: "user", content: `<tool_result>
|
|
72284
72773
|
${errorXml}
|
|
72285
72774
|
</tool_result>` });
|
|
72286
72775
|
}
|
|
72287
72776
|
} else if (this.toolImplementations[toolName]) {
|
|
72288
72777
|
try {
|
|
72289
|
-
let resolvedWorkingDirectory = this.cwd || this.allowedFolders && this.allowedFolders[0] || process.cwd();
|
|
72778
|
+
let resolvedWorkingDirectory = this.workspaceRoot || this.cwd || this.allowedFolders && this.allowedFolders[0] || process.cwd();
|
|
72290
72779
|
if (params.workingDirectory) {
|
|
72291
|
-
const requestedDir = isAbsolute5(params.workingDirectory) ? resolve6(params.workingDirectory) : resolve6(resolvedWorkingDirectory, params.workingDirectory);
|
|
72780
|
+
const requestedDir = safeRealpath(isAbsolute5(params.workingDirectory) ? resolve6(params.workingDirectory) : resolve6(resolvedWorkingDirectory, params.workingDirectory));
|
|
72292
72781
|
const isWithinAllowed = !this.allowedFolders || this.allowedFolders.length === 0 || this.allowedFolders.some((folder) => {
|
|
72293
|
-
const resolvedFolder =
|
|
72782
|
+
const resolvedFolder = safeRealpath(folder);
|
|
72294
72783
|
return requestedDir === resolvedFolder || requestedDir.startsWith(resolvedFolder + sep5);
|
|
72295
72784
|
});
|
|
72296
72785
|
if (isWithinAllowed) {
|
|
@@ -72362,6 +72851,7 @@ ${errorXml}
|
|
|
72362
72851
|
return await this.toolImplementations[toolName].execute(toolParams);
|
|
72363
72852
|
};
|
|
72364
72853
|
let toolResult;
|
|
72854
|
+
const toolStartTime = Date.now();
|
|
72365
72855
|
try {
|
|
72366
72856
|
if (this.tracer) {
|
|
72367
72857
|
toolResult = await this.tracer.withSpan("tool.call", executeToolCall, {
|
|
@@ -72372,6 +72862,8 @@ ${errorXml}
|
|
|
72372
72862
|
} else {
|
|
72373
72863
|
toolResult = await executeToolCall();
|
|
72374
72864
|
}
|
|
72865
|
+
const toolDurationMs = Date.now() - toolStartTime;
|
|
72866
|
+
this._recordToolResultTelemetry(toolName, toolResult, true, toolDurationMs, currentIteration);
|
|
72375
72867
|
if (this.debug) {
|
|
72376
72868
|
const resultPreview = typeof toolResult === "string" ? toolResult.length > 500 ? toolResult.substring(0, 500) + "..." : toolResult : toolResult ? JSON.stringify(toolResult, null, 2).substring(0, 500) + "..." : "No Result";
|
|
72377
72869
|
console.error(`[DEBUG] ========================================`);
|
|
@@ -72428,6 +72920,20 @@ ${toolResultContent}
|
|
|
72428
72920
|
role: "user",
|
|
72429
72921
|
content: toolResultMessage
|
|
72430
72922
|
});
|
|
72923
|
+
if (this.tracer) {
|
|
72924
|
+
if (typeof this.tracer.recordConversationTurn === "function") {
|
|
72925
|
+
this.tracer.recordConversationTurn("assistant", assistantResponseContent, {
|
|
72926
|
+
iteration: currentIteration,
|
|
72927
|
+
has_tool_call: true,
|
|
72928
|
+
tool_name: toolName
|
|
72929
|
+
});
|
|
72930
|
+
this.tracer.recordConversationTurn("tool_result", toolResultContent, {
|
|
72931
|
+
iteration: currentIteration,
|
|
72932
|
+
tool_name: toolName,
|
|
72933
|
+
tool_success: true
|
|
72934
|
+
});
|
|
72935
|
+
}
|
|
72936
|
+
}
|
|
72431
72937
|
if (this.debug) {
|
|
72432
72938
|
console.log(`[DEBUG] Tool ${toolName} executed successfully. Result length: ${typeof toolResult === "string" ? toolResult.length : JSON.stringify(toolResult).length}`);
|
|
72433
72939
|
}
|
|
@@ -72498,6 +73004,7 @@ ${errorXml}
|
|
|
72498
73004
|
if (this.debug) {
|
|
72499
73005
|
console.log(`[DEBUG] Detected wrapped tool '${wrappedToolName}' in assistant response - wrong XML format.`);
|
|
72500
73006
|
}
|
|
73007
|
+
this._recordErrorTelemetry("wrapped_tool", "Tool call wrapped in markdown", { toolName: wrappedToolName }, currentIteration);
|
|
72501
73008
|
const toolError = new ParameterError(
|
|
72502
73009
|
`Tool '${wrappedToolName}' found but in WRONG FORMAT - do not wrap tools in other XML tags.`,
|
|
72503
73010
|
{
|
|
@@ -72523,6 +73030,7 @@ ${formatErrorForAI(toolError)}
|
|
|
72523
73030
|
if (this.debug) {
|
|
72524
73031
|
console.log(`[DEBUG] Detected unrecognized tool '${unrecognizedTool}' in assistant response.`);
|
|
72525
73032
|
}
|
|
73033
|
+
this._recordErrorTelemetry("unrecognized_tool", `Unknown tool: ${unrecognizedTool}`, { toolName: unrecognizedTool, validTools }, currentIteration);
|
|
72526
73034
|
const toolError = new ParameterError(`Tool '${unrecognizedTool}' is not available in this context.`, {
|
|
72527
73035
|
suggestion: `Available tools: ${validTools.join(", ")}. Please use one of these tools instead.`
|
|
72528
73036
|
});
|
|
@@ -72530,6 +73038,7 @@ ${formatErrorForAI(toolError)}
|
|
|
72530
73038
|
${formatErrorForAI(toolError)}
|
|
72531
73039
|
</tool_result>`;
|
|
72532
73040
|
} else {
|
|
73041
|
+
this._recordErrorTelemetry("no_tool_call", "AI response did not contain tool call", { responsePreview: assistantResponseContent.substring(0, 500) }, currentIteration);
|
|
72533
73042
|
if (currentIteration >= maxIterations) {
|
|
72534
73043
|
let cleanedResponse = assistantResponseContent;
|
|
72535
73044
|
cleanedResponse = cleanedResponse.replace(/<thinking>[\s\S]*?<\/thinking>/gi, "").trim();
|
|
@@ -72605,6 +73114,7 @@ Note: <attempt_complete></attempt_complete> reuses your PREVIOUS assistant messa
|
|
|
72605
73114
|
sameFormatErrorCount++;
|
|
72606
73115
|
if (sameFormatErrorCount >= MAX_REPEATED_FORMAT_ERRORS) {
|
|
72607
73116
|
const errorDesc = isWrapped ? "wrapped tool format" : unrecognizedTool;
|
|
73117
|
+
this._recordErrorTelemetry("circuit_breaker", "Format error limit exceeded", { formatErrorCount: sameFormatErrorCount, errorCategory }, currentIteration);
|
|
72608
73118
|
console.error(`[ERROR] Format error category '${errorCategory}' repeated ${sameFormatErrorCount} times. Breaking loop early to prevent infinite iteration.`);
|
|
72609
73119
|
finalResult = `Error: Unable to complete request. The AI model repeatedly used incorrect tool call format (${errorDesc}). Please try rephrasing your question or using a different model.`;
|
|
72610
73120
|
break;
|
|
@@ -72618,6 +73128,10 @@ Note: <attempt_complete></attempt_complete> reuses your PREVIOUS assistant messa
|
|
|
72618
73128
|
sameFormatErrorCount = 0;
|
|
72619
73129
|
}
|
|
72620
73130
|
}
|
|
73131
|
+
this._recordIterationTelemetry("end", currentIteration, {
|
|
73132
|
+
"iteration.completed": completionAttempted,
|
|
73133
|
+
"iteration.message_count": currentMessages.length
|
|
73134
|
+
});
|
|
72621
73135
|
if (currentMessages.length > MAX_HISTORY_MESSAGES) {
|
|
72622
73136
|
const messagesBefore = currentMessages.length;
|
|
72623
73137
|
const systemMsg = currentMessages[0];
|
|
@@ -72734,7 +73248,7 @@ Convert your previous response content into actual JSON data that follows this s
|
|
|
72734
73248
|
}
|
|
72735
73249
|
const mermaidValidation = await validateAndFixMermaidResponse(finalResult, {
|
|
72736
73250
|
debug: this.debug,
|
|
72737
|
-
path: this.allowedFolders[0],
|
|
73251
|
+
path: this.workspaceRoot || this.allowedFolders[0],
|
|
72738
73252
|
provider: this.clientApiProvider,
|
|
72739
73253
|
model: this.model,
|
|
72740
73254
|
tracer: this.tracer
|
|
@@ -72807,7 +73321,7 @@ Convert your previous response content into actual JSON data that follows this s
|
|
|
72807
73321
|
}
|
|
72808
73322
|
const { JsonFixingAgent: JsonFixingAgent2 } = await Promise.resolve().then(() => (init_schemaUtils(), schemaUtils_exports));
|
|
72809
73323
|
const jsonFixer = new JsonFixingAgent2({
|
|
72810
|
-
path: this.allowedFolders[0],
|
|
73324
|
+
path: this.workspaceRoot || this.allowedFolders[0],
|
|
72811
73325
|
provider: this.clientApiProvider,
|
|
72812
73326
|
model: this.model,
|
|
72813
73327
|
debug: this.debug,
|
|
@@ -72876,7 +73390,7 @@ Convert your previous response content into actual JSON data that follows this s
|
|
|
72876
73390
|
}
|
|
72877
73391
|
const mermaidValidation = await validateAndFixMermaidResponse(finalResult, {
|
|
72878
73392
|
debug: this.debug,
|
|
72879
|
-
path: this.allowedFolders[0],
|
|
73393
|
+
path: this.workspaceRoot || this.allowedFolders[0],
|
|
72880
73394
|
provider: this.clientApiProvider,
|
|
72881
73395
|
model: this.model,
|
|
72882
73396
|
tracer: this.tracer
|
|
@@ -73008,7 +73522,7 @@ Convert your previous response content into actual JSON data that follows this s
|
|
|
73008
73522
|
}
|
|
73009
73523
|
const finalMermaidValidation = await validateAndFixMermaidResponse(finalResult, {
|
|
73010
73524
|
debug: this.debug,
|
|
73011
|
-
path: this.allowedFolders[0],
|
|
73525
|
+
path: this.workspaceRoot || this.allowedFolders[0],
|
|
73012
73526
|
provider: this.clientApiProvider,
|
|
73013
73527
|
model: this.model,
|
|
73014
73528
|
tracer: this.tracer
|
|
@@ -73158,8 +73672,7 @@ Convert your previous response content into actual JSON data that follows this s
|
|
|
73158
73672
|
allowEdit: this.allowEdit,
|
|
73159
73673
|
enableDelegate: this.enableDelegate,
|
|
73160
73674
|
architectureFileName: this.architectureFileName,
|
|
73161
|
-
|
|
73162
|
-
// Use first allowed folder as primary path
|
|
73675
|
+
// Pass allowedFolders which will recompute workspaceRoot correctly
|
|
73163
73676
|
allowedFolders: [...this.allowedFolders],
|
|
73164
73677
|
cwd: this.cwd,
|
|
73165
73678
|
// Preserve explicit working directory
|