@probelabs/probe 0.6.0-rc285 → 0.6.0-rc287
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-rc287-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc287-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc287-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc287-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc287-x86_64-unknown-linux-musl.tar.gz +0 -0
- package/build/agent/ProbeAgent.js +20 -3
- package/build/agent/index.js +151 -32
- package/build/downloader.js +5 -1
- package/build/tools/common.js +11 -1
- package/build/tools/vercel.js +38 -7
- package/cjs/agent/ProbeAgent.cjs +151 -32
- package/cjs/index.cjs +151 -32
- package/package.json +3 -3
- package/src/agent/ProbeAgent.js +20 -3
- package/src/downloader.js +5 -1
- package/src/tools/common.js +11 -1
- package/src/tools/vercel.js +38 -7
- package/bin/binaries/probe-v0.6.0-rc285-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc285-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc285-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc285-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc285-x86_64-unknown-linux-musl.tar.gz +0 -0
package/cjs/index.cjs
CHANGED
|
@@ -1098,7 +1098,11 @@ async function extractBinary(assetPath, outputDir) {
|
|
|
1098
1098
|
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
1099
1099
|
console.log(`Extracting zip to ${extractDir}...`);
|
|
1100
1100
|
}
|
|
1101
|
-
|
|
1101
|
+
if (isWindows) {
|
|
1102
|
+
await exec(`powershell -NoProfile -Command "Expand-Archive -Path '${assetPath}' -DestinationPath '${extractDir}' -Force"`);
|
|
1103
|
+
} else {
|
|
1104
|
+
await exec(`unzip -q "${assetPath}" -d "${extractDir}"`);
|
|
1105
|
+
}
|
|
1102
1106
|
} else {
|
|
1103
1107
|
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
1104
1108
|
console.log(`Copying binary directly to ${binaryPath}`);
|
|
@@ -27053,7 +27057,14 @@ function parseTargets(targets) {
|
|
|
27053
27057
|
}
|
|
27054
27058
|
function parseAndResolvePaths(pathStr, cwd) {
|
|
27055
27059
|
if (!pathStr) return [];
|
|
27056
|
-
|
|
27060
|
+
let paths = pathStr.split(",").map((p) => p.trim()).filter((p) => p.length > 0);
|
|
27061
|
+
paths = paths.flatMap((p) => {
|
|
27062
|
+
if (!/\s/.test(p)) return [p];
|
|
27063
|
+
const parts = p.split(/\s+/).filter(Boolean);
|
|
27064
|
+
if (parts.length <= 1) return [p];
|
|
27065
|
+
const allLookLikePaths = parts.every((part) => /[/\\]/.test(part) || /\.\w+/.test(part));
|
|
27066
|
+
return allLookLikePaths ? parts : [p];
|
|
27067
|
+
});
|
|
27057
27068
|
return paths.map((p) => {
|
|
27058
27069
|
if ((0, import_path5.isAbsolute)(p)) {
|
|
27059
27070
|
return p;
|
|
@@ -46716,6 +46727,7 @@ var init_parser2 = __esm({
|
|
|
46716
46727
|
{ ALT: () => this.CONSUME(Identifier) },
|
|
46717
46728
|
{ ALT: () => this.CONSUME(Text) },
|
|
46718
46729
|
{ ALT: () => this.CONSUME(NumberLiteral) },
|
|
46730
|
+
{ ALT: () => this.CONSUME(ColorValue) },
|
|
46719
46731
|
// Note: RoundOpen and RoundClose (parentheses) are NOT allowed in unquoted labels
|
|
46720
46732
|
// to match Mermaid's behavior - use quoted labels like ["text (with parens)"] instead
|
|
46721
46733
|
// Allow HTML-like tags (e.g., <br/>) inside labels
|
|
@@ -46807,6 +46819,7 @@ var init_parser2 = __esm({
|
|
|
46807
46819
|
{ ALT: () => this.CONSUME(Identifier) },
|
|
46808
46820
|
{ ALT: () => this.CONSUME(Text) },
|
|
46809
46821
|
{ ALT: () => this.CONSUME(NumberLiteral) },
|
|
46822
|
+
{ ALT: () => this.CONSUME(ColorValue) },
|
|
46810
46823
|
// Allow HTML-like angle brackets and slashes for <br/>, <i>, etc.
|
|
46811
46824
|
{ ALT: () => this.CONSUME(AngleLess) },
|
|
46812
46825
|
{ ALT: () => this.CONSUME(AngleOpen) },
|
|
@@ -47982,13 +47995,24 @@ function mapFlowchartParserError(err, text) {
|
|
|
47982
47995
|
length: len
|
|
47983
47996
|
};
|
|
47984
47997
|
}
|
|
47985
|
-
if (tokType === "QuotedString" || tokType === "SquareOpen" || tokType === "SquareClose") {
|
|
47998
|
+
if (tokType === "QuotedString" || tokType === "SquareOpen" || tokType === "SquareClose" || tokType === "DiamondOpen" || tokType === "DiamondClose") {
|
|
47986
47999
|
const context = err?.context;
|
|
47987
48000
|
const inLinkRule = context?.ruleStack?.includes("linkTextInline") || context?.ruleStack?.includes("link") || false;
|
|
47988
48001
|
const lineContent = allLines[Math.max(0, line - 1)] || "";
|
|
47989
48002
|
const beforeQuote = lineContent.slice(0, Math.max(0, column - 1));
|
|
47990
48003
|
const hasLinkBefore = beforeQuote.match(/--\s*$|==\s*$|-\.\s*$|-\.-\s*$|\[\s*$/);
|
|
47991
48004
|
if (inLinkRule || hasLinkBefore) {
|
|
48005
|
+
if (tokType === "DiamondOpen" || tokType === "DiamondClose") {
|
|
48006
|
+
return {
|
|
48007
|
+
line,
|
|
48008
|
+
column,
|
|
48009
|
+
severity: "error",
|
|
48010
|
+
code: "FL-EDGE-LABEL-CURLY-IN-PIPES",
|
|
48011
|
+
message: "Curly braces { } are not supported inside pipe-delimited edge labels.",
|
|
48012
|
+
hint: "Use HTML entities { and } inside |...|, e.g., --|Resolve ${VAR}|-->",
|
|
48013
|
+
length: len
|
|
48014
|
+
};
|
|
48015
|
+
}
|
|
47992
48016
|
if (tokType === "SquareOpen" || tokType === "SquareClose") {
|
|
47993
48017
|
return {
|
|
47994
48018
|
line,
|
|
@@ -48050,6 +48074,17 @@ function mapFlowchartParserError(err, text) {
|
|
|
48050
48074
|
length: len
|
|
48051
48075
|
};
|
|
48052
48076
|
}
|
|
48077
|
+
if (tokType === "DiamondOpen" || tokType === "DiamondClose") {
|
|
48078
|
+
return {
|
|
48079
|
+
line,
|
|
48080
|
+
column,
|
|
48081
|
+
severity: "error",
|
|
48082
|
+
code: "FL-LABEL-CURLY-IN-UNQUOTED",
|
|
48083
|
+
message: "Curly braces are not supported inside unquoted node labels.",
|
|
48084
|
+
hint: "Use { and } for literal braces, e.g., C[Substitute {params}].",
|
|
48085
|
+
length: len
|
|
48086
|
+
};
|
|
48087
|
+
}
|
|
48053
48088
|
{
|
|
48054
48089
|
const caret0 = Math.max(0, column - 1);
|
|
48055
48090
|
const openIdx = lineStr.lastIndexOf("[", caret0);
|
|
@@ -48091,9 +48126,20 @@ function mapFlowchartParserError(err, text) {
|
|
|
48091
48126
|
length: len
|
|
48092
48127
|
};
|
|
48093
48128
|
}
|
|
48129
|
+
if (seg.includes("{") || seg.includes("}")) {
|
|
48130
|
+
return {
|
|
48131
|
+
line,
|
|
48132
|
+
column,
|
|
48133
|
+
severity: "error",
|
|
48134
|
+
code: "FL-LABEL-CURLY-IN-UNQUOTED",
|
|
48135
|
+
message: "Curly braces are not supported inside unquoted node labels.",
|
|
48136
|
+
hint: "Use { and } for literal braces, e.g., C[Substitute {params}].",
|
|
48137
|
+
length: len
|
|
48138
|
+
};
|
|
48139
|
+
}
|
|
48094
48140
|
}
|
|
48095
48141
|
}
|
|
48096
|
-
if (tokType === "QuotedString"
|
|
48142
|
+
if (tokType === "QuotedString") {
|
|
48097
48143
|
return {
|
|
48098
48144
|
line,
|
|
48099
48145
|
column,
|
|
@@ -48104,6 +48150,17 @@ function mapFlowchartParserError(err, text) {
|
|
|
48104
48150
|
length: len
|
|
48105
48151
|
};
|
|
48106
48152
|
}
|
|
48153
|
+
if (tokType === "SquareOpen" || tokType === "SquareClose") {
|
|
48154
|
+
return {
|
|
48155
|
+
line,
|
|
48156
|
+
column,
|
|
48157
|
+
severity: "error",
|
|
48158
|
+
code: "FL-LABEL-BRACKET-IN-UNQUOTED",
|
|
48159
|
+
message: "Square brackets are not supported inside unquoted node labels.",
|
|
48160
|
+
hint: 'Use [ and ] for literal brackets or wrap the label in quotes, e.g., C["bind_paths[]"]',
|
|
48161
|
+
length: len
|
|
48162
|
+
};
|
|
48163
|
+
}
|
|
48107
48164
|
const q = findInnerQuoteIssue("[");
|
|
48108
48165
|
if (q?.kind === "escaped") {
|
|
48109
48166
|
return { line, column: q.column, severity: "error", code: "FL-LABEL-ESCAPED-QUOTE", message: 'Escaped quotes (\\") in node labels are not supported by Mermaid. Use " instead.', hint: 'Prefer "He said "Hi"".', length: 2 };
|
|
@@ -48114,7 +48171,7 @@ function mapFlowchartParserError(err, text) {
|
|
|
48114
48171
|
return { line, column, severity: "error", code: "FL-NODE-UNCLOSED-BRACKET", message: "Unclosed '['. Add a matching ']' before the arrow or newline.", hint: "Example: A[Label] --> B", length: 1 };
|
|
48115
48172
|
}
|
|
48116
48173
|
if (expecting(err, "RoundClose")) {
|
|
48117
|
-
if (tokType === "QuotedString"
|
|
48174
|
+
if (tokType === "QuotedString") {
|
|
48118
48175
|
return {
|
|
48119
48176
|
line,
|
|
48120
48177
|
column,
|
|
@@ -48125,6 +48182,17 @@ function mapFlowchartParserError(err, text) {
|
|
|
48125
48182
|
length: len
|
|
48126
48183
|
};
|
|
48127
48184
|
}
|
|
48185
|
+
if (tokType === "SquareOpen" || tokType === "SquareClose") {
|
|
48186
|
+
return {
|
|
48187
|
+
line,
|
|
48188
|
+
column,
|
|
48189
|
+
severity: "error",
|
|
48190
|
+
code: "FL-LABEL-BRACKET-IN-UNQUOTED",
|
|
48191
|
+
message: "Square brackets are not supported inside unquoted node labels.",
|
|
48192
|
+
hint: 'Use [ and ] for literal brackets or wrap the label in quotes, e.g., C["bind_paths[]"]',
|
|
48193
|
+
length: len
|
|
48194
|
+
};
|
|
48195
|
+
}
|
|
48128
48196
|
{
|
|
48129
48197
|
const caret0 = Math.max(0, column - 1);
|
|
48130
48198
|
const openIdx = lineStr.lastIndexOf("(", caret0);
|
|
@@ -48153,7 +48221,7 @@ function mapFlowchartParserError(err, text) {
|
|
|
48153
48221
|
return { line, column, severity: "error", code: "FL-NODE-UNCLOSED-BRACKET", message: "Unclosed '('. Add a matching ')'.", hint: "Example: B(Label)", length: 1 };
|
|
48154
48222
|
}
|
|
48155
48223
|
if (expecting(err, "DiamondClose")) {
|
|
48156
|
-
if (tokType === "QuotedString"
|
|
48224
|
+
if (tokType === "QuotedString") {
|
|
48157
48225
|
return {
|
|
48158
48226
|
line,
|
|
48159
48227
|
column,
|
|
@@ -48164,6 +48232,17 @@ function mapFlowchartParserError(err, text) {
|
|
|
48164
48232
|
length: len
|
|
48165
48233
|
};
|
|
48166
48234
|
}
|
|
48235
|
+
if (tokType === "SquareOpen" || tokType === "SquareClose") {
|
|
48236
|
+
return {
|
|
48237
|
+
line,
|
|
48238
|
+
column,
|
|
48239
|
+
severity: "error",
|
|
48240
|
+
code: "FL-LABEL-BRACKET-IN-UNQUOTED",
|
|
48241
|
+
message: "Square brackets are not supported inside unquoted node labels.",
|
|
48242
|
+
hint: 'Use [ and ] for literal brackets or wrap the label in quotes, e.g., C["bind_paths[]"]',
|
|
48243
|
+
length: len
|
|
48244
|
+
};
|
|
48245
|
+
}
|
|
48167
48246
|
{
|
|
48168
48247
|
const caret0 = Math.max(0, column - 1);
|
|
48169
48248
|
const openIdx = lineStr.lastIndexOf("{", caret0);
|
|
@@ -49006,7 +49085,7 @@ function validateFlowchart(text, options = {}) {
|
|
|
49006
49085
|
const byLine = /* @__PURE__ */ new Map();
|
|
49007
49086
|
const collect = (arr) => {
|
|
49008
49087
|
for (const e of arr || []) {
|
|
49009
|
-
if (e && (e.code === "FL-LABEL-PARENS-UNQUOTED" || e.code === "FL-LABEL-AT-IN-UNQUOTED" || e.code === "FL-LABEL-QUOTE-IN-UNQUOTED" || e.code === "FL-LABEL-SLASH-UNQUOTED")) {
|
|
49088
|
+
if (e && (e.code === "FL-LABEL-PARENS-UNQUOTED" || e.code === "FL-LABEL-AT-IN-UNQUOTED" || e.code === "FL-LABEL-QUOTE-IN-UNQUOTED" || e.code === "FL-LABEL-SLASH-UNQUOTED" || e.code === "FL-LABEL-CURLY-IN-UNQUOTED" || e.code === "FL-LABEL-BRACKET-IN-UNQUOTED")) {
|
|
49010
49089
|
const ln = e.line ?? 0;
|
|
49011
49090
|
const col = e.column ?? 1;
|
|
49012
49091
|
const list = byLine.get(ln) || [];
|
|
@@ -49088,6 +49167,9 @@ function validateFlowchart(text, options = {}) {
|
|
|
49088
49167
|
const hasParens = seg.includes("(") || seg.includes(")");
|
|
49089
49168
|
const hasAt = seg.includes("@");
|
|
49090
49169
|
const hasQuote = seg.includes('"');
|
|
49170
|
+
const hasCurly = seg.includes("{") || seg.includes("}");
|
|
49171
|
+
const hasBracket = seg.includes("[") || seg.includes("]");
|
|
49172
|
+
const isDoubleSquare = raw.slice(i, i + 2) === "[[" && raw.slice(j - 2, j) === "]]";
|
|
49091
49173
|
const isSingleQuoted = /^'[^]*'$/.test(trimmed);
|
|
49092
49174
|
const hasLeadingSlash = lsp === "/" || lsp === "\\";
|
|
49093
49175
|
if (!covered && !isQuoted && !isParenWrapped && hasParens) {
|
|
@@ -49105,6 +49187,16 @@ function validateFlowchart(text, options = {}) {
|
|
|
49105
49187
|
existing.push({ start: startCol, end: endCol });
|
|
49106
49188
|
byLine.set(ln, existing);
|
|
49107
49189
|
}
|
|
49190
|
+
if (!covered && !isQuoted && !isSlashPair && hasCurly) {
|
|
49191
|
+
errs.push({ line: ln, column: startCol, severity: "error", code: "FL-LABEL-CURLY-IN-UNQUOTED", message: "Curly braces are not supported inside unquoted node labels.", hint: "Use { and } for literal braces, e.g., C[Substitute {params}]." });
|
|
49192
|
+
existing.push({ start: startCol, end: endCol });
|
|
49193
|
+
byLine.set(ln, existing);
|
|
49194
|
+
}
|
|
49195
|
+
if (!covered && !isQuoted && !isSlashPair && !isDoubleSquare && hasBracket) {
|
|
49196
|
+
errs.push({ line: ln, column: startCol, severity: "error", code: "FL-LABEL-BRACKET-IN-UNQUOTED", message: "Square brackets are not supported inside unquoted node labels.", hint: 'Use [ and ] for literal brackets or wrap the label in quotes, e.g., C["bind_paths[]"]' });
|
|
49197
|
+
existing.push({ start: startCol, end: endCol });
|
|
49198
|
+
byLine.set(ln, existing);
|
|
49199
|
+
}
|
|
49108
49200
|
if (!covered && !isQuoted && !isSlashPair && hasQuote && !isSingleQuoted) {
|
|
49109
49201
|
errs.push({ line: ln, column: startCol, severity: "error", code: "FL-LABEL-QUOTE-IN-UNQUOTED", message: "Quotes are not allowed inside unquoted node labels. Use " for quotes or wrap the entire label in quotes.", hint: 'Example: C["HTML Output: data-trigger-visibility="true""]' });
|
|
49110
49202
|
existing.push({ start: startCol, end: endCol });
|
|
@@ -51465,7 +51557,7 @@ function computeFixes(text, errors, level = "safe") {
|
|
|
51465
51557
|
}
|
|
51466
51558
|
continue;
|
|
51467
51559
|
}
|
|
51468
|
-
if (is("FL-EDGE-LABEL-BRACKET", e)) {
|
|
51560
|
+
if (is("FL-EDGE-LABEL-BRACKET", e) || is("FL-EDGE-LABEL-CURLY-IN-PIPES", e)) {
|
|
51469
51561
|
const lineText = lineTextAt(text, e.line);
|
|
51470
51562
|
const firstBar = lineText.indexOf("|");
|
|
51471
51563
|
const secondBar = firstBar >= 0 ? lineText.indexOf("|", firstBar + 1) : -1;
|
|
@@ -51473,7 +51565,8 @@ function computeFixes(text, errors, level = "safe") {
|
|
|
51473
51565
|
const before = lineText.slice(0, firstBar + 1);
|
|
51474
51566
|
const label = lineText.slice(firstBar + 1, secondBar);
|
|
51475
51567
|
const after = lineText.slice(secondBar);
|
|
51476
|
-
|
|
51568
|
+
let fixedLabel = label.replace(/\[/g, "[").replace(/\]/g, "]");
|
|
51569
|
+
fixedLabel = fixedLabel.replace(/\{/g, "{").replace(/\}/g, "}");
|
|
51477
51570
|
const fixedLine = before + fixedLabel + after;
|
|
51478
51571
|
const finalLine = fixedLine.replace(/\[([^\]]*)\]/g, (m, seg) => "[" + String(seg).replace(/`/g, "") + "]");
|
|
51479
51572
|
edits.push({ start: { line: e.line, column: 1 }, end: { line: e.line, column: lineText.length + 1 }, newText: finalLine });
|
|
@@ -52113,7 +52206,7 @@ function computeFixes(text, errors, level = "safe") {
|
|
|
52113
52206
|
}
|
|
52114
52207
|
continue;
|
|
52115
52208
|
}
|
|
52116
|
-
if (is("FL-LABEL-PARENS-UNQUOTED", e) || is("FL-LABEL-AT-IN-UNQUOTED", e) || is("FL-LABEL-SLASH-UNQUOTED", e)) {
|
|
52209
|
+
if (is("FL-LABEL-PARENS-UNQUOTED", e) || is("FL-LABEL-AT-IN-UNQUOTED", e) || is("FL-LABEL-SLASH-UNQUOTED", e) || is("FL-LABEL-CURLY-IN-UNQUOTED", e) || is("FL-LABEL-BRACKET-IN-UNQUOTED", e)) {
|
|
52117
52210
|
if (level === "safe" || level === "all") {
|
|
52118
52211
|
if (patchedLines.has(e.line))
|
|
52119
52212
|
continue;
|
|
@@ -52154,7 +52247,7 @@ function computeFixes(text, errors, level = "safe") {
|
|
|
52154
52247
|
if (openIdx === -1)
|
|
52155
52248
|
break;
|
|
52156
52249
|
const contentStart = openIdx + shape.open.length;
|
|
52157
|
-
const closeIdx = shape.open === "(" && shape.close === ")" ? findMatchingCloser(lineText, openIdx, shape.open, shape.close) : lineText.indexOf(shape.close, contentStart);
|
|
52250
|
+
const closeIdx = shape.open === "(" && shape.close === ")" || shape.open === "[" && shape.close === "]" ? findMatchingCloser(lineText, openIdx, shape.open, shape.close) : lineText.indexOf(shape.close, contentStart);
|
|
52158
52251
|
if (closeIdx === -1)
|
|
52159
52252
|
break;
|
|
52160
52253
|
if (openIdx <= caret0 && caret0 < closeIdx) {
|
|
@@ -52174,11 +52267,21 @@ function computeFixes(text, errors, level = "safe") {
|
|
|
52174
52267
|
const isSlashPair = (l, r) => l === "/" && r === "/" || l === "\\" && r === "\\" || l === "/" && r === "\\" || l === "\\" && r === "/";
|
|
52175
52268
|
const isParallelogramShape = core.length >= 2 && isSlashPair(left, right);
|
|
52176
52269
|
let replaced;
|
|
52177
|
-
if (!isParallelogramShape) {
|
|
52178
|
-
const
|
|
52270
|
+
if (is("FL-LABEL-BRACKET-IN-UNQUOTED", e) && !isParallelogramShape) {
|
|
52271
|
+
const hasOtherHazards = /[(){}@]/.test(inner) || inner.includes('"') || inner.includes('\\"');
|
|
52272
|
+
if (hasOtherHazards) {
|
|
52273
|
+
const escaped = inner.replace(/`/g, "").replace(/\\"/g, """).replace(/"/g, """);
|
|
52274
|
+
replaced = '"' + escaped + '"';
|
|
52275
|
+
} else {
|
|
52276
|
+
replaced = inner.replace(/\[/g, "[").replace(/\]/g, "]");
|
|
52277
|
+
}
|
|
52278
|
+
} else if (is("FL-LABEL-CURLY-IN-UNQUOTED", e)) {
|
|
52279
|
+
replaced = inner.replace(/\{/g, "{").replace(/\}/g, "}");
|
|
52280
|
+
} else if (!isParallelogramShape) {
|
|
52281
|
+
const escaped = inner.replace(/`/g, "").replace(/\\"/g, """).replace(/"/g, """);
|
|
52179
52282
|
replaced = '"' + escaped + '"';
|
|
52180
52283
|
} else {
|
|
52181
|
-
replaced = inner.replace(/`/g, "").replace(/\(/g, "(").replace(/\)/g, ")").replace(/\"/g, """).replace(/"/g, """);
|
|
52284
|
+
replaced = inner.replace(/`/g, "").replace(/\(/g, "(").replace(/\)/g, ")").replace(/\[/g, "[").replace(/\]/g, "]").replace(/\\"/g, """).replace(/"/g, """);
|
|
52182
52285
|
}
|
|
52183
52286
|
if (replaced !== inner) {
|
|
52184
52287
|
edits.push({ start: { line: e.line, column: contentStart + 1 }, end: { line: e.line, column: closeIdx + 1 }, newText: replaced });
|
|
@@ -82266,14 +82369,6 @@ var init_FallbackManager = __esm({
|
|
|
82266
82369
|
});
|
|
82267
82370
|
|
|
82268
82371
|
// src/agent/contextCompactor.js
|
|
82269
|
-
var contextCompactor_exports = {};
|
|
82270
|
-
__export(contextCompactor_exports, {
|
|
82271
|
-
calculateCompactionStats: () => calculateCompactionStats,
|
|
82272
|
-
compactMessages: () => compactMessages,
|
|
82273
|
-
handleContextLimitError: () => handleContextLimitError,
|
|
82274
|
-
identifyMessageSegments: () => identifyMessageSegments,
|
|
82275
|
-
isContextLimitError: () => isContextLimitError
|
|
82276
|
-
});
|
|
82277
82372
|
function isContextLimitError(error40) {
|
|
82278
82373
|
if (!error40) return false;
|
|
82279
82374
|
const errorMessage = (typeof error40 === "string" ? error40 : error40?.message || "").toLowerCase();
|
|
@@ -98870,6 +98965,16 @@ You are working with a workspace. Available paths: ${workspaceDesc}
|
|
|
98870
98965
|
userMessage
|
|
98871
98966
|
];
|
|
98872
98967
|
}
|
|
98968
|
+
if (this.history.length > 0) {
|
|
98969
|
+
const compacted = compactMessages(currentMessages, { keepLastSegment: true, minSegmentsToKeep: 1 });
|
|
98970
|
+
if (compacted.length < currentMessages.length) {
|
|
98971
|
+
const stats = calculateCompactionStats(currentMessages, compacted);
|
|
98972
|
+
if (this.debug) {
|
|
98973
|
+
console.log(`[DEBUG] Proactive history compaction: ${currentMessages.length} \u2192 ${compacted.length} messages (${stats.reductionPercent}% reduction, ~${stats.tokensSaved} tokens saved)`);
|
|
98974
|
+
}
|
|
98975
|
+
currentMessages = compacted;
|
|
98976
|
+
}
|
|
98977
|
+
}
|
|
98873
98978
|
let currentIteration = 0;
|
|
98874
98979
|
let finalResult = "I was unable to complete your request due to reaching the maximum number of tool iterations.";
|
|
98875
98980
|
const baseMaxIterations = options._maxIterationsOverride || this.maxIterations || MAX_TOOL_ITERATIONS;
|
|
@@ -99570,7 +99675,6 @@ Double-check your response based on the criteria above. If everything looks good
|
|
|
99570
99675
|
* @returns {Object} Compaction statistics
|
|
99571
99676
|
*/
|
|
99572
99677
|
async compactHistory(options = {}) {
|
|
99573
|
-
const { compactMessages: compactMessages2, calculateCompactionStats: calculateCompactionStats2 } = await Promise.resolve().then(() => (init_contextCompactor(), contextCompactor_exports));
|
|
99574
99678
|
if (this.history.length === 0) {
|
|
99575
99679
|
if (this.debug) {
|
|
99576
99680
|
console.log(`[DEBUG] No history to compact for session ${this.sessionId}`);
|
|
@@ -99585,8 +99689,8 @@ Double-check your response based on the criteria above. If everything looks good
|
|
|
99585
99689
|
tokensSaved: 0
|
|
99586
99690
|
};
|
|
99587
99691
|
}
|
|
99588
|
-
const compactedMessages =
|
|
99589
|
-
const stats =
|
|
99692
|
+
const compactedMessages = compactMessages(this.history, options);
|
|
99693
|
+
const stats = calculateCompactionStats(this.history, compactedMessages);
|
|
99590
99694
|
this.history = compactedMessages;
|
|
99591
99695
|
try {
|
|
99592
99696
|
await this.storageAdapter.clearHistory(this.sessionId);
|
|
@@ -100915,11 +101019,24 @@ function normalizeTargets(targets) {
|
|
|
100915
101019
|
if (typeof target !== "string") continue;
|
|
100916
101020
|
const trimmed = target.trim();
|
|
100917
101021
|
if (!trimmed || seen.has(trimmed)) continue;
|
|
100918
|
-
|
|
100919
|
-
|
|
101022
|
+
const subTargets = splitSpaceSeparatedPaths(trimmed);
|
|
101023
|
+
for (const sub of subTargets) {
|
|
101024
|
+
if (!seen.has(sub)) {
|
|
101025
|
+
seen.add(sub);
|
|
101026
|
+
normalized.push(sub);
|
|
101027
|
+
}
|
|
101028
|
+
}
|
|
100920
101029
|
}
|
|
100921
101030
|
return normalized;
|
|
100922
101031
|
}
|
|
101032
|
+
function splitSpaceSeparatedPaths(target) {
|
|
101033
|
+
if (!/\s/.test(target)) return [target];
|
|
101034
|
+
const parts = target.split(/\s+/).filter(Boolean);
|
|
101035
|
+
if (parts.length <= 1) return [target];
|
|
101036
|
+
const allLookLikePaths = parts.every((p) => /[/\\]/.test(p) || /\.\w+/.test(p));
|
|
101037
|
+
if (allLookLikePaths) return parts;
|
|
101038
|
+
return [target];
|
|
101039
|
+
}
|
|
100923
101040
|
function extractJsonSnippet(text) {
|
|
100924
101041
|
const jsonBlockMatch = text.match(/```json\s*([\s\S]*?)```/i);
|
|
100925
101042
|
if (jsonBlockMatch) {
|
|
@@ -101405,14 +101522,15 @@ var init_vercel = __esm({
|
|
|
101405
101522
|
const parsedTargets = parseTargets(targets);
|
|
101406
101523
|
extractFiles = parsedTargets.map((target) => resolveTargetPath(target, effectiveCwd));
|
|
101407
101524
|
if (options.allowedFolders && options.allowedFolders.length > 0) {
|
|
101525
|
+
const { join: pathJoin, sep: pathSep } = await import("path");
|
|
101408
101526
|
extractFiles = extractFiles.map((target) => {
|
|
101409
101527
|
const { filePart, suffix } = splitTargetSuffix(target);
|
|
101410
101528
|
if ((0, import_fs11.existsSync)(filePart)) return target;
|
|
101411
|
-
const cwdPrefix = effectiveCwd.endsWith(
|
|
101529
|
+
const cwdPrefix = effectiveCwd.endsWith(pathSep) ? effectiveCwd : effectiveCwd + pathSep;
|
|
101412
101530
|
const relativePart = filePart.startsWith(cwdPrefix) ? filePart.slice(cwdPrefix.length) : null;
|
|
101413
101531
|
if (relativePart) {
|
|
101414
101532
|
for (const folder of options.allowedFolders) {
|
|
101415
|
-
const candidate = folder
|
|
101533
|
+
const candidate = pathJoin(folder, relativePart);
|
|
101416
101534
|
if ((0, import_fs11.existsSync)(candidate)) {
|
|
101417
101535
|
if (debug) console.error(`[extract] Auto-fixed path: ${filePart} \u2192 ${candidate}`);
|
|
101418
101536
|
return candidate + suffix;
|
|
@@ -101420,11 +101538,12 @@ var init_vercel = __esm({
|
|
|
101420
101538
|
}
|
|
101421
101539
|
}
|
|
101422
101540
|
for (const folder of options.allowedFolders) {
|
|
101423
|
-
const folderPrefix = folder.endsWith(
|
|
101424
|
-
const
|
|
101541
|
+
const folderPrefix = folder.endsWith(pathSep) ? folder : folder + pathSep;
|
|
101542
|
+
const sepEscaped = pathSep === "\\" ? "\\\\" : pathSep;
|
|
101543
|
+
const wsParent = folderPrefix.replace(new RegExp("[^" + sepEscaped + "]+" + sepEscaped + "$"), "");
|
|
101425
101544
|
if (filePart.startsWith(wsParent)) {
|
|
101426
101545
|
const tail = filePart.slice(wsParent.length);
|
|
101427
|
-
const candidate = folderPrefix
|
|
101546
|
+
const candidate = pathJoin(folderPrefix, tail);
|
|
101428
101547
|
if (candidate !== filePart && (0, import_fs11.existsSync)(candidate)) {
|
|
101429
101548
|
if (debug) console.error(`[extract] Auto-fixed path via workspace: ${filePart} \u2192 ${candidate}`);
|
|
101430
101549
|
return candidate + suffix;
|
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-rc287",
|
|
4
4
|
"description": "Node.js wrapper for the probe code search tool",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"module": "src/index.js",
|
|
@@ -80,11 +80,11 @@
|
|
|
80
80
|
"@anthropic-ai/claude-agent-sdk": "^0.1.46",
|
|
81
81
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
82
82
|
"@nyariv/sandboxjs": "github:probelabs/SandboxJS",
|
|
83
|
-
"@probelabs/maid": "^0.0.
|
|
83
|
+
"@probelabs/maid": "^0.0.27",
|
|
84
84
|
"acorn": "^8.15.0",
|
|
85
85
|
"acorn-walk": "^8.3.4",
|
|
86
86
|
"adm-zip": "^0.5.16",
|
|
87
|
-
"ai": "^6.0.
|
|
87
|
+
"ai": "^6.0.0",
|
|
88
88
|
"ajv": "^8.17.1",
|
|
89
89
|
"astring": "^1.9.0",
|
|
90
90
|
"axios": "^1.8.3",
|
package/src/agent/ProbeAgent.js
CHANGED
|
@@ -93,7 +93,7 @@ import { formatAvailableSkillsXml as formatAvailableSkills } from './skills/form
|
|
|
93
93
|
import { createSkillToolInstances } from './skills/tools.js';
|
|
94
94
|
import { RetryManager, createRetryManagerFromEnv } from './RetryManager.js';
|
|
95
95
|
import { FallbackManager, createFallbackManagerFromEnv, buildFallbackProvidersFromEnv } from './FallbackManager.js';
|
|
96
|
-
import { handleContextLimitError } from './contextCompactor.js';
|
|
96
|
+
import { handleContextLimitError, compactMessages, calculateCompactionStats } from './contextCompactor.js';
|
|
97
97
|
import { formatErrorForAI, ParameterError } from '../utils/error-types.js';
|
|
98
98
|
import { getCommonPrefix, toRelativePath, safeRealpath } from '../utils/path-validation.js';
|
|
99
99
|
import { truncateIfNeeded, getMaxOutputTokens } from './outputTruncator.js';
|
|
@@ -3227,6 +3227,25 @@ Follow these instructions carefully:
|
|
|
3227
3227
|
];
|
|
3228
3228
|
}
|
|
3229
3229
|
|
|
3230
|
+
// Proactively compact for multi-turn conversations.
|
|
3231
|
+
// On turn 2+, previous turns contain full tool call/result history which can
|
|
3232
|
+
// be 50K+ tokens. This drowns out the new user message and causes the model to
|
|
3233
|
+
// focus on prior context rather than the new question.
|
|
3234
|
+
// compactMessages strips intermediate monologue from completed segments,
|
|
3235
|
+
// keeping user messages + final answers from prior turns.
|
|
3236
|
+
// Must run AFTER adding the new user message so the compactor sees 2+ segments
|
|
3237
|
+
// (completed prior turns + the new incomplete turn), preserving the latest segment.
|
|
3238
|
+
if (this.history.length > 0) {
|
|
3239
|
+
const compacted = compactMessages(currentMessages, { keepLastSegment: true, minSegmentsToKeep: 1 });
|
|
3240
|
+
if (compacted.length < currentMessages.length) {
|
|
3241
|
+
const stats = calculateCompactionStats(currentMessages, compacted);
|
|
3242
|
+
if (this.debug) {
|
|
3243
|
+
console.log(`[DEBUG] Proactive history compaction: ${currentMessages.length} → ${compacted.length} messages (${stats.reductionPercent}% reduction, ~${stats.tokensSaved} tokens saved)`);
|
|
3244
|
+
}
|
|
3245
|
+
currentMessages = compacted;
|
|
3246
|
+
}
|
|
3247
|
+
}
|
|
3248
|
+
|
|
3230
3249
|
let currentIteration = 0;
|
|
3231
3250
|
let finalResult = 'I was unable to complete your request due to reaching the maximum number of tool iterations.';
|
|
3232
3251
|
|
|
@@ -4141,8 +4160,6 @@ Double-check your response based on the criteria above. If everything looks good
|
|
|
4141
4160
|
* @returns {Object} Compaction statistics
|
|
4142
4161
|
*/
|
|
4143
4162
|
async compactHistory(options = {}) {
|
|
4144
|
-
const { compactMessages, calculateCompactionStats } = await import('./contextCompactor.js');
|
|
4145
|
-
|
|
4146
4163
|
if (this.history.length === 0) {
|
|
4147
4164
|
if (this.debug) {
|
|
4148
4165
|
console.log(`[DEBUG] No history to compact for session ${this.sessionId}`);
|
package/src/downloader.js
CHANGED
|
@@ -743,7 +743,11 @@ async function extractBinary(assetPath, outputDir) {
|
|
|
743
743
|
if (process.env.DEBUG === '1' || process.env.VERBOSE === '1') {
|
|
744
744
|
console.log(`Extracting zip to ${extractDir}...`);
|
|
745
745
|
}
|
|
746
|
-
|
|
746
|
+
if (isWindows) {
|
|
747
|
+
await exec(`powershell -NoProfile -Command "Expand-Archive -Path '${assetPath}' -DestinationPath '${extractDir}' -Force"`);
|
|
748
|
+
} else {
|
|
749
|
+
await exec(`unzip -q "${assetPath}" -d "${extractDir}"`);
|
|
750
|
+
}
|
|
747
751
|
} else {
|
|
748
752
|
// Assume it's a direct binary
|
|
749
753
|
if (process.env.DEBUG === '1' || process.env.VERBOSE === '1') {
|
package/src/tools/common.js
CHANGED
|
@@ -228,7 +228,17 @@ export function parseAndResolvePaths(pathStr, cwd) {
|
|
|
228
228
|
if (!pathStr) return [];
|
|
229
229
|
|
|
230
230
|
// Split on comma and trim whitespace
|
|
231
|
-
|
|
231
|
+
let paths = pathStr.split(',').map(p => p.trim()).filter(p => p.length > 0);
|
|
232
|
+
|
|
233
|
+
// Auto-fix: model sometimes passes space-separated file paths as one string
|
|
234
|
+
// e.g. "src/ranking.rs src/simd_ranking.rs" — split if each part looks like a path
|
|
235
|
+
paths = paths.flatMap(p => {
|
|
236
|
+
if (!/\s/.test(p)) return [p];
|
|
237
|
+
const parts = p.split(/\s+/).filter(Boolean);
|
|
238
|
+
if (parts.length <= 1) return [p];
|
|
239
|
+
const allLookLikePaths = parts.every(part => /[/\\]/.test(part) || /\.\w+/.test(part));
|
|
240
|
+
return allLookLikePaths ? parts : [p];
|
|
241
|
+
});
|
|
232
242
|
|
|
233
243
|
// Resolve relative paths against cwd
|
|
234
244
|
return paths.map(p => {
|
package/src/tools/vercel.js
CHANGED
|
@@ -105,13 +105,42 @@ function normalizeTargets(targets) {
|
|
|
105
105
|
if (typeof target !== 'string') continue;
|
|
106
106
|
const trimmed = target.trim();
|
|
107
107
|
if (!trimmed || seen.has(trimmed)) continue;
|
|
108
|
-
|
|
109
|
-
|
|
108
|
+
|
|
109
|
+
// Auto-fix: model sometimes puts multiple space-separated file paths in one string
|
|
110
|
+
// e.g. "src/ranking.rs src/simd_ranking.rs" — split them apart
|
|
111
|
+
const subTargets = splitSpaceSeparatedPaths(trimmed);
|
|
112
|
+
for (const sub of subTargets) {
|
|
113
|
+
if (!seen.has(sub)) {
|
|
114
|
+
seen.add(sub);
|
|
115
|
+
normalized.push(sub);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
110
118
|
}
|
|
111
119
|
|
|
112
120
|
return normalized;
|
|
113
121
|
}
|
|
114
122
|
|
|
123
|
+
/**
|
|
124
|
+
* Split a string that may contain multiple space-separated file paths.
|
|
125
|
+
* Detects patterns like "path/file.ext path2/file2.ext" and splits them.
|
|
126
|
+
* Preserves single paths and paths with suffixes like ":10-20" or "#Symbol".
|
|
127
|
+
*/
|
|
128
|
+
function splitSpaceSeparatedPaths(target) {
|
|
129
|
+
// If no spaces, it's a single target
|
|
130
|
+
if (!/\s/.test(target)) return [target];
|
|
131
|
+
|
|
132
|
+
// Split on whitespace and check if parts look like file paths
|
|
133
|
+
const parts = target.split(/\s+/).filter(Boolean);
|
|
134
|
+
if (parts.length <= 1) return [target];
|
|
135
|
+
|
|
136
|
+
// Check if each part looks like a file path (has a dot extension or path separator)
|
|
137
|
+
const allLookLikePaths = parts.every(p => /[/\\]/.test(p) || /\.\w+/.test(p));
|
|
138
|
+
if (allLookLikePaths) return parts;
|
|
139
|
+
|
|
140
|
+
// Not confident these are separate paths — return as-is
|
|
141
|
+
return [target];
|
|
142
|
+
}
|
|
143
|
+
|
|
115
144
|
function extractJsonSnippet(text) {
|
|
116
145
|
const jsonBlockMatch = text.match(/```json\s*([\s\S]*?)```/i);
|
|
117
146
|
if (jsonBlockMatch) {
|
|
@@ -691,19 +720,20 @@ export const extractTool = (options = {}) => {
|
|
|
691
720
|
// model constructs wrong absolute paths (e.g., /workspace/gateway/file.go
|
|
692
721
|
// instead of /workspace/tyk/gateway/file.go)
|
|
693
722
|
if (options.allowedFolders && options.allowedFolders.length > 0) {
|
|
723
|
+
const { join: pathJoin, sep: pathSep } = await import('path');
|
|
694
724
|
extractFiles = extractFiles.map(target => {
|
|
695
725
|
const { filePart, suffix } = splitTargetSuffix(target);
|
|
696
726
|
if (existsSync(filePart)) return target;
|
|
697
727
|
|
|
698
728
|
// Try resolving the relative tail against each allowedFolder
|
|
699
|
-
const cwdPrefix =
|
|
729
|
+
const cwdPrefix = effectiveCwd.endsWith(pathSep) ? effectiveCwd : effectiveCwd + pathSep;
|
|
700
730
|
const relativePart = filePart.startsWith(cwdPrefix)
|
|
701
731
|
? filePart.slice(cwdPrefix.length)
|
|
702
732
|
: null;
|
|
703
733
|
|
|
704
734
|
if (relativePart) {
|
|
705
735
|
for (const folder of options.allowedFolders) {
|
|
706
|
-
const candidate = folder
|
|
736
|
+
const candidate = pathJoin(folder, relativePart);
|
|
707
737
|
if (existsSync(candidate)) {
|
|
708
738
|
if (debug) console.error(`[extract] Auto-fixed path: ${filePart} → ${candidate}`);
|
|
709
739
|
return candidate + suffix;
|
|
@@ -714,11 +744,12 @@ export const extractTool = (options = {}) => {
|
|
|
714
744
|
// Try stripping workspace prefix and resolving against allowedFolders
|
|
715
745
|
// e.g., /tmp/visor-workspaces/abc/gateway/file.go → try each folder + gateway/file.go
|
|
716
746
|
for (const folder of options.allowedFolders) {
|
|
717
|
-
const folderPrefix = folder.endsWith(
|
|
718
|
-
const
|
|
747
|
+
const folderPrefix = folder.endsWith(pathSep) ? folder : folder + pathSep;
|
|
748
|
+
const sepEscaped = pathSep === '\\' ? '\\\\' : pathSep;
|
|
749
|
+
const wsParent = folderPrefix.replace(new RegExp('[^' + sepEscaped + ']+' + sepEscaped + '$'), '');
|
|
719
750
|
if (filePart.startsWith(wsParent)) {
|
|
720
751
|
const tail = filePart.slice(wsParent.length);
|
|
721
|
-
const candidate = folderPrefix
|
|
752
|
+
const candidate = pathJoin(folderPrefix, tail);
|
|
722
753
|
if (candidate !== filePart && existsSync(candidate)) {
|
|
723
754
|
if (debug) console.error(`[extract] Auto-fixed path via workspace: ${filePart} → ${candidate}`);
|
|
724
755
|
return candidate + suffix;
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|