@probelabs/probe 0.6.0-rc281 → 0.6.0-rc282
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-rc282-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc282-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc282-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/{probe-v0.6.0-rc281-x86_64-pc-windows-msvc.zip → probe-v0.6.0-rc282-x86_64-pc-windows-msvc.zip} +0 -0
- package/bin/binaries/probe-v0.6.0-rc282-x86_64-unknown-linux-musl.tar.gz +0 -0
- package/build/agent/index.js +53 -8
- package/build/tools/vercel.js +67 -8
- package/cjs/agent/ProbeAgent.cjs +55 -10
- package/cjs/index.cjs +55 -10
- package/package.json +2 -2
- package/src/tools/vercel.js +67 -8
- package/bin/binaries/probe-v0.6.0-rc281-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc281-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc281-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc281-x86_64-unknown-linux-musl.tar.gz +0 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/build/agent/index.js
CHANGED
|
@@ -9185,13 +9185,19 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
9185
9185
|
"- listFiles: Understand directory structure to find where relevant code might live.",
|
|
9186
9186
|
"",
|
|
9187
9187
|
"CRITICAL - How probe search works (do NOT ignore):",
|
|
9188
|
-
"- By default (exact=false), probe ALREADY handles stemming, case-insensitive matching, and camelCase/snake_case splitting.",
|
|
9188
|
+
"- By default (exact=false), probe ALREADY handles stemming, case-insensitive matching, and camelCase/snake_case splitting automatically.",
|
|
9189
9189
|
'- Searching "allowed_ips" ALREADY matches "AllowedIPs", "allowedIps", "allowed_ips", etc. Do NOT manually try case/style variations.',
|
|
9190
9190
|
'- Searching "getUserData" ALREADY matches "get", "user", "data" and their variations.',
|
|
9191
|
-
"- NEVER repeat the same search query \u2014 you will get the same results.",
|
|
9191
|
+
"- NEVER repeat the same search query \u2014 you will get the same results. Changing the path does NOT change this.",
|
|
9192
9192
|
"- NEVER search trivial variations of the same keyword (e.g., AllowedIPs then allowedIps then allowed_ips). This is wasteful \u2014 probe handles it.",
|
|
9193
|
-
"- If a search returns no results, the term likely does not exist
|
|
9194
|
-
"- If 2-3
|
|
9193
|
+
"- If a search returns no results, the term likely does not exist. Try a genuinely DIFFERENT keyword or concept, not a variation.",
|
|
9194
|
+
"- If 2-3 searches return no results for a concept, STOP searching for it and move on. Do NOT keep retrying.",
|
|
9195
|
+
"",
|
|
9196
|
+
"When to use exact=true:",
|
|
9197
|
+
"- Use exact=true when searching for a KNOWN symbol name (function, type, variable, struct).",
|
|
9198
|
+
"- exact=true matches the literal string only \u2014 no stemming, no splitting.",
|
|
9199
|
+
'- This is ideal for precise lookups: exact=true "ForwardMessage", exact=true "SessionLimiter", exact=true "ThrottleRetryLimit".',
|
|
9200
|
+
"- Do NOT use exact=true for exploratory/conceptual queries \u2014 use the default for those.",
|
|
9195
9201
|
"",
|
|
9196
9202
|
"GOOD search strategy (do this):",
|
|
9197
9203
|
' Query: "How does authentication work and how are sessions managed?"',
|
|
@@ -9200,10 +9206,18 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
9200
9206
|
' \u2192 search "allowlist middleware" (one search, probe handles IP/ip/Ip variations)',
|
|
9201
9207
|
' Query: "How does BM25 scoring work with SIMD optimization?"',
|
|
9202
9208
|
' \u2192 search "BM25 scoring" \u2192 search "SIMD optimization" (two different concepts)',
|
|
9209
|
+
' Query: "Find ForwardMessage and SessionLimiter functions"',
|
|
9210
|
+
' \u2192 search exact=true "ForwardMessage" \u2192 search exact=true "SessionLimiter" (known symbols, use exact)',
|
|
9211
|
+
' Query: "Find ThrottleRetryLimit usage"',
|
|
9212
|
+
' \u2192 search exact=true "ThrottleRetryLimit" (one search, if no results the symbol does not exist \u2014 stop)',
|
|
9203
9213
|
"",
|
|
9204
9214
|
"BAD search strategy (never do this):",
|
|
9205
|
-
' \u2192 search "AllowedIPs" \u2192 search "allowedIps" \u2192 search "allowed_ips" (WRONG:
|
|
9206
|
-
' \u2192 search "
|
|
9215
|
+
' \u2192 search "AllowedIPs" \u2192 search "allowedIps" \u2192 search "allowed_ips" (WRONG: case/style variations, probe handles them)',
|
|
9216
|
+
' \u2192 search "limitDRL" \u2192 search "LimitDRL" (WRONG: case variation of same term)',
|
|
9217
|
+
' \u2192 search "throttle_retry_limit" after searching "ThrottleRetryLimit" (WRONG: snake_case variation, probe handles it)',
|
|
9218
|
+
' \u2192 search "ThrottleRetryLimit" path=tyk \u2192 search "ThrottleRetryLimit" path=gateway \u2192 search "ThrottleRetryLimit" path=apidef (WRONG: same query on different paths hoping for different results)',
|
|
9219
|
+
' \u2192 search "func (k *RateLimitAndQuotaCheck) handleRateLimitFailure" (WRONG: do not search full function signatures, just use exact=true "handleRateLimitFailure")',
|
|
9220
|
+
' \u2192 search "ForwardMessage" \u2192 search "ForwardMessage" \u2192 search "ForwardMessage" (WRONG: repeating the exact same query)',
|
|
9207
9221
|
' \u2192 search "error handling" \u2192 search "error handling" \u2192 search "error handling" (WRONG: repeating exact same query)',
|
|
9208
9222
|
"",
|
|
9209
9223
|
"Keyword tips:",
|
|
@@ -9212,12 +9226,13 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
9212
9226
|
'- To bypass stopword filtering: wrap terms in quotes ("return", "struct") or set exact=true. Both disable stemming and splitting too.',
|
|
9213
9227
|
"- Multiple words without operators use OR logic: foo bar = foo OR bar. Use AND explicitly if you need both: foo AND bar.",
|
|
9214
9228
|
'- camelCase terms are split: getUserData becomes "get", "user", "data" \u2014 so one search covers all naming styles.',
|
|
9229
|
+
'- Do NOT search for full function signatures like "func (r *Type) Method(args)". Just search for the method name with exact=true.',
|
|
9215
9230
|
"",
|
|
9216
9231
|
"Strategy:",
|
|
9217
9232
|
"1. Analyze the query - identify key concepts, entities, and relationships",
|
|
9218
|
-
"2. Run ONE focused search per concept
|
|
9233
|
+
"2. Run ONE focused search per concept. For known symbol names use exact=true. For concepts use default (exact=false).",
|
|
9219
9234
|
"3. If a search returns results, use extract to verify relevance",
|
|
9220
|
-
"4.
|
|
9235
|
+
"4. If a search returns NO results, the term does not exist in the codebase. Do NOT retry with variations, different paths, or longer strings. Move on.",
|
|
9221
9236
|
"5. Combine all relevant targets in your final response",
|
|
9222
9237
|
"",
|
|
9223
9238
|
`Query: ${searchQuery}`,
|
|
@@ -9538,6 +9553,36 @@ var init_vercel = __esm({
|
|
|
9538
9553
|
} else if (targets) {
|
|
9539
9554
|
const parsedTargets = parseTargets(targets);
|
|
9540
9555
|
extractFiles = parsedTargets.map((target) => resolveTargetPath(target, effectiveCwd));
|
|
9556
|
+
if (options.allowedFolders && options.allowedFolders.length > 0) {
|
|
9557
|
+
extractFiles = extractFiles.map((target) => {
|
|
9558
|
+
const { filePart, suffix } = splitTargetSuffix(target);
|
|
9559
|
+
if (existsSync(filePart)) return target;
|
|
9560
|
+
const cwdPrefix = effectiveCwd.endsWith("/") ? effectiveCwd : effectiveCwd + "/";
|
|
9561
|
+
const relativePart = filePart.startsWith(cwdPrefix) ? filePart.slice(cwdPrefix.length) : null;
|
|
9562
|
+
if (relativePart) {
|
|
9563
|
+
for (const folder of options.allowedFolders) {
|
|
9564
|
+
const candidate = folder + "/" + relativePart;
|
|
9565
|
+
if (existsSync(candidate)) {
|
|
9566
|
+
if (debug) console.error(`[extract] Auto-fixed path: ${filePart} \u2192 ${candidate}`);
|
|
9567
|
+
return candidate + suffix;
|
|
9568
|
+
}
|
|
9569
|
+
}
|
|
9570
|
+
}
|
|
9571
|
+
for (const folder of options.allowedFolders) {
|
|
9572
|
+
const folderPrefix = folder.endsWith("/") ? folder : folder + "/";
|
|
9573
|
+
const wsParent = folderPrefix.replace(/[^/]+\/$/, "");
|
|
9574
|
+
if (filePart.startsWith(wsParent)) {
|
|
9575
|
+
const tail = filePart.slice(wsParent.length);
|
|
9576
|
+
const candidate = folderPrefix + tail;
|
|
9577
|
+
if (candidate !== filePart && existsSync(candidate)) {
|
|
9578
|
+
if (debug) console.error(`[extract] Auto-fixed path via workspace: ${filePart} \u2192 ${candidate}`);
|
|
9579
|
+
return candidate + suffix;
|
|
9580
|
+
}
|
|
9581
|
+
}
|
|
9582
|
+
}
|
|
9583
|
+
return target;
|
|
9584
|
+
});
|
|
9585
|
+
}
|
|
9541
9586
|
let effectiveFormat = format;
|
|
9542
9587
|
if (outline && format === "outline-xml") {
|
|
9543
9588
|
effectiveFormat = "xml";
|
package/build/tools/vercel.js
CHANGED
|
@@ -144,13 +144,19 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
144
144
|
'- listFiles: Understand directory structure to find where relevant code might live.',
|
|
145
145
|
'',
|
|
146
146
|
'CRITICAL - How probe search works (do NOT ignore):',
|
|
147
|
-
'- By default (exact=false), probe ALREADY handles stemming, case-insensitive matching, and camelCase/snake_case splitting.',
|
|
147
|
+
'- By default (exact=false), probe ALREADY handles stemming, case-insensitive matching, and camelCase/snake_case splitting automatically.',
|
|
148
148
|
'- Searching "allowed_ips" ALREADY matches "AllowedIPs", "allowedIps", "allowed_ips", etc. Do NOT manually try case/style variations.',
|
|
149
149
|
'- Searching "getUserData" ALREADY matches "get", "user", "data" and their variations.',
|
|
150
|
-
'- NEVER repeat the same search query — you will get the same results.',
|
|
150
|
+
'- NEVER repeat the same search query — you will get the same results. Changing the path does NOT change this.',
|
|
151
151
|
'- NEVER search trivial variations of the same keyword (e.g., AllowedIPs then allowedIps then allowed_ips). This is wasteful — probe handles it.',
|
|
152
|
-
'- If a search returns no results, the term likely does not exist
|
|
153
|
-
'- If 2-3
|
|
152
|
+
'- If a search returns no results, the term likely does not exist. Try a genuinely DIFFERENT keyword or concept, not a variation.',
|
|
153
|
+
'- If 2-3 searches return no results for a concept, STOP searching for it and move on. Do NOT keep retrying.',
|
|
154
|
+
'',
|
|
155
|
+
'When to use exact=true:',
|
|
156
|
+
'- Use exact=true when searching for a KNOWN symbol name (function, type, variable, struct).',
|
|
157
|
+
'- exact=true matches the literal string only — no stemming, no splitting.',
|
|
158
|
+
'- This is ideal for precise lookups: exact=true "ForwardMessage", exact=true "SessionLimiter", exact=true "ThrottleRetryLimit".',
|
|
159
|
+
'- Do NOT use exact=true for exploratory/conceptual queries — use the default for those.',
|
|
154
160
|
'',
|
|
155
161
|
'GOOD search strategy (do this):',
|
|
156
162
|
' Query: "How does authentication work and how are sessions managed?"',
|
|
@@ -159,10 +165,18 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
159
165
|
' → search "allowlist middleware" (one search, probe handles IP/ip/Ip variations)',
|
|
160
166
|
' Query: "How does BM25 scoring work with SIMD optimization?"',
|
|
161
167
|
' → search "BM25 scoring" → search "SIMD optimization" (two different concepts)',
|
|
168
|
+
' Query: "Find ForwardMessage and SessionLimiter functions"',
|
|
169
|
+
' → search exact=true "ForwardMessage" → search exact=true "SessionLimiter" (known symbols, use exact)',
|
|
170
|
+
' Query: "Find ThrottleRetryLimit usage"',
|
|
171
|
+
' → search exact=true "ThrottleRetryLimit" (one search, if no results the symbol does not exist — stop)',
|
|
162
172
|
'',
|
|
163
173
|
'BAD search strategy (never do this):',
|
|
164
|
-
' → search "AllowedIPs" → search "allowedIps" → search "allowed_ips" (WRONG:
|
|
165
|
-
' → search "
|
|
174
|
+
' → search "AllowedIPs" → search "allowedIps" → search "allowed_ips" (WRONG: case/style variations, probe handles them)',
|
|
175
|
+
' → search "limitDRL" → search "LimitDRL" (WRONG: case variation of same term)',
|
|
176
|
+
' → search "throttle_retry_limit" after searching "ThrottleRetryLimit" (WRONG: snake_case variation, probe handles it)',
|
|
177
|
+
' → search "ThrottleRetryLimit" path=tyk → search "ThrottleRetryLimit" path=gateway → search "ThrottleRetryLimit" path=apidef (WRONG: same query on different paths hoping for different results)',
|
|
178
|
+
' → search "func (k *RateLimitAndQuotaCheck) handleRateLimitFailure" (WRONG: do not search full function signatures, just use exact=true "handleRateLimitFailure")',
|
|
179
|
+
' → search "ForwardMessage" → search "ForwardMessage" → search "ForwardMessage" (WRONG: repeating the exact same query)',
|
|
166
180
|
' → search "error handling" → search "error handling" → search "error handling" (WRONG: repeating exact same query)',
|
|
167
181
|
'',
|
|
168
182
|
'Keyword tips:',
|
|
@@ -171,12 +185,13 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
171
185
|
'- To bypass stopword filtering: wrap terms in quotes ("return", "struct") or set exact=true. Both disable stemming and splitting too.',
|
|
172
186
|
'- Multiple words without operators use OR logic: foo bar = foo OR bar. Use AND explicitly if you need both: foo AND bar.',
|
|
173
187
|
'- camelCase terms are split: getUserData becomes "get", "user", "data" — so one search covers all naming styles.',
|
|
188
|
+
'- Do NOT search for full function signatures like "func (r *Type) Method(args)". Just search for the method name with exact=true.',
|
|
174
189
|
'',
|
|
175
190
|
'Strategy:',
|
|
176
191
|
'1. Analyze the query - identify key concepts, entities, and relationships',
|
|
177
|
-
'2. Run ONE focused search per concept
|
|
192
|
+
'2. Run ONE focused search per concept. For known symbol names use exact=true. For concepts use default (exact=false).',
|
|
178
193
|
'3. If a search returns results, use extract to verify relevance',
|
|
179
|
-
'4.
|
|
194
|
+
'4. If a search returns NO results, the term does not exist in the codebase. Do NOT retry with variations, different paths, or longer strings. Move on.',
|
|
180
195
|
'5. Combine all relevant targets in your final response',
|
|
181
196
|
'',
|
|
182
197
|
`Query: ${searchQuery}`,
|
|
@@ -570,6 +585,50 @@ export const extractTool = (options = {}) => {
|
|
|
570
585
|
// Resolve relative paths in targets against cwd
|
|
571
586
|
extractFiles = parsedTargets.map(target => resolveTargetPath(target, effectiveCwd));
|
|
572
587
|
|
|
588
|
+
// Auto-fix: if resolved paths don't exist, try allowedFolders subdirs
|
|
589
|
+
// Handles when search returns relative paths (e.g., "gateway/file.go") and
|
|
590
|
+
// model constructs wrong absolute paths (e.g., /workspace/gateway/file.go
|
|
591
|
+
// instead of /workspace/tyk/gateway/file.go)
|
|
592
|
+
if (options.allowedFolders && options.allowedFolders.length > 0) {
|
|
593
|
+
extractFiles = extractFiles.map(target => {
|
|
594
|
+
const { filePart, suffix } = splitTargetSuffix(target);
|
|
595
|
+
if (existsSync(filePart)) return target;
|
|
596
|
+
|
|
597
|
+
// Try resolving the relative tail against each allowedFolder
|
|
598
|
+
const cwdPrefix = (effectiveCwd.endsWith('/') ? effectiveCwd : effectiveCwd + '/');
|
|
599
|
+
const relativePart = filePart.startsWith(cwdPrefix)
|
|
600
|
+
? filePart.slice(cwdPrefix.length)
|
|
601
|
+
: null;
|
|
602
|
+
|
|
603
|
+
if (relativePart) {
|
|
604
|
+
for (const folder of options.allowedFolders) {
|
|
605
|
+
const candidate = folder + '/' + relativePart;
|
|
606
|
+
if (existsSync(candidate)) {
|
|
607
|
+
if (debug) console.error(`[extract] Auto-fixed path: ${filePart} → ${candidate}`);
|
|
608
|
+
return candidate + suffix;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// Try stripping workspace prefix and resolving against allowedFolders
|
|
614
|
+
// e.g., /tmp/visor-workspaces/abc/gateway/file.go → try each folder + gateway/file.go
|
|
615
|
+
for (const folder of options.allowedFolders) {
|
|
616
|
+
const folderPrefix = folder.endsWith('/') ? folder : folder + '/';
|
|
617
|
+
const wsParent = folderPrefix.replace(/[^/]+\/$/, '');
|
|
618
|
+
if (filePart.startsWith(wsParent)) {
|
|
619
|
+
const tail = filePart.slice(wsParent.length);
|
|
620
|
+
const candidate = folderPrefix + tail;
|
|
621
|
+
if (candidate !== filePart && existsSync(candidate)) {
|
|
622
|
+
if (debug) console.error(`[extract] Auto-fixed path via workspace: ${filePart} → ${candidate}`);
|
|
623
|
+
return candidate + suffix;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
return target;
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
|
|
573
632
|
// Apply format mapping for outline-xml to xml
|
|
574
633
|
let effectiveFormat = format;
|
|
575
634
|
if (outline && format === 'outline-xml') {
|
package/cjs/agent/ProbeAgent.cjs
CHANGED
|
@@ -4205,7 +4205,7 @@ var init_NormalizedSchema = __esm({
|
|
|
4205
4205
|
if (this.isDocumentSchema()) {
|
|
4206
4206
|
return member([15, 0], memberName);
|
|
4207
4207
|
}
|
|
4208
|
-
throw new Error(`@smithy/core/schema - ${this.getName(true)} has no
|
|
4208
|
+
throw new Error(`@smithy/core/schema - ${this.getName(true)} has no member=${memberName}.`);
|
|
4209
4209
|
}
|
|
4210
4210
|
getMemberSchemas() {
|
|
4211
4211
|
const buffer = {};
|
|
@@ -5996,7 +5996,7 @@ var init_EventStreamSerde = __esm({
|
|
|
5996
5996
|
throw new Error("@smithy/core/event-streams - non-struct member not supported in event stream union.");
|
|
5997
5997
|
}
|
|
5998
5998
|
}
|
|
5999
|
-
const messageSerialization = serializer.flush();
|
|
5999
|
+
const messageSerialization = serializer.flush() ?? new Uint8Array();
|
|
6000
6000
|
const body = typeof messageSerialization === "string" ? (this.serdeContext?.utf8Decoder ?? import_util_utf8.fromUtf8)(messageSerialization) : messageSerialization;
|
|
6001
6001
|
return {
|
|
6002
6002
|
body,
|
|
@@ -36563,13 +36563,19 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
36563
36563
|
"- listFiles: Understand directory structure to find where relevant code might live.",
|
|
36564
36564
|
"",
|
|
36565
36565
|
"CRITICAL - How probe search works (do NOT ignore):",
|
|
36566
|
-
"- By default (exact=false), probe ALREADY handles stemming, case-insensitive matching, and camelCase/snake_case splitting.",
|
|
36566
|
+
"- By default (exact=false), probe ALREADY handles stemming, case-insensitive matching, and camelCase/snake_case splitting automatically.",
|
|
36567
36567
|
'- Searching "allowed_ips" ALREADY matches "AllowedIPs", "allowedIps", "allowed_ips", etc. Do NOT manually try case/style variations.',
|
|
36568
36568
|
'- Searching "getUserData" ALREADY matches "get", "user", "data" and their variations.',
|
|
36569
|
-
"- NEVER repeat the same search query \u2014 you will get the same results.",
|
|
36569
|
+
"- NEVER repeat the same search query \u2014 you will get the same results. Changing the path does NOT change this.",
|
|
36570
36570
|
"- NEVER search trivial variations of the same keyword (e.g., AllowedIPs then allowedIps then allowed_ips). This is wasteful \u2014 probe handles it.",
|
|
36571
|
-
"- If a search returns no results, the term likely does not exist
|
|
36572
|
-
"- If 2-3
|
|
36571
|
+
"- If a search returns no results, the term likely does not exist. Try a genuinely DIFFERENT keyword or concept, not a variation.",
|
|
36572
|
+
"- If 2-3 searches return no results for a concept, STOP searching for it and move on. Do NOT keep retrying.",
|
|
36573
|
+
"",
|
|
36574
|
+
"When to use exact=true:",
|
|
36575
|
+
"- Use exact=true when searching for a KNOWN symbol name (function, type, variable, struct).",
|
|
36576
|
+
"- exact=true matches the literal string only \u2014 no stemming, no splitting.",
|
|
36577
|
+
'- This is ideal for precise lookups: exact=true "ForwardMessage", exact=true "SessionLimiter", exact=true "ThrottleRetryLimit".',
|
|
36578
|
+
"- Do NOT use exact=true for exploratory/conceptual queries \u2014 use the default for those.",
|
|
36573
36579
|
"",
|
|
36574
36580
|
"GOOD search strategy (do this):",
|
|
36575
36581
|
' Query: "How does authentication work and how are sessions managed?"',
|
|
@@ -36578,10 +36584,18 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
36578
36584
|
' \u2192 search "allowlist middleware" (one search, probe handles IP/ip/Ip variations)',
|
|
36579
36585
|
' Query: "How does BM25 scoring work with SIMD optimization?"',
|
|
36580
36586
|
' \u2192 search "BM25 scoring" \u2192 search "SIMD optimization" (two different concepts)',
|
|
36587
|
+
' Query: "Find ForwardMessage and SessionLimiter functions"',
|
|
36588
|
+
' \u2192 search exact=true "ForwardMessage" \u2192 search exact=true "SessionLimiter" (known symbols, use exact)',
|
|
36589
|
+
' Query: "Find ThrottleRetryLimit usage"',
|
|
36590
|
+
' \u2192 search exact=true "ThrottleRetryLimit" (one search, if no results the symbol does not exist \u2014 stop)',
|
|
36581
36591
|
"",
|
|
36582
36592
|
"BAD search strategy (never do this):",
|
|
36583
|
-
' \u2192 search "AllowedIPs" \u2192 search "allowedIps" \u2192 search "allowed_ips" (WRONG:
|
|
36584
|
-
' \u2192 search "
|
|
36593
|
+
' \u2192 search "AllowedIPs" \u2192 search "allowedIps" \u2192 search "allowed_ips" (WRONG: case/style variations, probe handles them)',
|
|
36594
|
+
' \u2192 search "limitDRL" \u2192 search "LimitDRL" (WRONG: case variation of same term)',
|
|
36595
|
+
' \u2192 search "throttle_retry_limit" after searching "ThrottleRetryLimit" (WRONG: snake_case variation, probe handles it)',
|
|
36596
|
+
' \u2192 search "ThrottleRetryLimit" path=tyk \u2192 search "ThrottleRetryLimit" path=gateway \u2192 search "ThrottleRetryLimit" path=apidef (WRONG: same query on different paths hoping for different results)',
|
|
36597
|
+
' \u2192 search "func (k *RateLimitAndQuotaCheck) handleRateLimitFailure" (WRONG: do not search full function signatures, just use exact=true "handleRateLimitFailure")',
|
|
36598
|
+
' \u2192 search "ForwardMessage" \u2192 search "ForwardMessage" \u2192 search "ForwardMessage" (WRONG: repeating the exact same query)',
|
|
36585
36599
|
' \u2192 search "error handling" \u2192 search "error handling" \u2192 search "error handling" (WRONG: repeating exact same query)',
|
|
36586
36600
|
"",
|
|
36587
36601
|
"Keyword tips:",
|
|
@@ -36590,12 +36604,13 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
36590
36604
|
'- To bypass stopword filtering: wrap terms in quotes ("return", "struct") or set exact=true. Both disable stemming and splitting too.',
|
|
36591
36605
|
"- Multiple words without operators use OR logic: foo bar = foo OR bar. Use AND explicitly if you need both: foo AND bar.",
|
|
36592
36606
|
'- camelCase terms are split: getUserData becomes "get", "user", "data" \u2014 so one search covers all naming styles.',
|
|
36607
|
+
'- Do NOT search for full function signatures like "func (r *Type) Method(args)". Just search for the method name with exact=true.',
|
|
36593
36608
|
"",
|
|
36594
36609
|
"Strategy:",
|
|
36595
36610
|
"1. Analyze the query - identify key concepts, entities, and relationships",
|
|
36596
|
-
"2. Run ONE focused search per concept
|
|
36611
|
+
"2. Run ONE focused search per concept. For known symbol names use exact=true. For concepts use default (exact=false).",
|
|
36597
36612
|
"3. If a search returns results, use extract to verify relevance",
|
|
36598
|
-
"4.
|
|
36613
|
+
"4. If a search returns NO results, the term does not exist in the codebase. Do NOT retry with variations, different paths, or longer strings. Move on.",
|
|
36599
36614
|
"5. Combine all relevant targets in your final response",
|
|
36600
36615
|
"",
|
|
36601
36616
|
`Query: ${searchQuery}`,
|
|
@@ -36918,6 +36933,36 @@ var init_vercel = __esm({
|
|
|
36918
36933
|
} else if (targets) {
|
|
36919
36934
|
const parsedTargets = parseTargets(targets);
|
|
36920
36935
|
extractFiles = parsedTargets.map((target) => resolveTargetPath(target, effectiveCwd));
|
|
36936
|
+
if (options.allowedFolders && options.allowedFolders.length > 0) {
|
|
36937
|
+
extractFiles = extractFiles.map((target) => {
|
|
36938
|
+
const { filePart, suffix } = splitTargetSuffix(target);
|
|
36939
|
+
if ((0, import_fs4.existsSync)(filePart)) return target;
|
|
36940
|
+
const cwdPrefix = effectiveCwd.endsWith("/") ? effectiveCwd : effectiveCwd + "/";
|
|
36941
|
+
const relativePart = filePart.startsWith(cwdPrefix) ? filePart.slice(cwdPrefix.length) : null;
|
|
36942
|
+
if (relativePart) {
|
|
36943
|
+
for (const folder of options.allowedFolders) {
|
|
36944
|
+
const candidate = folder + "/" + relativePart;
|
|
36945
|
+
if ((0, import_fs4.existsSync)(candidate)) {
|
|
36946
|
+
if (debug) console.error(`[extract] Auto-fixed path: ${filePart} \u2192 ${candidate}`);
|
|
36947
|
+
return candidate + suffix;
|
|
36948
|
+
}
|
|
36949
|
+
}
|
|
36950
|
+
}
|
|
36951
|
+
for (const folder of options.allowedFolders) {
|
|
36952
|
+
const folderPrefix = folder.endsWith("/") ? folder : folder + "/";
|
|
36953
|
+
const wsParent = folderPrefix.replace(/[^/]+\/$/, "");
|
|
36954
|
+
if (filePart.startsWith(wsParent)) {
|
|
36955
|
+
const tail = filePart.slice(wsParent.length);
|
|
36956
|
+
const candidate = folderPrefix + tail;
|
|
36957
|
+
if (candidate !== filePart && (0, import_fs4.existsSync)(candidate)) {
|
|
36958
|
+
if (debug) console.error(`[extract] Auto-fixed path via workspace: ${filePart} \u2192 ${candidate}`);
|
|
36959
|
+
return candidate + suffix;
|
|
36960
|
+
}
|
|
36961
|
+
}
|
|
36962
|
+
}
|
|
36963
|
+
return target;
|
|
36964
|
+
});
|
|
36965
|
+
}
|
|
36921
36966
|
let effectiveFormat = format2;
|
|
36922
36967
|
if (outline && format2 === "outline-xml") {
|
|
36923
36968
|
effectiveFormat = "xml";
|
package/cjs/index.cjs
CHANGED
|
@@ -6063,7 +6063,7 @@ var init_NormalizedSchema = __esm({
|
|
|
6063
6063
|
if (this.isDocumentSchema()) {
|
|
6064
6064
|
return member([15, 0], memberName);
|
|
6065
6065
|
}
|
|
6066
|
-
throw new Error(`@smithy/core/schema - ${this.getName(true)} has no
|
|
6066
|
+
throw new Error(`@smithy/core/schema - ${this.getName(true)} has no member=${memberName}.`);
|
|
6067
6067
|
}
|
|
6068
6068
|
getMemberSchemas() {
|
|
6069
6069
|
const buffer = {};
|
|
@@ -7854,7 +7854,7 @@ var init_EventStreamSerde = __esm({
|
|
|
7854
7854
|
throw new Error("@smithy/core/event-streams - non-struct member not supported in event stream union.");
|
|
7855
7855
|
}
|
|
7856
7856
|
}
|
|
7857
|
-
const messageSerialization = serializer.flush();
|
|
7857
|
+
const messageSerialization = serializer.flush() ?? new Uint8Array();
|
|
7858
7858
|
const body = typeof messageSerialization === "string" ? (this.serdeContext?.utf8Decoder ?? import_util_utf8.fromUtf8)(messageSerialization) : messageSerialization;
|
|
7859
7859
|
return {
|
|
7860
7860
|
body,
|
|
@@ -110725,13 +110725,19 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
110725
110725
|
"- listFiles: Understand directory structure to find where relevant code might live.",
|
|
110726
110726
|
"",
|
|
110727
110727
|
"CRITICAL - How probe search works (do NOT ignore):",
|
|
110728
|
-
"- By default (exact=false), probe ALREADY handles stemming, case-insensitive matching, and camelCase/snake_case splitting.",
|
|
110728
|
+
"- By default (exact=false), probe ALREADY handles stemming, case-insensitive matching, and camelCase/snake_case splitting automatically.",
|
|
110729
110729
|
'- Searching "allowed_ips" ALREADY matches "AllowedIPs", "allowedIps", "allowed_ips", etc. Do NOT manually try case/style variations.',
|
|
110730
110730
|
'- Searching "getUserData" ALREADY matches "get", "user", "data" and their variations.',
|
|
110731
|
-
"- NEVER repeat the same search query \u2014 you will get the same results.",
|
|
110731
|
+
"- NEVER repeat the same search query \u2014 you will get the same results. Changing the path does NOT change this.",
|
|
110732
110732
|
"- NEVER search trivial variations of the same keyword (e.g., AllowedIPs then allowedIps then allowed_ips). This is wasteful \u2014 probe handles it.",
|
|
110733
|
-
"- If a search returns no results, the term likely does not exist
|
|
110734
|
-
"- If 2-3
|
|
110733
|
+
"- If a search returns no results, the term likely does not exist. Try a genuinely DIFFERENT keyword or concept, not a variation.",
|
|
110734
|
+
"- If 2-3 searches return no results for a concept, STOP searching for it and move on. Do NOT keep retrying.",
|
|
110735
|
+
"",
|
|
110736
|
+
"When to use exact=true:",
|
|
110737
|
+
"- Use exact=true when searching for a KNOWN symbol name (function, type, variable, struct).",
|
|
110738
|
+
"- exact=true matches the literal string only \u2014 no stemming, no splitting.",
|
|
110739
|
+
'- This is ideal for precise lookups: exact=true "ForwardMessage", exact=true "SessionLimiter", exact=true "ThrottleRetryLimit".',
|
|
110740
|
+
"- Do NOT use exact=true for exploratory/conceptual queries \u2014 use the default for those.",
|
|
110735
110741
|
"",
|
|
110736
110742
|
"GOOD search strategy (do this):",
|
|
110737
110743
|
' Query: "How does authentication work and how are sessions managed?"',
|
|
@@ -110740,10 +110746,18 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
110740
110746
|
' \u2192 search "allowlist middleware" (one search, probe handles IP/ip/Ip variations)',
|
|
110741
110747
|
' Query: "How does BM25 scoring work with SIMD optimization?"',
|
|
110742
110748
|
' \u2192 search "BM25 scoring" \u2192 search "SIMD optimization" (two different concepts)',
|
|
110749
|
+
' Query: "Find ForwardMessage and SessionLimiter functions"',
|
|
110750
|
+
' \u2192 search exact=true "ForwardMessage" \u2192 search exact=true "SessionLimiter" (known symbols, use exact)',
|
|
110751
|
+
' Query: "Find ThrottleRetryLimit usage"',
|
|
110752
|
+
' \u2192 search exact=true "ThrottleRetryLimit" (one search, if no results the symbol does not exist \u2014 stop)',
|
|
110743
110753
|
"",
|
|
110744
110754
|
"BAD search strategy (never do this):",
|
|
110745
|
-
' \u2192 search "AllowedIPs" \u2192 search "allowedIps" \u2192 search "allowed_ips" (WRONG:
|
|
110746
|
-
' \u2192 search "
|
|
110755
|
+
' \u2192 search "AllowedIPs" \u2192 search "allowedIps" \u2192 search "allowed_ips" (WRONG: case/style variations, probe handles them)',
|
|
110756
|
+
' \u2192 search "limitDRL" \u2192 search "LimitDRL" (WRONG: case variation of same term)',
|
|
110757
|
+
' \u2192 search "throttle_retry_limit" after searching "ThrottleRetryLimit" (WRONG: snake_case variation, probe handles it)',
|
|
110758
|
+
' \u2192 search "ThrottleRetryLimit" path=tyk \u2192 search "ThrottleRetryLimit" path=gateway \u2192 search "ThrottleRetryLimit" path=apidef (WRONG: same query on different paths hoping for different results)',
|
|
110759
|
+
' \u2192 search "func (k *RateLimitAndQuotaCheck) handleRateLimitFailure" (WRONG: do not search full function signatures, just use exact=true "handleRateLimitFailure")',
|
|
110760
|
+
' \u2192 search "ForwardMessage" \u2192 search "ForwardMessage" \u2192 search "ForwardMessage" (WRONG: repeating the exact same query)',
|
|
110747
110761
|
' \u2192 search "error handling" \u2192 search "error handling" \u2192 search "error handling" (WRONG: repeating exact same query)',
|
|
110748
110762
|
"",
|
|
110749
110763
|
"Keyword tips:",
|
|
@@ -110752,12 +110766,13 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
110752
110766
|
'- To bypass stopword filtering: wrap terms in quotes ("return", "struct") or set exact=true. Both disable stemming and splitting too.',
|
|
110753
110767
|
"- Multiple words without operators use OR logic: foo bar = foo OR bar. Use AND explicitly if you need both: foo AND bar.",
|
|
110754
110768
|
'- camelCase terms are split: getUserData becomes "get", "user", "data" \u2014 so one search covers all naming styles.',
|
|
110769
|
+
'- Do NOT search for full function signatures like "func (r *Type) Method(args)". Just search for the method name with exact=true.',
|
|
110755
110770
|
"",
|
|
110756
110771
|
"Strategy:",
|
|
110757
110772
|
"1. Analyze the query - identify key concepts, entities, and relationships",
|
|
110758
|
-
"2. Run ONE focused search per concept
|
|
110773
|
+
"2. Run ONE focused search per concept. For known symbol names use exact=true. For concepts use default (exact=false).",
|
|
110759
110774
|
"3. If a search returns results, use extract to verify relevance",
|
|
110760
|
-
"4.
|
|
110775
|
+
"4. If a search returns NO results, the term does not exist in the codebase. Do NOT retry with variations, different paths, or longer strings. Move on.",
|
|
110761
110776
|
"5. Combine all relevant targets in your final response",
|
|
110762
110777
|
"",
|
|
110763
110778
|
`Query: ${searchQuery}`,
|
|
@@ -111080,6 +111095,36 @@ var init_vercel = __esm({
|
|
|
111080
111095
|
} else if (targets) {
|
|
111081
111096
|
const parsedTargets = parseTargets(targets);
|
|
111082
111097
|
extractFiles = parsedTargets.map((target) => resolveTargetPath(target, effectiveCwd));
|
|
111098
|
+
if (options.allowedFolders && options.allowedFolders.length > 0) {
|
|
111099
|
+
extractFiles = extractFiles.map((target) => {
|
|
111100
|
+
const { filePart, suffix } = splitTargetSuffix(target);
|
|
111101
|
+
if ((0, import_fs11.existsSync)(filePart)) return target;
|
|
111102
|
+
const cwdPrefix = effectiveCwd.endsWith("/") ? effectiveCwd : effectiveCwd + "/";
|
|
111103
|
+
const relativePart = filePart.startsWith(cwdPrefix) ? filePart.slice(cwdPrefix.length) : null;
|
|
111104
|
+
if (relativePart) {
|
|
111105
|
+
for (const folder of options.allowedFolders) {
|
|
111106
|
+
const candidate = folder + "/" + relativePart;
|
|
111107
|
+
if ((0, import_fs11.existsSync)(candidate)) {
|
|
111108
|
+
if (debug) console.error(`[extract] Auto-fixed path: ${filePart} \u2192 ${candidate}`);
|
|
111109
|
+
return candidate + suffix;
|
|
111110
|
+
}
|
|
111111
|
+
}
|
|
111112
|
+
}
|
|
111113
|
+
for (const folder of options.allowedFolders) {
|
|
111114
|
+
const folderPrefix = folder.endsWith("/") ? folder : folder + "/";
|
|
111115
|
+
const wsParent = folderPrefix.replace(/[^/]+\/$/, "");
|
|
111116
|
+
if (filePart.startsWith(wsParent)) {
|
|
111117
|
+
const tail = filePart.slice(wsParent.length);
|
|
111118
|
+
const candidate = folderPrefix + tail;
|
|
111119
|
+
if (candidate !== filePart && (0, import_fs11.existsSync)(candidate)) {
|
|
111120
|
+
if (debug) console.error(`[extract] Auto-fixed path via workspace: ${filePart} \u2192 ${candidate}`);
|
|
111121
|
+
return candidate + suffix;
|
|
111122
|
+
}
|
|
111123
|
+
}
|
|
111124
|
+
}
|
|
111125
|
+
return target;
|
|
111126
|
+
});
|
|
111127
|
+
}
|
|
111083
111128
|
let effectiveFormat = format2;
|
|
111084
111129
|
if (outline && format2 === "outline-xml") {
|
|
111085
111130
|
effectiveFormat = "xml";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@probelabs/probe",
|
|
3
|
-
"version": "0.6.0-
|
|
3
|
+
"version": "0.6.0-rc282",
|
|
4
4
|
"description": "Node.js wrapper for the probe code search tool",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"module": "src/index.js",
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"dependencies": {
|
|
76
76
|
"@ai-sdk/amazon-bedrock": "^1.0.8",
|
|
77
77
|
"@ai-sdk/anthropic": "^2.0.8",
|
|
78
|
-
"@ai-sdk/google": "^
|
|
78
|
+
"@ai-sdk/google": "^3.0.37",
|
|
79
79
|
"@ai-sdk/openai": "^2.0.10",
|
|
80
80
|
"@anthropic-ai/claude-agent-sdk": "^0.1.46",
|
|
81
81
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
package/src/tools/vercel.js
CHANGED
|
@@ -144,13 +144,19 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
144
144
|
'- listFiles: Understand directory structure to find where relevant code might live.',
|
|
145
145
|
'',
|
|
146
146
|
'CRITICAL - How probe search works (do NOT ignore):',
|
|
147
|
-
'- By default (exact=false), probe ALREADY handles stemming, case-insensitive matching, and camelCase/snake_case splitting.',
|
|
147
|
+
'- By default (exact=false), probe ALREADY handles stemming, case-insensitive matching, and camelCase/snake_case splitting automatically.',
|
|
148
148
|
'- Searching "allowed_ips" ALREADY matches "AllowedIPs", "allowedIps", "allowed_ips", etc. Do NOT manually try case/style variations.',
|
|
149
149
|
'- Searching "getUserData" ALREADY matches "get", "user", "data" and their variations.',
|
|
150
|
-
'- NEVER repeat the same search query — you will get the same results.',
|
|
150
|
+
'- NEVER repeat the same search query — you will get the same results. Changing the path does NOT change this.',
|
|
151
151
|
'- NEVER search trivial variations of the same keyword (e.g., AllowedIPs then allowedIps then allowed_ips). This is wasteful — probe handles it.',
|
|
152
|
-
'- If a search returns no results, the term likely does not exist
|
|
153
|
-
'- If 2-3
|
|
152
|
+
'- If a search returns no results, the term likely does not exist. Try a genuinely DIFFERENT keyword or concept, not a variation.',
|
|
153
|
+
'- If 2-3 searches return no results for a concept, STOP searching for it and move on. Do NOT keep retrying.',
|
|
154
|
+
'',
|
|
155
|
+
'When to use exact=true:',
|
|
156
|
+
'- Use exact=true when searching for a KNOWN symbol name (function, type, variable, struct).',
|
|
157
|
+
'- exact=true matches the literal string only — no stemming, no splitting.',
|
|
158
|
+
'- This is ideal for precise lookups: exact=true "ForwardMessage", exact=true "SessionLimiter", exact=true "ThrottleRetryLimit".',
|
|
159
|
+
'- Do NOT use exact=true for exploratory/conceptual queries — use the default for those.',
|
|
154
160
|
'',
|
|
155
161
|
'GOOD search strategy (do this):',
|
|
156
162
|
' Query: "How does authentication work and how are sessions managed?"',
|
|
@@ -159,10 +165,18 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
159
165
|
' → search "allowlist middleware" (one search, probe handles IP/ip/Ip variations)',
|
|
160
166
|
' Query: "How does BM25 scoring work with SIMD optimization?"',
|
|
161
167
|
' → search "BM25 scoring" → search "SIMD optimization" (two different concepts)',
|
|
168
|
+
' Query: "Find ForwardMessage and SessionLimiter functions"',
|
|
169
|
+
' → search exact=true "ForwardMessage" → search exact=true "SessionLimiter" (known symbols, use exact)',
|
|
170
|
+
' Query: "Find ThrottleRetryLimit usage"',
|
|
171
|
+
' → search exact=true "ThrottleRetryLimit" (one search, if no results the symbol does not exist — stop)',
|
|
162
172
|
'',
|
|
163
173
|
'BAD search strategy (never do this):',
|
|
164
|
-
' → search "AllowedIPs" → search "allowedIps" → search "allowed_ips" (WRONG:
|
|
165
|
-
' → search "
|
|
174
|
+
' → search "AllowedIPs" → search "allowedIps" → search "allowed_ips" (WRONG: case/style variations, probe handles them)',
|
|
175
|
+
' → search "limitDRL" → search "LimitDRL" (WRONG: case variation of same term)',
|
|
176
|
+
' → search "throttle_retry_limit" after searching "ThrottleRetryLimit" (WRONG: snake_case variation, probe handles it)',
|
|
177
|
+
' → search "ThrottleRetryLimit" path=tyk → search "ThrottleRetryLimit" path=gateway → search "ThrottleRetryLimit" path=apidef (WRONG: same query on different paths hoping for different results)',
|
|
178
|
+
' → search "func (k *RateLimitAndQuotaCheck) handleRateLimitFailure" (WRONG: do not search full function signatures, just use exact=true "handleRateLimitFailure")',
|
|
179
|
+
' → search "ForwardMessage" → search "ForwardMessage" → search "ForwardMessage" (WRONG: repeating the exact same query)',
|
|
166
180
|
' → search "error handling" → search "error handling" → search "error handling" (WRONG: repeating exact same query)',
|
|
167
181
|
'',
|
|
168
182
|
'Keyword tips:',
|
|
@@ -171,12 +185,13 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
171
185
|
'- To bypass stopword filtering: wrap terms in quotes ("return", "struct") or set exact=true. Both disable stemming and splitting too.',
|
|
172
186
|
'- Multiple words without operators use OR logic: foo bar = foo OR bar. Use AND explicitly if you need both: foo AND bar.',
|
|
173
187
|
'- camelCase terms are split: getUserData becomes "get", "user", "data" — so one search covers all naming styles.',
|
|
188
|
+
'- Do NOT search for full function signatures like "func (r *Type) Method(args)". Just search for the method name with exact=true.',
|
|
174
189
|
'',
|
|
175
190
|
'Strategy:',
|
|
176
191
|
'1. Analyze the query - identify key concepts, entities, and relationships',
|
|
177
|
-
'2. Run ONE focused search per concept
|
|
192
|
+
'2. Run ONE focused search per concept. For known symbol names use exact=true. For concepts use default (exact=false).',
|
|
178
193
|
'3. If a search returns results, use extract to verify relevance',
|
|
179
|
-
'4.
|
|
194
|
+
'4. If a search returns NO results, the term does not exist in the codebase. Do NOT retry with variations, different paths, or longer strings. Move on.',
|
|
180
195
|
'5. Combine all relevant targets in your final response',
|
|
181
196
|
'',
|
|
182
197
|
`Query: ${searchQuery}`,
|
|
@@ -570,6 +585,50 @@ export const extractTool = (options = {}) => {
|
|
|
570
585
|
// Resolve relative paths in targets against cwd
|
|
571
586
|
extractFiles = parsedTargets.map(target => resolveTargetPath(target, effectiveCwd));
|
|
572
587
|
|
|
588
|
+
// Auto-fix: if resolved paths don't exist, try allowedFolders subdirs
|
|
589
|
+
// Handles when search returns relative paths (e.g., "gateway/file.go") and
|
|
590
|
+
// model constructs wrong absolute paths (e.g., /workspace/gateway/file.go
|
|
591
|
+
// instead of /workspace/tyk/gateway/file.go)
|
|
592
|
+
if (options.allowedFolders && options.allowedFolders.length > 0) {
|
|
593
|
+
extractFiles = extractFiles.map(target => {
|
|
594
|
+
const { filePart, suffix } = splitTargetSuffix(target);
|
|
595
|
+
if (existsSync(filePart)) return target;
|
|
596
|
+
|
|
597
|
+
// Try resolving the relative tail against each allowedFolder
|
|
598
|
+
const cwdPrefix = (effectiveCwd.endsWith('/') ? effectiveCwd : effectiveCwd + '/');
|
|
599
|
+
const relativePart = filePart.startsWith(cwdPrefix)
|
|
600
|
+
? filePart.slice(cwdPrefix.length)
|
|
601
|
+
: null;
|
|
602
|
+
|
|
603
|
+
if (relativePart) {
|
|
604
|
+
for (const folder of options.allowedFolders) {
|
|
605
|
+
const candidate = folder + '/' + relativePart;
|
|
606
|
+
if (existsSync(candidate)) {
|
|
607
|
+
if (debug) console.error(`[extract] Auto-fixed path: ${filePart} → ${candidate}`);
|
|
608
|
+
return candidate + suffix;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// Try stripping workspace prefix and resolving against allowedFolders
|
|
614
|
+
// e.g., /tmp/visor-workspaces/abc/gateway/file.go → try each folder + gateway/file.go
|
|
615
|
+
for (const folder of options.allowedFolders) {
|
|
616
|
+
const folderPrefix = folder.endsWith('/') ? folder : folder + '/';
|
|
617
|
+
const wsParent = folderPrefix.replace(/[^/]+\/$/, '');
|
|
618
|
+
if (filePart.startsWith(wsParent)) {
|
|
619
|
+
const tail = filePart.slice(wsParent.length);
|
|
620
|
+
const candidate = folderPrefix + tail;
|
|
621
|
+
if (candidate !== filePart && existsSync(candidate)) {
|
|
622
|
+
if (debug) console.error(`[extract] Auto-fixed path via workspace: ${filePart} → ${candidate}`);
|
|
623
|
+
return candidate + suffix;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
return target;
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
|
|
573
632
|
// Apply format mapping for outline-xml to xml
|
|
574
633
|
let effectiveFormat = format;
|
|
575
634
|
if (outline && format === 'outline-xml') {
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|