@probelabs/probe 0.6.0-rc253 → 0.6.0-rc255
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/README.md +166 -3
- package/bin/binaries/probe-v0.6.0-rc255-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc255-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc255-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc255-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc255-x86_64-unknown-linux-musl.tar.gz +0 -0
- package/build/agent/ProbeAgent.d.ts +1 -1
- package/build/agent/ProbeAgent.js +51 -16
- package/build/agent/acp/tools.js +2 -1
- package/build/agent/acp/tools.test.js +2 -1
- package/build/agent/dsl/environment.js +19 -0
- package/build/agent/index.js +1512 -413
- package/build/agent/schemaUtils.js +91 -2
- package/build/agent/tools.js +0 -28
- package/build/delegate.js +3 -0
- package/build/index.js +2 -0
- package/build/tools/common.js +6 -5
- package/build/tools/edit.js +457 -65
- package/build/tools/executePlan.js +3 -1
- package/build/tools/fileTracker.js +318 -0
- package/build/tools/fuzzyMatch.js +271 -0
- package/build/tools/hashline.js +131 -0
- package/build/tools/lineEditHeuristics.js +138 -0
- package/build/tools/symbolEdit.js +119 -0
- package/build/tools/vercel.js +40 -9
- package/cjs/agent/ProbeAgent.cjs +1615 -517
- package/cjs/index.cjs +1643 -543
- package/index.d.ts +189 -1
- package/package.json +1 -1
- package/src/agent/ProbeAgent.d.ts +1 -1
- package/src/agent/ProbeAgent.js +51 -16
- package/src/agent/acp/tools.js +2 -1
- package/src/agent/acp/tools.test.js +2 -1
- package/src/agent/dsl/environment.js +19 -0
- package/src/agent/index.js +14 -3
- package/src/agent/schemaUtils.js +91 -2
- package/src/agent/tools.js +0 -28
- package/src/delegate.js +3 -0
- package/src/index.js +2 -0
- package/src/tools/common.js +6 -5
- package/src/tools/edit.js +457 -65
- package/src/tools/executePlan.js +3 -1
- package/src/tools/fileTracker.js +318 -0
- package/src/tools/fuzzyMatch.js +271 -0
- package/src/tools/hashline.js +131 -0
- package/src/tools/lineEditHeuristics.js +138 -0
- package/src/tools/symbolEdit.js +119 -0
- package/src/tools/vercel.js +40 -9
- package/bin/binaries/probe-v0.6.0-rc253-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc253-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc253-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc253-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc253-x86_64-unknown-linux-musl.tar.gz +0 -0
package/build/agent/index.js
CHANGED
|
@@ -2377,7 +2377,7 @@ async function waitForFileLock(lockPath, binaryPath) {
|
|
|
2377
2377
|
}
|
|
2378
2378
|
} catch {
|
|
2379
2379
|
}
|
|
2380
|
-
await new Promise((
|
|
2380
|
+
await new Promise((resolve9) => setTimeout(resolve9, LOCK_POLL_INTERVAL_MS));
|
|
2381
2381
|
}
|
|
2382
2382
|
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
2383
2383
|
console.log(`Timeout waiting for file lock`);
|
|
@@ -3718,7 +3718,7 @@ Cwd: ${cwd}`;
|
|
|
3718
3718
|
}
|
|
3719
3719
|
}
|
|
3720
3720
|
function extractWithStdin(binaryPath, cliArgs, content, options, cwd) {
|
|
3721
|
-
return new Promise((
|
|
3721
|
+
return new Promise((resolve9, reject2) => {
|
|
3722
3722
|
const childProcess = spawn(binaryPath, ["extract", ...cliArgs], {
|
|
3723
3723
|
stdio: ["pipe", "pipe", "pipe"],
|
|
3724
3724
|
cwd
|
|
@@ -3741,7 +3741,7 @@ function extractWithStdin(binaryPath, cliArgs, content, options, cwd) {
|
|
|
3741
3741
|
}
|
|
3742
3742
|
try {
|
|
3743
3743
|
const result = processExtractOutput(stdout, options);
|
|
3744
|
-
|
|
3744
|
+
resolve9(result);
|
|
3745
3745
|
} catch (error) {
|
|
3746
3746
|
reject2(error);
|
|
3747
3747
|
}
|
|
@@ -3849,6 +3849,7 @@ async function delegate({
|
|
|
3849
3849
|
model = null,
|
|
3850
3850
|
enableBash = false,
|
|
3851
3851
|
bashConfig = null,
|
|
3852
|
+
allowEdit = false,
|
|
3852
3853
|
architectureFileName = null,
|
|
3853
3854
|
promptType = "code-researcher",
|
|
3854
3855
|
allowedTools = null,
|
|
@@ -3928,6 +3929,8 @@ async function delegate({
|
|
|
3928
3929
|
// Inherit from parent
|
|
3929
3930
|
bashConfig,
|
|
3930
3931
|
// Inherit from parent
|
|
3932
|
+
allowEdit,
|
|
3933
|
+
// Inherit from parent
|
|
3931
3934
|
architectureFileName,
|
|
3932
3935
|
allowedTools,
|
|
3933
3936
|
disableTools,
|
|
@@ -4112,7 +4115,7 @@ var init_delegate = __esm({
|
|
|
4112
4115
|
if (debug) {
|
|
4113
4116
|
console.error(`[DelegationManager] Slot unavailable (${this.globalActive}/${this.maxConcurrent}), queuing... (queue size: ${this.waitQueue.length}, timeout: ${effectiveTimeout}ms)`);
|
|
4114
4117
|
}
|
|
4115
|
-
return new Promise((
|
|
4118
|
+
return new Promise((resolve9, reject2) => {
|
|
4116
4119
|
const entry = {
|
|
4117
4120
|
resolve: null,
|
|
4118
4121
|
// Will be wrapped below
|
|
@@ -4128,7 +4131,7 @@ var init_delegate = __esm({
|
|
|
4128
4131
|
if (settled) return;
|
|
4129
4132
|
settled = true;
|
|
4130
4133
|
if (entry.timeoutId) clearTimeout(entry.timeoutId);
|
|
4131
|
-
|
|
4134
|
+
resolve9(value);
|
|
4132
4135
|
};
|
|
4133
4136
|
entry.reject = (error) => {
|
|
4134
4137
|
if (settled) return;
|
|
@@ -4178,7 +4181,7 @@ var init_delegate = __esm({
|
|
|
4178
4181
|
while (this.waitQueue.length > 0 && this.globalActive < this.maxConcurrent) {
|
|
4179
4182
|
const next = this.waitQueue.shift();
|
|
4180
4183
|
if (!next) break;
|
|
4181
|
-
const { resolve:
|
|
4184
|
+
const { resolve: resolve9, reject: reject2, parentSessionId, queuedAt } = next;
|
|
4182
4185
|
if (parentSessionId) {
|
|
4183
4186
|
const sessionData = this.sessionDelegations.get(parentSessionId);
|
|
4184
4187
|
const sessionCount = sessionData?.count || 0;
|
|
@@ -4195,12 +4198,12 @@ var init_delegate = __esm({
|
|
|
4195
4198
|
const waitTime = Date.now() - queuedAt;
|
|
4196
4199
|
console.error(`[DelegationManager] Granted slot from queue (waited ${waitTime}ms). Active: ${this.globalActive}/${this.maxConcurrent}`);
|
|
4197
4200
|
}
|
|
4198
|
-
toResolve.push(
|
|
4201
|
+
toResolve.push(resolve9);
|
|
4199
4202
|
}
|
|
4200
4203
|
if (toResolve.length > 0 || toReject.length > 0) {
|
|
4201
4204
|
setImmediate(() => {
|
|
4202
|
-
for (const
|
|
4203
|
-
|
|
4205
|
+
for (const resolve9 of toResolve) {
|
|
4206
|
+
resolve9(true);
|
|
4204
4207
|
}
|
|
4205
4208
|
for (const { reject: reject2, error } of toReject) {
|
|
4206
4209
|
reject2(error);
|
|
@@ -8835,6 +8838,400 @@ var init_zod = __esm({
|
|
|
8835
8838
|
}
|
|
8836
8839
|
});
|
|
8837
8840
|
|
|
8841
|
+
// src/tools/fuzzyMatch.js
|
|
8842
|
+
function findFuzzyMatch(content, searchString) {
|
|
8843
|
+
if (!searchString || searchString.trim().length === 0) {
|
|
8844
|
+
return null;
|
|
8845
|
+
}
|
|
8846
|
+
const normalizedContent = content.replace(/\r\n/g, "\n");
|
|
8847
|
+
const normalizedSearch = searchString.replace(/\r\n/g, "\n");
|
|
8848
|
+
const contentLines = normalizedContent.split("\n");
|
|
8849
|
+
const searchLines = normalizedSearch.split("\n");
|
|
8850
|
+
const trimmed = lineTrimmedMatch(contentLines, searchLines);
|
|
8851
|
+
if (trimmed) return { ...trimmed, strategy: "line-trimmed" };
|
|
8852
|
+
const normalized = whitespaceNormalizedMatch(normalizedContent, normalizedSearch);
|
|
8853
|
+
if (normalized) return { ...normalized, strategy: "whitespace-normalized" };
|
|
8854
|
+
const indentFlex = indentFlexibleMatch(contentLines, searchLines);
|
|
8855
|
+
if (indentFlex) return { ...indentFlex, strategy: "indent-flexible" };
|
|
8856
|
+
return null;
|
|
8857
|
+
}
|
|
8858
|
+
function lineTrimmedMatch(contentLines, searchLines) {
|
|
8859
|
+
if (searchLines.length === 0) return null;
|
|
8860
|
+
const trimmedSearchLines = searchLines.map((line) => line.trim());
|
|
8861
|
+
if (trimmedSearchLines.every((line) => line === "")) return null;
|
|
8862
|
+
const windowSize = searchLines.length;
|
|
8863
|
+
const matches = [];
|
|
8864
|
+
for (let i = 0; i <= contentLines.length - windowSize; i++) {
|
|
8865
|
+
let allMatch = true;
|
|
8866
|
+
for (let j = 0; j < windowSize; j++) {
|
|
8867
|
+
if (contentLines[i + j].trim() !== trimmedSearchLines[j]) {
|
|
8868
|
+
allMatch = false;
|
|
8869
|
+
break;
|
|
8870
|
+
}
|
|
8871
|
+
}
|
|
8872
|
+
if (allMatch) {
|
|
8873
|
+
const matchedText = contentLines.slice(i, i + windowSize).join("\n");
|
|
8874
|
+
matches.push(matchedText);
|
|
8875
|
+
}
|
|
8876
|
+
}
|
|
8877
|
+
if (matches.length === 0) return null;
|
|
8878
|
+
return {
|
|
8879
|
+
matchedText: matches[0],
|
|
8880
|
+
count: matches.length
|
|
8881
|
+
};
|
|
8882
|
+
}
|
|
8883
|
+
function whitespaceNormalizedMatch(content, search2) {
|
|
8884
|
+
if (!search2 || search2.trim().length === 0) return null;
|
|
8885
|
+
const { normalized: normContent, indexMap: contentMap } = buildNormalizedMap(content);
|
|
8886
|
+
const { normalized: normSearch } = buildNormalizedMap(search2);
|
|
8887
|
+
if (normSearch.length === 0) return null;
|
|
8888
|
+
const matches = [];
|
|
8889
|
+
let searchStart = 0;
|
|
8890
|
+
while (searchStart <= normContent.length - normSearch.length) {
|
|
8891
|
+
const idx = normContent.indexOf(normSearch, searchStart);
|
|
8892
|
+
if (idx === -1) break;
|
|
8893
|
+
const originalStart = contentMap[idx];
|
|
8894
|
+
const originalEnd = contentMap[idx + normSearch.length - 1];
|
|
8895
|
+
let actualEnd = originalEnd + 1;
|
|
8896
|
+
while (actualEnd < content.length && /[ \t]/.test(content[actualEnd]) && (actualEnd === originalEnd + 1 || /[ \t]/.test(content[actualEnd - 1]))) {
|
|
8897
|
+
if (contentMap.indexOf(actualEnd) > idx + normSearch.length - 1 || contentMap.indexOf(actualEnd) === -1) {
|
|
8898
|
+
break;
|
|
8899
|
+
}
|
|
8900
|
+
actualEnd++;
|
|
8901
|
+
}
|
|
8902
|
+
const matchedText = content.substring(originalStart, actualEnd);
|
|
8903
|
+
matches.push(matchedText);
|
|
8904
|
+
searchStart = idx + 1;
|
|
8905
|
+
}
|
|
8906
|
+
if (matches.length === 0) return null;
|
|
8907
|
+
return {
|
|
8908
|
+
matchedText: matches[0],
|
|
8909
|
+
count: matches.length
|
|
8910
|
+
};
|
|
8911
|
+
}
|
|
8912
|
+
function buildNormalizedMap(str) {
|
|
8913
|
+
const normalized = [];
|
|
8914
|
+
const indexMap = [];
|
|
8915
|
+
let i = 0;
|
|
8916
|
+
while (i < str.length) {
|
|
8917
|
+
const ch = str[i];
|
|
8918
|
+
if (ch === " " || ch === " ") {
|
|
8919
|
+
normalized.push(" ");
|
|
8920
|
+
indexMap.push(i);
|
|
8921
|
+
while (i < str.length && (str[i] === " " || str[i] === " ")) {
|
|
8922
|
+
i++;
|
|
8923
|
+
}
|
|
8924
|
+
} else {
|
|
8925
|
+
normalized.push(ch);
|
|
8926
|
+
indexMap.push(i);
|
|
8927
|
+
i++;
|
|
8928
|
+
}
|
|
8929
|
+
}
|
|
8930
|
+
return {
|
|
8931
|
+
normalized: normalized.join(""),
|
|
8932
|
+
indexMap
|
|
8933
|
+
};
|
|
8934
|
+
}
|
|
8935
|
+
function indentFlexibleMatch(contentLines, searchLines) {
|
|
8936
|
+
if (searchLines.length === 0) return null;
|
|
8937
|
+
if (searchLines.every((line) => line.trim() === "")) return null;
|
|
8938
|
+
const searchMinIndent = getMinIndent(searchLines);
|
|
8939
|
+
const strippedSearch = searchLines.map((line) => stripIndent(line, searchMinIndent));
|
|
8940
|
+
const windowSize = searchLines.length;
|
|
8941
|
+
const matches = [];
|
|
8942
|
+
for (let i = 0; i <= contentLines.length - windowSize; i++) {
|
|
8943
|
+
const windowLines = contentLines.slice(i, i + windowSize);
|
|
8944
|
+
const windowMinIndent = getMinIndent(windowLines);
|
|
8945
|
+
const strippedWindow = windowLines.map((line) => stripIndent(line, windowMinIndent));
|
|
8946
|
+
let allMatch = true;
|
|
8947
|
+
for (let j = 0; j < windowSize; j++) {
|
|
8948
|
+
if (strippedWindow[j] !== strippedSearch[j]) {
|
|
8949
|
+
allMatch = false;
|
|
8950
|
+
break;
|
|
8951
|
+
}
|
|
8952
|
+
}
|
|
8953
|
+
if (allMatch) {
|
|
8954
|
+
const matchedText = windowLines.join("\n");
|
|
8955
|
+
matches.push(matchedText);
|
|
8956
|
+
}
|
|
8957
|
+
}
|
|
8958
|
+
if (matches.length === 0) return null;
|
|
8959
|
+
return {
|
|
8960
|
+
matchedText: matches[0],
|
|
8961
|
+
count: matches.length
|
|
8962
|
+
};
|
|
8963
|
+
}
|
|
8964
|
+
function getMinIndent(lines) {
|
|
8965
|
+
let min = Infinity;
|
|
8966
|
+
for (const line of lines) {
|
|
8967
|
+
if (line.trim() === "") continue;
|
|
8968
|
+
const match2 = line.match(/^([ \t]*)/);
|
|
8969
|
+
if (match2) {
|
|
8970
|
+
min = Math.min(min, match2[1].length);
|
|
8971
|
+
}
|
|
8972
|
+
}
|
|
8973
|
+
return min === Infinity ? 0 : min;
|
|
8974
|
+
}
|
|
8975
|
+
function stripIndent(line, amount) {
|
|
8976
|
+
if (line.trim() === "") return "";
|
|
8977
|
+
if (amount <= 0) return line;
|
|
8978
|
+
return line.substring(Math.min(amount, line.length));
|
|
8979
|
+
}
|
|
8980
|
+
var init_fuzzyMatch = __esm({
|
|
8981
|
+
"src/tools/fuzzyMatch.js"() {
|
|
8982
|
+
"use strict";
|
|
8983
|
+
}
|
|
8984
|
+
});
|
|
8985
|
+
|
|
8986
|
+
// src/tools/symbolEdit.js
|
|
8987
|
+
async function findSymbol(filePath, symbolName, cwd) {
|
|
8988
|
+
try {
|
|
8989
|
+
const result = await extract({
|
|
8990
|
+
files: [`${filePath}#${symbolName}`],
|
|
8991
|
+
format: "json",
|
|
8992
|
+
json: true,
|
|
8993
|
+
cwd
|
|
8994
|
+
});
|
|
8995
|
+
if (!result || !result.results || result.results.length === 0) {
|
|
8996
|
+
return null;
|
|
8997
|
+
}
|
|
8998
|
+
const match2 = result.results[0];
|
|
8999
|
+
return {
|
|
9000
|
+
startLine: match2.lines[0],
|
|
9001
|
+
// 1-indexed
|
|
9002
|
+
endLine: match2.lines[1],
|
|
9003
|
+
// 1-indexed
|
|
9004
|
+
code: match2.code,
|
|
9005
|
+
nodeType: match2.node_type,
|
|
9006
|
+
file: match2.file
|
|
9007
|
+
};
|
|
9008
|
+
} catch (error) {
|
|
9009
|
+
if (process.env.DEBUG === "1") {
|
|
9010
|
+
console.error(`[SymbolEdit] findSymbol error for "${symbolName}" in ${filePath}: ${error.message}`);
|
|
9011
|
+
}
|
|
9012
|
+
return null;
|
|
9013
|
+
}
|
|
9014
|
+
}
|
|
9015
|
+
async function findAllSymbols(filePath, symbolName, cwd) {
|
|
9016
|
+
try {
|
|
9017
|
+
const result = await extract({
|
|
9018
|
+
files: [`${filePath}#${symbolName}`],
|
|
9019
|
+
format: "json",
|
|
9020
|
+
json: true,
|
|
9021
|
+
cwd
|
|
9022
|
+
});
|
|
9023
|
+
if (!result || !result.results || result.results.length === 0) {
|
|
9024
|
+
return [];
|
|
9025
|
+
}
|
|
9026
|
+
return result.results.map((match2) => ({
|
|
9027
|
+
startLine: match2.lines[0],
|
|
9028
|
+
endLine: match2.lines[1],
|
|
9029
|
+
code: match2.code,
|
|
9030
|
+
nodeType: match2.node_type,
|
|
9031
|
+
file: match2.file,
|
|
9032
|
+
qualifiedName: match2.symbol_signature || symbolName
|
|
9033
|
+
}));
|
|
9034
|
+
} catch (error) {
|
|
9035
|
+
if (process.env.DEBUG === "1") {
|
|
9036
|
+
console.error(`[SymbolEdit] findAllSymbols error for "${symbolName}" in ${filePath}: ${error.message}`);
|
|
9037
|
+
}
|
|
9038
|
+
return [];
|
|
9039
|
+
}
|
|
9040
|
+
}
|
|
9041
|
+
function detectBaseIndent(code) {
|
|
9042
|
+
const lines = code.split("\n");
|
|
9043
|
+
for (const line of lines) {
|
|
9044
|
+
if (line.trim().length > 0) {
|
|
9045
|
+
const match2 = line.match(/^(\s*)/);
|
|
9046
|
+
return match2 ? match2[1] : "";
|
|
9047
|
+
}
|
|
9048
|
+
}
|
|
9049
|
+
return "";
|
|
9050
|
+
}
|
|
9051
|
+
function reindent(newContent, targetIndent) {
|
|
9052
|
+
const lines = newContent.split("\n");
|
|
9053
|
+
const sourceIndent = detectBaseIndent(newContent);
|
|
9054
|
+
return lines.map((line) => {
|
|
9055
|
+
if (line.trim().length === 0) {
|
|
9056
|
+
return "";
|
|
9057
|
+
}
|
|
9058
|
+
if (line.startsWith(sourceIndent)) {
|
|
9059
|
+
return targetIndent + line.slice(sourceIndent.length);
|
|
9060
|
+
}
|
|
9061
|
+
return line;
|
|
9062
|
+
}).join("\n");
|
|
9063
|
+
}
|
|
9064
|
+
var init_symbolEdit = __esm({
|
|
9065
|
+
"src/tools/symbolEdit.js"() {
|
|
9066
|
+
"use strict";
|
|
9067
|
+
init_extract();
|
|
9068
|
+
}
|
|
9069
|
+
});
|
|
9070
|
+
|
|
9071
|
+
// src/tools/hashline.js
|
|
9072
|
+
function computeLineHash(line) {
|
|
9073
|
+
const stripped = (line || "").replace(/\s+/g, "");
|
|
9074
|
+
let h = 5381;
|
|
9075
|
+
for (let i = 0; i < stripped.length; i++) {
|
|
9076
|
+
h = (h << 5) + h + stripped.charCodeAt(i) & 4294967295;
|
|
9077
|
+
}
|
|
9078
|
+
return ((h >>> 0) % 256).toString(16).padStart(2, "0");
|
|
9079
|
+
}
|
|
9080
|
+
function parseLineRef(ref2) {
|
|
9081
|
+
if (ref2 === void 0 || ref2 === null) return null;
|
|
9082
|
+
const str = String(ref2).trim();
|
|
9083
|
+
if (!str) return null;
|
|
9084
|
+
const hashMatch = str.match(/^(\d+):([0-9a-fA-F]{2})$/);
|
|
9085
|
+
if (hashMatch) {
|
|
9086
|
+
const line = parseInt(hashMatch[1], 10);
|
|
9087
|
+
if (line < 1 || !isFinite(line)) return null;
|
|
9088
|
+
return { line, hash: hashMatch[2].toLowerCase() };
|
|
9089
|
+
}
|
|
9090
|
+
const lineMatch = str.match(/^(\d+)$/);
|
|
9091
|
+
if (lineMatch) {
|
|
9092
|
+
const line = parseInt(lineMatch[1], 10);
|
|
9093
|
+
if (line < 1 || !isFinite(line)) return null;
|
|
9094
|
+
return { line, hash: null };
|
|
9095
|
+
}
|
|
9096
|
+
return null;
|
|
9097
|
+
}
|
|
9098
|
+
function validateLineHash(lineNum, hash, fileLines) {
|
|
9099
|
+
const idx = lineNum - 1;
|
|
9100
|
+
if (idx < 0 || idx >= fileLines.length) {
|
|
9101
|
+
return { valid: false, actualHash: "", actualContent: "" };
|
|
9102
|
+
}
|
|
9103
|
+
const actualContent = fileLines[idx];
|
|
9104
|
+
const actualHash = computeLineHash(actualContent);
|
|
9105
|
+
return {
|
|
9106
|
+
valid: actualHash === hash.toLowerCase(),
|
|
9107
|
+
actualHash,
|
|
9108
|
+
actualContent
|
|
9109
|
+
};
|
|
9110
|
+
}
|
|
9111
|
+
function annotateOutputWithHashes(output) {
|
|
9112
|
+
if (!output || typeof output !== "string") return output;
|
|
9113
|
+
return output.split("\n").map((line) => {
|
|
9114
|
+
const cleanLine = line.endsWith("\r") ? line.slice(0, -1) : line;
|
|
9115
|
+
const match2 = cleanLine.match(/^(\s*)(\d+)(\s*\|)(.*)$/);
|
|
9116
|
+
if (!match2) return line;
|
|
9117
|
+
const [, prefix, lineNum, pipeSection, content] = match2;
|
|
9118
|
+
const hash = computeLineHash(content);
|
|
9119
|
+
const cr = line.endsWith("\r") ? "\r" : "";
|
|
9120
|
+
return `${prefix}${lineNum}:${hash}${pipeSection}${content}${cr}`;
|
|
9121
|
+
}).join("\n");
|
|
9122
|
+
}
|
|
9123
|
+
function stripHashlinePrefixes(text) {
|
|
9124
|
+
if (!text || typeof text !== "string") return { cleaned: text || "", stripped: false };
|
|
9125
|
+
const lines = text.split("\n");
|
|
9126
|
+
if (lines.length === 0) return { cleaned: "", stripped: false };
|
|
9127
|
+
const nonEmptyLines = lines.filter((l) => l.trim().length > 0);
|
|
9128
|
+
if (nonEmptyLines.length === 0) return { cleaned: text, stripped: false };
|
|
9129
|
+
const prefixPattern = /^\s*\d+(?::[0-9a-fA-F]{2})?\s*\|\s?/;
|
|
9130
|
+
const matchCount = nonEmptyLines.filter((l) => prefixPattern.test(l)).length;
|
|
9131
|
+
if (matchCount / nonEmptyLines.length <= 0.5) {
|
|
9132
|
+
return { cleaned: text, stripped: false };
|
|
9133
|
+
}
|
|
9134
|
+
const cleaned = lines.map((line) => {
|
|
9135
|
+
if (line.trim().length === 0) return line;
|
|
9136
|
+
return line.replace(prefixPattern, "");
|
|
9137
|
+
}).join("\n");
|
|
9138
|
+
return { cleaned, stripped: true };
|
|
9139
|
+
}
|
|
9140
|
+
var init_hashline = __esm({
|
|
9141
|
+
"src/tools/hashline.js"() {
|
|
9142
|
+
"use strict";
|
|
9143
|
+
}
|
|
9144
|
+
});
|
|
9145
|
+
|
|
9146
|
+
// src/tools/lineEditHeuristics.js
|
|
9147
|
+
function stripEchoedBoundaries(newStr, fileLines, startLine, endLine, position) {
|
|
9148
|
+
const modifications = [];
|
|
9149
|
+
let lines = newStr.split("\n");
|
|
9150
|
+
if (lines.length === 0) return { result: newStr, modifications };
|
|
9151
|
+
if (position === "after") {
|
|
9152
|
+
const anchorIdx = startLine - 1;
|
|
9153
|
+
if (anchorIdx >= 0 && anchorIdx < fileLines.length) {
|
|
9154
|
+
const anchorTrimmed = fileLines[anchorIdx].trim();
|
|
9155
|
+
if (anchorTrimmed.length > 0 && lines.length > 0 && lines[0].trim() === anchorTrimmed) {
|
|
9156
|
+
lines = lines.slice(1);
|
|
9157
|
+
modifications.push("stripped echoed anchor line (insert-after)");
|
|
9158
|
+
}
|
|
9159
|
+
}
|
|
9160
|
+
} else if (position === "before") {
|
|
9161
|
+
const anchorIdx = startLine - 1;
|
|
9162
|
+
if (anchorIdx >= 0 && anchorIdx < fileLines.length) {
|
|
9163
|
+
const anchorTrimmed = fileLines[anchorIdx].trim();
|
|
9164
|
+
if (anchorTrimmed.length > 0 && lines.length > 0 && lines[lines.length - 1].trim() === anchorTrimmed) {
|
|
9165
|
+
lines = lines.slice(0, -1);
|
|
9166
|
+
modifications.push("stripped echoed anchor line (insert-before)");
|
|
9167
|
+
}
|
|
9168
|
+
}
|
|
9169
|
+
} else {
|
|
9170
|
+
const beforeIdx = startLine - 2;
|
|
9171
|
+
if (beforeIdx >= 0 && beforeIdx < fileLines.length) {
|
|
9172
|
+
const beforeTrimmed = fileLines[beforeIdx].trim();
|
|
9173
|
+
if (beforeTrimmed.length > 0 && lines.length > 0 && lines[0].trim() === beforeTrimmed) {
|
|
9174
|
+
lines = lines.slice(1);
|
|
9175
|
+
modifications.push("stripped echoed line before range");
|
|
9176
|
+
}
|
|
9177
|
+
}
|
|
9178
|
+
const afterIdx = endLine;
|
|
9179
|
+
if (afterIdx >= 0 && afterIdx < fileLines.length) {
|
|
9180
|
+
const afterTrimmed = fileLines[afterIdx].trim();
|
|
9181
|
+
if (afterTrimmed.length > 0 && lines.length > 0 && lines[lines.length - 1].trim() === afterTrimmed) {
|
|
9182
|
+
lines = lines.slice(0, -1);
|
|
9183
|
+
modifications.push("stripped echoed line after range");
|
|
9184
|
+
}
|
|
9185
|
+
}
|
|
9186
|
+
}
|
|
9187
|
+
return { result: lines.join("\n"), modifications };
|
|
9188
|
+
}
|
|
9189
|
+
function restoreIndentation(newStr, originalLines) {
|
|
9190
|
+
const modifications = [];
|
|
9191
|
+
if (!newStr || !originalLines || originalLines.length === 0) {
|
|
9192
|
+
return { result: newStr || "", modifications };
|
|
9193
|
+
}
|
|
9194
|
+
const originalCode = originalLines.join("\n");
|
|
9195
|
+
const targetIndent = detectBaseIndent(originalCode);
|
|
9196
|
+
const newIndent = detectBaseIndent(newStr);
|
|
9197
|
+
if (targetIndent !== newIndent) {
|
|
9198
|
+
const reindented = reindent(newStr, targetIndent);
|
|
9199
|
+
if (reindented !== newStr) {
|
|
9200
|
+
modifications.push(`reindented from "${newIndent}" to "${targetIndent}"`);
|
|
9201
|
+
return { result: reindented, modifications };
|
|
9202
|
+
}
|
|
9203
|
+
}
|
|
9204
|
+
return { result: newStr, modifications };
|
|
9205
|
+
}
|
|
9206
|
+
function cleanNewString(newStr, fileLines, startLine, endLine, position) {
|
|
9207
|
+
const modifications = [];
|
|
9208
|
+
if (!newStr && newStr !== "") return { cleaned: "", modifications };
|
|
9209
|
+
const { cleaned: afterPrefixes, stripped } = stripHashlinePrefixes(newStr);
|
|
9210
|
+
if (stripped) modifications.push("stripped line-number prefixes");
|
|
9211
|
+
const { result: afterEchoes, modifications: echoMods } = stripEchoedBoundaries(
|
|
9212
|
+
afterPrefixes,
|
|
9213
|
+
fileLines,
|
|
9214
|
+
startLine,
|
|
9215
|
+
endLine,
|
|
9216
|
+
position
|
|
9217
|
+
);
|
|
9218
|
+
modifications.push(...echoMods);
|
|
9219
|
+
if (!position) {
|
|
9220
|
+
const originalLines = fileLines.slice(startLine - 1, endLine);
|
|
9221
|
+
const { result: afterIndent, modifications: indentMods } = restoreIndentation(afterEchoes, originalLines);
|
|
9222
|
+
modifications.push(...indentMods);
|
|
9223
|
+
return { cleaned: afterIndent, modifications };
|
|
9224
|
+
}
|
|
9225
|
+
return { cleaned: afterEchoes, modifications };
|
|
9226
|
+
}
|
|
9227
|
+
var init_lineEditHeuristics = __esm({
|
|
9228
|
+
"src/tools/lineEditHeuristics.js"() {
|
|
9229
|
+
"use strict";
|
|
9230
|
+
init_symbolEdit();
|
|
9231
|
+
init_hashline();
|
|
9232
|
+
}
|
|
9233
|
+
});
|
|
9234
|
+
|
|
8838
9235
|
// src/tools/edit.js
|
|
8839
9236
|
import { tool } from "ai";
|
|
8840
9237
|
import { promises as fs6 } from "fs";
|
|
@@ -8862,29 +9259,204 @@ function parseFileToolOptions(options = {}) {
|
|
|
8862
9259
|
workspaceRoot: options.workspaceRoot || options.cwd || allowedFolders.length > 0 && allowedFolders[0] || process.cwd()
|
|
8863
9260
|
};
|
|
8864
9261
|
}
|
|
9262
|
+
async function handleSymbolEdit({ resolvedPath, file_path, symbol, new_string, position, debug, cwd, fileTracker }) {
|
|
9263
|
+
if (typeof symbol !== "string" || symbol.trim() === "") {
|
|
9264
|
+
return 'Error editing file: Invalid symbol - must be a non-empty string. Provide the name of a function, class, method, or other named code definition (e.g. "myFunction" or "MyClass.myMethod"). To edit by text matching instead, use old_string + new_string.';
|
|
9265
|
+
}
|
|
9266
|
+
if (position !== void 0 && position !== null && position !== "before" && position !== "after") {
|
|
9267
|
+
return 'Error editing file: Invalid position - must be "before" or "after". Use position="before" to insert code above the symbol, or position="after" to insert code below it. Omit position entirely to replace the symbol with new_string.';
|
|
9268
|
+
}
|
|
9269
|
+
const allMatches = await findAllSymbols(resolvedPath, symbol, cwd || process.cwd());
|
|
9270
|
+
if (allMatches.length === 0) {
|
|
9271
|
+
return `Error editing file: Symbol "${symbol}" not found in ${file_path}. Verify the symbol name matches a top-level function, class, method, or other named definition exactly as declared in the source. Use 'search' or 'extract' to inspect the file and find the correct symbol name. Alternatively, use old_string + new_string for text-based editing instead.`;
|
|
9272
|
+
}
|
|
9273
|
+
if (allMatches.length > 1) {
|
|
9274
|
+
const suggestions = allMatches.map(
|
|
9275
|
+
(m) => ` - ${m.qualifiedName} (${m.nodeType}, line ${m.startLine})`
|
|
9276
|
+
).join("\n");
|
|
9277
|
+
return `Error editing ${file_path}: Found ${allMatches.length} symbols named "${symbol}". Use a qualified name to specify which one:
|
|
9278
|
+
${suggestions}
|
|
9279
|
+
|
|
9280
|
+
Example: <edit><file_path>${file_path}</file_path><symbol>${allMatches[0].qualifiedName}</symbol><new_string>...</new_string></edit>`;
|
|
9281
|
+
}
|
|
9282
|
+
const symbolInfo = allMatches[0];
|
|
9283
|
+
if (fileTracker) {
|
|
9284
|
+
const check = fileTracker.checkSymbolContent(resolvedPath, symbol, symbolInfo.code);
|
|
9285
|
+
if (!check.ok && check.reason === "stale") {
|
|
9286
|
+
return `Error editing ${file_path}: Symbol "${symbol}" has changed since you last read it. Use extract to re-read the current content, then retry.
|
|
9287
|
+
|
|
9288
|
+
Example: <extract><targets>${file_path}#${symbol}</targets></extract>`;
|
|
9289
|
+
}
|
|
9290
|
+
}
|
|
9291
|
+
const content = await fs6.readFile(resolvedPath, "utf-8");
|
|
9292
|
+
const lines = content.split("\n");
|
|
9293
|
+
if (position) {
|
|
9294
|
+
const refIndent = detectBaseIndent(symbolInfo.code);
|
|
9295
|
+
const reindented = reindent(new_string, refIndent);
|
|
9296
|
+
const newLines = reindented.split("\n");
|
|
9297
|
+
if (position === "after") {
|
|
9298
|
+
lines.splice(symbolInfo.endLine, 0, "", ...newLines);
|
|
9299
|
+
} else {
|
|
9300
|
+
lines.splice(symbolInfo.startLine - 1, 0, ...newLines, "");
|
|
9301
|
+
}
|
|
9302
|
+
await fs6.writeFile(resolvedPath, lines.join("\n"), "utf-8");
|
|
9303
|
+
if (fileTracker) {
|
|
9304
|
+
const updated = await findSymbol(resolvedPath, symbol, cwd || process.cwd());
|
|
9305
|
+
if (updated) {
|
|
9306
|
+
fileTracker.trackSymbolAfterWrite(resolvedPath, symbol, updated.code, updated.startLine, updated.endLine);
|
|
9307
|
+
}
|
|
9308
|
+
fileTracker.markFileSeen(resolvedPath);
|
|
9309
|
+
}
|
|
9310
|
+
const insertLine = position === "after" ? symbolInfo.endLine + 1 : symbolInfo.startLine;
|
|
9311
|
+
if (debug) {
|
|
9312
|
+
console.error(`[Edit] Successfully inserted ${newLines.length} lines ${position} "${symbol}" at line ${insertLine} in ${resolvedPath}`);
|
|
9313
|
+
}
|
|
9314
|
+
return `Successfully inserted ${newLines.length} lines ${position} symbol "${symbol}" in ${file_path} (at line ${insertLine})`;
|
|
9315
|
+
} else {
|
|
9316
|
+
const originalIndent = detectBaseIndent(symbolInfo.code);
|
|
9317
|
+
const reindented = reindent(new_string, originalIndent);
|
|
9318
|
+
const newLines = reindented.split("\n");
|
|
9319
|
+
lines.splice(symbolInfo.startLine - 1, symbolInfo.endLine - symbolInfo.startLine + 1, ...newLines);
|
|
9320
|
+
await fs6.writeFile(resolvedPath, lines.join("\n"), "utf-8");
|
|
9321
|
+
if (fileTracker) {
|
|
9322
|
+
const updated = await findSymbol(resolvedPath, symbol, cwd || process.cwd());
|
|
9323
|
+
if (updated) {
|
|
9324
|
+
fileTracker.trackSymbolAfterWrite(resolvedPath, symbol, updated.code, updated.startLine, updated.endLine);
|
|
9325
|
+
}
|
|
9326
|
+
fileTracker.markFileSeen(resolvedPath);
|
|
9327
|
+
}
|
|
9328
|
+
if (debug) {
|
|
9329
|
+
console.error(`[Edit] Successfully replaced symbol "${symbol}" in ${resolvedPath} (lines ${symbolInfo.startLine}-${symbolInfo.endLine})`);
|
|
9330
|
+
}
|
|
9331
|
+
return `Successfully replaced symbol "${symbol}" in ${file_path} (was lines ${symbolInfo.startLine}-${symbolInfo.endLine}, now ${newLines.length} lines)`;
|
|
9332
|
+
}
|
|
9333
|
+
}
|
|
9334
|
+
function buildLineEditResponse(file_path, startLine, endLine, newLineCount, updatedLines, insertOffset, action, heuristicMods) {
|
|
9335
|
+
const contextBefore = 1;
|
|
9336
|
+
const contextAfter = 1;
|
|
9337
|
+
const contextStart = Math.max(0, insertOffset - contextBefore);
|
|
9338
|
+
const contextEnd = Math.min(updatedLines.length, insertOffset + newLineCount + contextAfter);
|
|
9339
|
+
let context = "Context:\n";
|
|
9340
|
+
for (let i = contextStart; i < contextEnd; i++) {
|
|
9341
|
+
const lineNum = i + 1;
|
|
9342
|
+
const hash = computeLineHash(updatedLines[i]);
|
|
9343
|
+
const isNew = i >= insertOffset && i < insertOffset + newLineCount;
|
|
9344
|
+
const marker = isNew ? ">" : " ";
|
|
9345
|
+
context += `${marker} ${lineNum}:${hash} | ${updatedLines[i]}
|
|
9346
|
+
`;
|
|
9347
|
+
}
|
|
9348
|
+
let msg = `Successfully edited ${file_path} (${action})`;
|
|
9349
|
+
if (heuristicMods.length > 0) {
|
|
9350
|
+
msg += ` [auto-corrected: ${heuristicMods.join(", ")}]`;
|
|
9351
|
+
}
|
|
9352
|
+
msg += "\n" + context;
|
|
9353
|
+
return msg;
|
|
9354
|
+
}
|
|
9355
|
+
async function handleLineEdit({ resolvedPath, file_path, start_line, end_line, new_string, position, debug, fileTracker }) {
|
|
9356
|
+
const startRef = parseLineRef(start_line);
|
|
9357
|
+
if (!startRef) {
|
|
9358
|
+
return `Error editing file: Invalid start_line '${start_line}'. Use a line number (e.g. "42") or line:hash (e.g. "42:ab"). Line numbers are 1-indexed.`;
|
|
9359
|
+
}
|
|
9360
|
+
let endRef = null;
|
|
9361
|
+
if (end_line !== void 0 && end_line !== null) {
|
|
9362
|
+
endRef = parseLineRef(end_line);
|
|
9363
|
+
if (!endRef) {
|
|
9364
|
+
return `Error editing file: Invalid end_line '${end_line}'. Use a line number (e.g. "55") or line:hash (e.g. "55:cd"). Must be >= start_line.`;
|
|
9365
|
+
}
|
|
9366
|
+
}
|
|
9367
|
+
const startLine = startRef.line;
|
|
9368
|
+
const endLine = endRef ? endRef.line : startLine;
|
|
9369
|
+
if (endLine < startLine) {
|
|
9370
|
+
return `Error editing file: end_line (${endLine}) must be >= start_line (${startLine}).`;
|
|
9371
|
+
}
|
|
9372
|
+
if (position !== void 0 && position !== null && position !== "before" && position !== "after") {
|
|
9373
|
+
return 'Error editing file: Invalid position - must be "before" or "after". Use position="before" to insert before the line, or position="after" to insert after it.';
|
|
9374
|
+
}
|
|
9375
|
+
const content = await fs6.readFile(resolvedPath, "utf-8");
|
|
9376
|
+
const fileLines = content.split("\n");
|
|
9377
|
+
if (startLine > fileLines.length) {
|
|
9378
|
+
return `Error editing file: Line ${startLine} is beyond file length (${fileLines.length} lines). Use 'extract' to read the current file content.`;
|
|
9379
|
+
}
|
|
9380
|
+
if (endLine > fileLines.length) {
|
|
9381
|
+
return `Error editing file: Line ${endLine} is beyond file length (${fileLines.length} lines). Use 'extract' to read the current file content.`;
|
|
9382
|
+
}
|
|
9383
|
+
if (startRef.hash) {
|
|
9384
|
+
const validation = validateLineHash(startLine, startRef.hash, fileLines);
|
|
9385
|
+
if (!validation.valid) {
|
|
9386
|
+
return `Error editing file: Line ${startLine} has changed since last read. Expected hash '${startRef.hash}' but content is now: ${startLine}:${validation.actualHash} | ${validation.actualContent}. Use '${startLine}:${validation.actualHash}' instead.`;
|
|
9387
|
+
}
|
|
9388
|
+
}
|
|
9389
|
+
if (endRef && endRef.hash) {
|
|
9390
|
+
const validation = validateLineHash(endLine, endRef.hash, fileLines);
|
|
9391
|
+
if (!validation.valid) {
|
|
9392
|
+
return `Error editing file: Line ${endLine} has changed since last read. Expected hash '${endRef.hash}' but content is now: ${endLine}:${validation.actualHash} | ${validation.actualContent}. Use '${endLine}:${validation.actualHash}' instead.`;
|
|
9393
|
+
}
|
|
9394
|
+
}
|
|
9395
|
+
const { cleaned, modifications } = cleanNewString(new_string, fileLines, startLine, endLine, position);
|
|
9396
|
+
if (debug) {
|
|
9397
|
+
if (modifications.length > 0) {
|
|
9398
|
+
console.error(`[Edit] Heuristic corrections: ${modifications.join(", ")}`);
|
|
9399
|
+
}
|
|
9400
|
+
}
|
|
9401
|
+
const newLines = cleaned === "" ? [] : cleaned.split("\n");
|
|
9402
|
+
if (position === "after") {
|
|
9403
|
+
fileLines.splice(startLine, 0, ...newLines);
|
|
9404
|
+
await fs6.writeFile(resolvedPath, fileLines.join("\n"), "utf-8");
|
|
9405
|
+
if (fileTracker) await fileTracker.trackFileAfterWrite(resolvedPath);
|
|
9406
|
+
const action = `${newLines.length} line${newLines.length !== 1 ? "s" : ""} inserted after line ${startLine}`;
|
|
9407
|
+
return buildLineEditResponse(file_path, startLine, startLine, newLines.length, fileLines, startLine, action, modifications);
|
|
9408
|
+
} else if (position === "before") {
|
|
9409
|
+
fileLines.splice(startLine - 1, 0, ...newLines);
|
|
9410
|
+
await fs6.writeFile(resolvedPath, fileLines.join("\n"), "utf-8");
|
|
9411
|
+
if (fileTracker) await fileTracker.trackFileAfterWrite(resolvedPath);
|
|
9412
|
+
const action = `${newLines.length} line${newLines.length !== 1 ? "s" : ""} inserted before line ${startLine}`;
|
|
9413
|
+
return buildLineEditResponse(file_path, startLine, startLine, newLines.length, fileLines, startLine - 1, action, modifications);
|
|
9414
|
+
} else {
|
|
9415
|
+
const replacedCount = endLine - startLine + 1;
|
|
9416
|
+
fileLines.splice(startLine - 1, replacedCount, ...newLines);
|
|
9417
|
+
await fs6.writeFile(resolvedPath, fileLines.join("\n"), "utf-8");
|
|
9418
|
+
if (fileTracker) await fileTracker.trackFileAfterWrite(resolvedPath);
|
|
9419
|
+
let action;
|
|
9420
|
+
if (newLines.length === 0) {
|
|
9421
|
+
action = `${replacedCount} line${replacedCount !== 1 ? "s" : ""} deleted (lines ${startLine}-${endLine})`;
|
|
9422
|
+
} else if (startLine === endLine) {
|
|
9423
|
+
action = `line ${startLine} replaced with ${newLines.length} line${newLines.length !== 1 ? "s" : ""}`;
|
|
9424
|
+
} else {
|
|
9425
|
+
action = `lines ${startLine}-${endLine} replaced with ${newLines.length} line${newLines.length !== 1 ? "s" : ""}`;
|
|
9426
|
+
}
|
|
9427
|
+
return buildLineEditResponse(file_path, startLine, endLine, newLines.length, fileLines, startLine - 1, action, modifications);
|
|
9428
|
+
}
|
|
9429
|
+
}
|
|
8865
9430
|
var editTool, createTool, editSchema, createSchema, editDescription, createDescription, editToolDefinition, createToolDefinition;
|
|
8866
9431
|
var init_edit = __esm({
|
|
8867
9432
|
"src/tools/edit.js"() {
|
|
8868
9433
|
"use strict";
|
|
8869
9434
|
init_path_validation();
|
|
9435
|
+
init_fuzzyMatch();
|
|
9436
|
+
init_symbolEdit();
|
|
9437
|
+
init_hashline();
|
|
9438
|
+
init_lineEditHeuristics();
|
|
8870
9439
|
editTool = (options = {}) => {
|
|
8871
9440
|
const { debug, allowedFolders, cwd, workspaceRoot } = parseFileToolOptions(options);
|
|
8872
9441
|
return tool({
|
|
8873
9442
|
name: "edit",
|
|
8874
|
-
description: `Edit files using
|
|
9443
|
+
description: `Edit files using text replacement, AST-aware symbol operations, or line-targeted editing.
|
|
8875
9444
|
|
|
8876
|
-
|
|
9445
|
+
Modes:
|
|
9446
|
+
1. Text edit: Provide old_string + new_string to find and replace text (with fuzzy matching fallback)
|
|
9447
|
+
2. Symbol replace: Provide symbol + new_string to replace an entire function/class/method by name
|
|
9448
|
+
3. Symbol insert: Provide symbol + new_string + position to insert code before/after a symbol
|
|
9449
|
+
4. Line-targeted edit: Provide start_line + new_string to edit by line number (from extract/search output)
|
|
8877
9450
|
|
|
8878
9451
|
Parameters:
|
|
8879
9452
|
- file_path: Path to the file to edit (absolute or relative)
|
|
8880
|
-
-
|
|
8881
|
-
-
|
|
8882
|
-
- replace_all: (optional) Replace all occurrences
|
|
8883
|
-
|
|
8884
|
-
|
|
8885
|
-
-
|
|
8886
|
-
-
|
|
8887
|
-
- Use larger context around the string to ensure uniqueness when needed`,
|
|
9453
|
+
- new_string: Replacement text or new code content
|
|
9454
|
+
- old_string: (optional) Text to find and replace. If omitted, symbol or start_line must be provided.
|
|
9455
|
+
- replace_all: (optional) Replace all occurrences (text mode only)
|
|
9456
|
+
- symbol: (optional) Symbol name for AST-aware editing (e.g. "myFunction", "MyClass.myMethod")
|
|
9457
|
+
- position: (optional) "before" or "after" \u2014 insert code near a symbol or line instead of replacing it
|
|
9458
|
+
- start_line: (optional) Line reference (e.g. "42" or "42:ab") for line-targeted editing
|
|
9459
|
+
- end_line: (optional) End of line range, inclusive (e.g. "55" or "55:cd")`,
|
|
8888
9460
|
inputSchema: {
|
|
8889
9461
|
type: "object",
|
|
8890
9462
|
properties: {
|
|
@@ -8894,30 +9466,44 @@ Important:
|
|
|
8894
9466
|
},
|
|
8895
9467
|
old_string: {
|
|
8896
9468
|
type: "string",
|
|
8897
|
-
description: "
|
|
9469
|
+
description: "Text to find and replace (for text-based editing)"
|
|
8898
9470
|
},
|
|
8899
9471
|
new_string: {
|
|
8900
9472
|
type: "string",
|
|
8901
|
-
description: "
|
|
9473
|
+
description: "Replacement text or new code content"
|
|
8902
9474
|
},
|
|
8903
9475
|
replace_all: {
|
|
8904
9476
|
type: "boolean",
|
|
8905
|
-
description: "Replace all occurrences (default: false)",
|
|
9477
|
+
description: "Replace all occurrences (default: false, text mode only)",
|
|
8906
9478
|
default: false
|
|
9479
|
+
},
|
|
9480
|
+
symbol: {
|
|
9481
|
+
type: "string",
|
|
9482
|
+
description: 'Symbol name for AST-aware editing (e.g. "myFunction", "MyClass.myMethod")'
|
|
9483
|
+
},
|
|
9484
|
+
position: {
|
|
9485
|
+
type: "string",
|
|
9486
|
+
enum: ["before", "after"],
|
|
9487
|
+
description: "Insert before/after symbol or line (requires symbol or start_line, omit to replace)"
|
|
9488
|
+
},
|
|
9489
|
+
start_line: {
|
|
9490
|
+
type: "string",
|
|
9491
|
+
description: 'Line reference for line-targeted editing (e.g. "42" or "42:ab" with hash)'
|
|
9492
|
+
},
|
|
9493
|
+
end_line: {
|
|
9494
|
+
type: "string",
|
|
9495
|
+
description: 'End of line range, inclusive (e.g. "55" or "55:cd"). Defaults to start_line.'
|
|
8907
9496
|
}
|
|
8908
9497
|
},
|
|
8909
|
-
required: ["file_path", "
|
|
9498
|
+
required: ["file_path", "new_string"]
|
|
8910
9499
|
},
|
|
8911
|
-
execute: async ({ file_path, old_string, new_string, replace_all = false }) => {
|
|
9500
|
+
execute: async ({ file_path, old_string, new_string, replace_all = false, symbol, position, start_line, end_line }) => {
|
|
8912
9501
|
try {
|
|
8913
9502
|
if (!file_path || typeof file_path !== "string" || file_path.trim() === "") {
|
|
8914
|
-
return `Error editing file: Invalid file_path - must be a non-empty string
|
|
8915
|
-
}
|
|
8916
|
-
if (old_string === void 0 || old_string === null || typeof old_string !== "string") {
|
|
8917
|
-
return `Error editing file: Invalid old_string - must be a string`;
|
|
9503
|
+
return `Error editing file: Invalid file_path - must be a non-empty string. Provide an absolute path or a path relative to the working directory (e.g. "src/main.js").`;
|
|
8918
9504
|
}
|
|
8919
9505
|
if (new_string === void 0 || new_string === null || typeof new_string !== "string") {
|
|
8920
|
-
return `Error editing file: Invalid new_string - must be a string
|
|
9506
|
+
return `Error editing file: Invalid new_string - must be a string. Provide the replacement content as a string value (empty string "" is valid for deletions).`;
|
|
8921
9507
|
}
|
|
8922
9508
|
const resolvedPath = isAbsolute(file_path) ? file_path : resolve(cwd || process.cwd(), file_path);
|
|
8923
9509
|
if (debug) {
|
|
@@ -8925,34 +9511,64 @@ Important:
|
|
|
8925
9511
|
}
|
|
8926
9512
|
if (!isPathAllowed(resolvedPath, allowedFolders)) {
|
|
8927
9513
|
const relativePath = toRelativePath(resolvedPath, workspaceRoot);
|
|
8928
|
-
return `Error editing file: Permission denied - ${relativePath} is outside allowed directories
|
|
9514
|
+
return `Error editing file: Permission denied - ${relativePath} is outside allowed directories. Use a file path within the project workspace.`;
|
|
8929
9515
|
}
|
|
8930
9516
|
if (!existsSync(resolvedPath)) {
|
|
8931
|
-
return `Error editing file: File not found - ${file_path}
|
|
9517
|
+
return `Error editing file: File not found - ${file_path}. Verify the path is correct and the file exists. Use 'search' to find files by name, or 'create' to make a new file.`;
|
|
9518
|
+
}
|
|
9519
|
+
if (options.fileTracker && !options.fileTracker.isFileSeen(resolvedPath)) {
|
|
9520
|
+
const displayPath = toRelativePath(resolvedPath, workspaceRoot);
|
|
9521
|
+
return `Error editing ${displayPath}: This file has not been read yet in this session. Use 'extract' to read the file first, then retry your edit. This ensures you are working with the current file content.
|
|
9522
|
+
|
|
9523
|
+
Example: <extract><targets>${displayPath}</targets></extract>`;
|
|
9524
|
+
}
|
|
9525
|
+
if (symbol !== void 0 && symbol !== null) {
|
|
9526
|
+
return await handleSymbolEdit({ resolvedPath, file_path, symbol, new_string, position, debug, cwd, fileTracker: options.fileTracker });
|
|
9527
|
+
}
|
|
9528
|
+
if (start_line !== void 0 && start_line !== null) {
|
|
9529
|
+
return await handleLineEdit({ resolvedPath, file_path, start_line, end_line, new_string, position, debug, fileTracker: options.fileTracker });
|
|
9530
|
+
}
|
|
9531
|
+
if (old_string === void 0 || old_string === null) {
|
|
9532
|
+
return 'Error editing file: Must provide either old_string (for text edit), symbol (for AST-aware edit), or start_line (for line-targeted edit). For text editing: set old_string to the exact text to find and new_string to its replacement. For symbol editing: set symbol to a function/class/method name (e.g. "myFunction"). For line-targeted editing: set start_line to a line number from extract/search output (e.g. "42" or "42:ab").';
|
|
9533
|
+
}
|
|
9534
|
+
if (typeof old_string !== "string") {
|
|
9535
|
+
return `Error editing file: Invalid old_string - must be a string. Provide the exact text to find in the file, or use the symbol parameter instead for AST-aware editing by name.`;
|
|
8932
9536
|
}
|
|
8933
9537
|
const content = await fs6.readFile(resolvedPath, "utf-8");
|
|
9538
|
+
let matchTarget = old_string;
|
|
9539
|
+
let matchStrategy = "exact";
|
|
8934
9540
|
if (!content.includes(old_string)) {
|
|
8935
|
-
|
|
9541
|
+
const fuzzy = findFuzzyMatch(content, old_string);
|
|
9542
|
+
if (!fuzzy) {
|
|
9543
|
+
return `Error editing file: String not found - the specified old_string was not found in ${file_path}. The text may have changed or differ from what you expected. Try: (1) Use 'search' or 'extract' to read the current file content and copy the exact text. (2) Use the symbol parameter to edit by function/class name instead. (3) Verify the file_path is correct.`;
|
|
9544
|
+
}
|
|
9545
|
+
matchTarget = fuzzy.matchedText;
|
|
9546
|
+
matchStrategy = fuzzy.strategy;
|
|
9547
|
+
if (debug) {
|
|
9548
|
+
console.error(`[Edit] Exact match failed, used ${matchStrategy} matching`);
|
|
9549
|
+
}
|
|
8936
9550
|
}
|
|
8937
|
-
const occurrences = content.split(
|
|
9551
|
+
const occurrences = content.split(matchTarget).length - 1;
|
|
8938
9552
|
if (!replace_all && occurrences > 1) {
|
|
8939
|
-
return `Error editing file: Multiple occurrences found - the old_string appears ${occurrences} times.
|
|
9553
|
+
return `Error editing file: Multiple occurrences found - the old_string appears ${occurrences} times in ${file_path}. To fix: (1) Set replace_all=true to replace all occurrences, or (2) Include more surrounding lines in old_string to make the match unique (add the full line or adjacent lines for context).`;
|
|
8940
9554
|
}
|
|
8941
9555
|
let newContent;
|
|
8942
9556
|
if (replace_all) {
|
|
8943
|
-
newContent = content.replaceAll(
|
|
9557
|
+
newContent = content.replaceAll(matchTarget, new_string);
|
|
8944
9558
|
} else {
|
|
8945
|
-
newContent = content.replace(
|
|
9559
|
+
newContent = content.replace(matchTarget, new_string);
|
|
8946
9560
|
}
|
|
8947
9561
|
if (newContent === content) {
|
|
8948
|
-
return `Error editing file: No changes made - old_string and new_string
|
|
9562
|
+
return `Error editing file: No changes made - the replacement result is identical to the original. Verify that old_string and new_string are actually different. If fuzzy matching was used, the matched text may already equal new_string.`;
|
|
8949
9563
|
}
|
|
8950
9564
|
await fs6.writeFile(resolvedPath, newContent, "utf-8");
|
|
9565
|
+
if (options.fileTracker) await options.fileTracker.trackFileAfterWrite(resolvedPath);
|
|
8951
9566
|
const replacedCount = replace_all ? occurrences : 1;
|
|
8952
9567
|
if (debug) {
|
|
8953
9568
|
console.error(`[Edit] Successfully edited ${resolvedPath}, replaced ${replacedCount} occurrence(s)`);
|
|
8954
9569
|
}
|
|
8955
|
-
|
|
9570
|
+
const strategyNote = matchStrategy !== "exact" ? `, matched via ${matchStrategy}` : "";
|
|
9571
|
+
return `Successfully edited ${file_path} (${replacedCount} replacement${replacedCount !== 1 ? "s" : ""}${strategyNote})`;
|
|
8956
9572
|
} catch (error) {
|
|
8957
9573
|
console.error("[Edit] Error:", error);
|
|
8958
9574
|
return `Error editing file: ${error.message}`;
|
|
@@ -8999,10 +9615,10 @@ Important:
|
|
|
8999
9615
|
execute: async ({ file_path, content, overwrite = false }) => {
|
|
9000
9616
|
try {
|
|
9001
9617
|
if (!file_path || typeof file_path !== "string" || file_path.trim() === "") {
|
|
9002
|
-
return `Error creating file: Invalid file_path - must be a non-empty string
|
|
9618
|
+
return `Error creating file: Invalid file_path - must be a non-empty string. Provide an absolute path or a path relative to the working directory (e.g. "src/newFile.js").`;
|
|
9003
9619
|
}
|
|
9004
9620
|
if (content === void 0 || content === null || typeof content !== "string") {
|
|
9005
|
-
return `Error creating file: Invalid content - must be a string
|
|
9621
|
+
return `Error creating file: Invalid content - must be a string. Provide the file content as a string value (empty string "" is valid for an empty file).`;
|
|
9006
9622
|
}
|
|
9007
9623
|
const resolvedPath = isAbsolute(file_path) ? file_path : resolve(cwd || process.cwd(), file_path);
|
|
9008
9624
|
if (debug) {
|
|
@@ -9010,15 +9626,17 @@ Important:
|
|
|
9010
9626
|
}
|
|
9011
9627
|
if (!isPathAllowed(resolvedPath, allowedFolders)) {
|
|
9012
9628
|
const relativePath = toRelativePath(resolvedPath, workspaceRoot);
|
|
9013
|
-
return `Error creating file: Permission denied - ${relativePath} is outside allowed directories
|
|
9629
|
+
return `Error creating file: Permission denied - ${relativePath} is outside allowed directories. Use a file path within the project workspace.`;
|
|
9014
9630
|
}
|
|
9015
9631
|
if (existsSync(resolvedPath) && !overwrite) {
|
|
9016
9632
|
return `Error creating file: File already exists - ${file_path}. Use overwrite: true to replace it.`;
|
|
9017
9633
|
}
|
|
9634
|
+
const existed = existsSync(resolvedPath);
|
|
9018
9635
|
const dir = dirname(resolvedPath);
|
|
9019
9636
|
await fs6.mkdir(dir, { recursive: true });
|
|
9020
9637
|
await fs6.writeFile(resolvedPath, content, "utf-8");
|
|
9021
|
-
|
|
9638
|
+
if (options.fileTracker) await options.fileTracker.trackFileAfterWrite(resolvedPath);
|
|
9639
|
+
const action = existed && overwrite ? "overwrote" : "created";
|
|
9022
9640
|
const bytes = Buffer.byteLength(content, "utf-8");
|
|
9023
9641
|
if (debug) {
|
|
9024
9642
|
console.error(`[Create] Successfully ${action} ${resolvedPath}`);
|
|
@@ -9040,18 +9658,35 @@ Important:
|
|
|
9040
9658
|
},
|
|
9041
9659
|
old_string: {
|
|
9042
9660
|
type: "string",
|
|
9043
|
-
description: "
|
|
9661
|
+
description: "Text to find and replace (for text-based editing)"
|
|
9044
9662
|
},
|
|
9045
9663
|
new_string: {
|
|
9046
9664
|
type: "string",
|
|
9047
|
-
description: "
|
|
9665
|
+
description: "Replacement text or new code content"
|
|
9048
9666
|
},
|
|
9049
9667
|
replace_all: {
|
|
9050
9668
|
type: "boolean",
|
|
9051
|
-
description: "Replace all occurrences (default: false)"
|
|
9669
|
+
description: "Replace all occurrences (default: false, text mode only)"
|
|
9670
|
+
},
|
|
9671
|
+
symbol: {
|
|
9672
|
+
type: "string",
|
|
9673
|
+
description: 'Symbol name for AST-aware editing (e.g. "myFunction", "MyClass.myMethod")'
|
|
9674
|
+
},
|
|
9675
|
+
position: {
|
|
9676
|
+
type: "string",
|
|
9677
|
+
enum: ["before", "after"],
|
|
9678
|
+
description: "Insert before/after symbol or line (requires symbol or start_line, omit to replace)"
|
|
9679
|
+
},
|
|
9680
|
+
start_line: {
|
|
9681
|
+
type: "string",
|
|
9682
|
+
description: 'Line reference for line-targeted editing (e.g. "42" or "42:ab" with hash)'
|
|
9683
|
+
},
|
|
9684
|
+
end_line: {
|
|
9685
|
+
type: "string",
|
|
9686
|
+
description: 'End of line range, inclusive (e.g. "55" or "55:cd"). Defaults to start_line.'
|
|
9052
9687
|
}
|
|
9053
9688
|
},
|
|
9054
|
-
required: ["file_path", "
|
|
9689
|
+
required: ["file_path", "new_string"]
|
|
9055
9690
|
};
|
|
9056
9691
|
createSchema = {
|
|
9057
9692
|
type: "object",
|
|
@@ -9071,50 +9706,123 @@ Important:
|
|
|
9071
9706
|
},
|
|
9072
9707
|
required: ["file_path", "content"]
|
|
9073
9708
|
};
|
|
9074
|
-
editDescription = "Edit files using
|
|
9709
|
+
editDescription = "Edit files using text replacement, AST-aware symbol operations, or line-targeted editing. Supports fuzzy matching for text edits and optional hash-based integrity verification for line edits.";
|
|
9075
9710
|
createDescription = "Create new files with specified content. Will create parent directories if needed.";
|
|
9076
9711
|
editToolDefinition = `
|
|
9077
9712
|
## edit
|
|
9078
9713
|
Description: ${editDescription}
|
|
9079
9714
|
|
|
9080
|
-
|
|
9081
|
-
- For precise, surgical edits to existing files
|
|
9082
|
-
- When you need to change specific lines or blocks of code
|
|
9083
|
-
- For renaming functions, variables, or updating configuration values
|
|
9084
|
-
- When the exact text to replace is known and unique (or use replace_all for multiple occurrences)
|
|
9715
|
+
Four editing modes \u2014 choose based on the scope of your change:
|
|
9085
9716
|
|
|
9086
|
-
|
|
9087
|
-
|
|
9088
|
-
|
|
9089
|
-
|
|
9717
|
+
1. **Text edit** (old_string + new_string): For small, precise changes \u2014 fix a condition, rename a variable, update a value. Provide old_string copied verbatim from the file and new_string with the replacement. Fuzzy matching handles minor whitespace/indentation differences automatically, but always try to copy the exact text.
|
|
9718
|
+
|
|
9719
|
+
2. **Symbol replace** (symbol + new_string): For replacing an entire function, class, or method by name. No need to quote the old code \u2014 just provide the symbol name and the full new implementation. Indentation is automatically adjusted to match the original. Prefer this mode when rewriting whole definitions.
|
|
9720
|
+
|
|
9721
|
+
3. **Symbol insert** (symbol + new_string + position): For adding new code before or after an existing symbol. Set position to "before" or "after".
|
|
9722
|
+
|
|
9723
|
+
4. **Line-targeted edit** (start_line + new_string): For precise edits using line numbers from extract/search output. Use start_line with a line number (e.g. "42") or line:hash (e.g. "42:ab") for integrity verification. Add end_line for multi-line ranges. Use position="before" or "after" to insert instead of replace.
|
|
9090
9724
|
|
|
9091
9725
|
Parameters:
|
|
9092
9726
|
- file_path: (required) Path to the file to edit
|
|
9093
|
-
-
|
|
9094
|
-
-
|
|
9095
|
-
- replace_all: (optional, default: false) Replace all occurrences
|
|
9096
|
-
|
|
9097
|
-
|
|
9098
|
-
-
|
|
9099
|
-
-
|
|
9100
|
-
|
|
9727
|
+
- new_string: (required) Replacement text or new code content
|
|
9728
|
+
- old_string: (optional) Text to find and replace \u2014 copy verbatim from the file, do not paraphrase or reformat
|
|
9729
|
+
- replace_all: (optional, default: false) Replace all occurrences of old_string (text mode only)
|
|
9730
|
+
- symbol: (optional) Name of a code symbol (e.g. "myFunction", "MyClass.myMethod") \u2014 must match a function, class, or method definition
|
|
9731
|
+
- position: (optional) "before" or "after" \u2014 insert new_string near the symbol or line instead of replacing it
|
|
9732
|
+
- start_line: (optional) Line reference for line-targeted editing (e.g. "42" or "42:ab")
|
|
9733
|
+
- end_line: (optional) End of line range, inclusive (e.g. "55" or "55:cd"). Defaults to start_line.
|
|
9734
|
+
|
|
9735
|
+
Mode selection rules (priority order):
|
|
9736
|
+
- If symbol is provided, symbol mode is used (old_string and start_line are ignored)
|
|
9737
|
+
- If start_line is provided (without symbol), line-targeted mode is used
|
|
9738
|
+
- If old_string is provided (without symbol or start_line), text mode is used
|
|
9739
|
+
- If none are provided, the tool returns an error with guidance
|
|
9740
|
+
|
|
9741
|
+
When to use each mode:
|
|
9742
|
+
- Small edits (a line or a few lines): use text mode with old_string
|
|
9743
|
+
- Replacing entire functions/classes/methods: use symbol mode \u2014 no exact text matching needed
|
|
9744
|
+
- Editing specific lines from extract/search output: use line-targeted mode with start_line
|
|
9745
|
+
- Editing inside large functions without rewriting them entirely: first use extract with the symbol target (e.g. "file.js#myFunction") to see the function with line numbers, then use start_line/end_line to edit specific lines within it
|
|
9746
|
+
|
|
9747
|
+
Error handling:
|
|
9748
|
+
- If an edit fails, read the error message carefully \u2014 it contains specific instructions for how to fix the call and retry
|
|
9749
|
+
- Common fixes: use 'search'/'extract' to get exact file content, add more context to old_string, switch between text and symbol modes
|
|
9750
|
+
- Line-targeted hash mismatch: the file changed since last read; the error provides updated line:hash references
|
|
9101
9751
|
|
|
9102
9752
|
Examples:
|
|
9753
|
+
|
|
9754
|
+
Text edit (find and replace):
|
|
9103
9755
|
<edit>
|
|
9104
9756
|
<file_path>src/main.js</file_path>
|
|
9105
|
-
<old_string>
|
|
9106
|
-
|
|
9107
|
-
}</old_string>
|
|
9108
|
-
<new_string>function newName() {
|
|
9109
|
-
return 42;
|
|
9110
|
-
}</new_string>
|
|
9757
|
+
<old_string>return false;</old_string>
|
|
9758
|
+
<new_string>return true;</new_string>
|
|
9111
9759
|
</edit>
|
|
9112
9760
|
|
|
9761
|
+
Text edit with replace_all:
|
|
9113
9762
|
<edit>
|
|
9114
9763
|
<file_path>config.json</file_path>
|
|
9115
9764
|
<old_string>"debug": false</old_string>
|
|
9116
9765
|
<new_string>"debug": true</new_string>
|
|
9117
9766
|
<replace_all>true</replace_all>
|
|
9767
|
+
</edit>
|
|
9768
|
+
|
|
9769
|
+
Symbol replace (rewrite entire function by name):
|
|
9770
|
+
<edit>
|
|
9771
|
+
<file_path>src/utils.js</file_path>
|
|
9772
|
+
<symbol>calculateTotal</symbol>
|
|
9773
|
+
<new_string>function calculateTotal(items) {
|
|
9774
|
+
return items.reduce((sum, item) => sum + item.price * item.quantity, 0);
|
|
9775
|
+
}</new_string>
|
|
9776
|
+
</edit>
|
|
9777
|
+
|
|
9778
|
+
Symbol insert (add new function after existing one):
|
|
9779
|
+
<edit>
|
|
9780
|
+
<file_path>src/utils.js</file_path>
|
|
9781
|
+
<symbol>calculateTotal</symbol>
|
|
9782
|
+
<position>after</position>
|
|
9783
|
+
<new_string>function calculateTax(total, rate) {
|
|
9784
|
+
return total * rate;
|
|
9785
|
+
}</new_string>
|
|
9786
|
+
</edit>
|
|
9787
|
+
|
|
9788
|
+
Line-targeted edit (replace a line):
|
|
9789
|
+
<edit>
|
|
9790
|
+
<file_path>src/main.js</file_path>
|
|
9791
|
+
<start_line>42</start_line>
|
|
9792
|
+
<new_string> return processItems(order.items);</new_string>
|
|
9793
|
+
</edit>
|
|
9794
|
+
|
|
9795
|
+
Line-targeted edit (replace a range of lines):
|
|
9796
|
+
<edit>
|
|
9797
|
+
<file_path>src/main.js</file_path>
|
|
9798
|
+
<start_line>42</start_line>
|
|
9799
|
+
<end_line>55</end_line>
|
|
9800
|
+
<new_string> // simplified implementation
|
|
9801
|
+
return processItems(order.items);</new_string>
|
|
9802
|
+
</edit>
|
|
9803
|
+
|
|
9804
|
+
Line-targeted edit with hash verification:
|
|
9805
|
+
<edit>
|
|
9806
|
+
<file_path>src/main.js</file_path>
|
|
9807
|
+
<start_line>42:ab</start_line>
|
|
9808
|
+
<end_line>55:cd</end_line>
|
|
9809
|
+
<new_string> return processItems(order.items);</new_string>
|
|
9810
|
+
</edit>
|
|
9811
|
+
|
|
9812
|
+
Line-targeted insert (add code after a line):
|
|
9813
|
+
<edit>
|
|
9814
|
+
<file_path>src/main.js</file_path>
|
|
9815
|
+
<start_line>42</start_line>
|
|
9816
|
+
<position>after</position>
|
|
9817
|
+
<new_string> const validated = validate(input);</new_string>
|
|
9818
|
+
</edit>
|
|
9819
|
+
|
|
9820
|
+
Line-targeted delete (remove lines):
|
|
9821
|
+
<edit>
|
|
9822
|
+
<file_path>src/main.js</file_path>
|
|
9823
|
+
<start_line>42</start_line>
|
|
9824
|
+
<end_line>45</end_line>
|
|
9825
|
+
<new_string></new_string>
|
|
9118
9826
|
</edit>`;
|
|
9119
9827
|
createToolDefinition = `
|
|
9120
9828
|
## create
|
|
@@ -9652,7 +10360,7 @@ function getValidParamsForTool(toolName) {
|
|
|
9652
10360
|
};
|
|
9653
10361
|
const schema = schemaMap[toolName];
|
|
9654
10362
|
if (!schema) {
|
|
9655
|
-
return ["path", "directory", "pattern", "recursive", "includeHidden", "task", "files", "
|
|
10363
|
+
return ["path", "directory", "pattern", "recursive", "includeHidden", "task", "files", "result"];
|
|
9656
10364
|
}
|
|
9657
10365
|
if (toolName === "attempt_completion") {
|
|
9658
10366
|
return ["result"];
|
|
@@ -9773,7 +10481,6 @@ function detectUnrecognizedToolCall(xmlString, validTools) {
|
|
|
9773
10481
|
"listSkills",
|
|
9774
10482
|
"useSkill",
|
|
9775
10483
|
"readImage",
|
|
9776
|
-
"implement",
|
|
9777
10484
|
"edit",
|
|
9778
10485
|
"create",
|
|
9779
10486
|
"delegate",
|
|
@@ -10147,6 +10854,8 @@ User: Read file inside the dependency
|
|
|
10147
10854
|
</extract>
|
|
10148
10855
|
|
|
10149
10856
|
</examples>
|
|
10857
|
+
|
|
10858
|
+
**Edit Integration:** The line numbers shown in extract output (e.g. "42 | code") can be used directly with the edit tool's start_line/end_line parameters for precise line-targeted editing. To edit inside a large function: extract it by symbol name first (e.g. "file.js#myFunction"), then use the line numbers from the output to make surgical edits with start_line/end_line.
|
|
10150
10859
|
`;
|
|
10151
10860
|
delegateToolDefinition = `
|
|
10152
10861
|
## delegate
|
|
@@ -10302,7 +11011,7 @@ Capabilities:
|
|
|
10302
11011
|
`;
|
|
10303
11012
|
searchDescription = "Search code in the repository. Free-form questions are accepted, but Elasticsearch-style keyword queries work best. Use this tool first for any code-related questions.";
|
|
10304
11013
|
queryDescription = "Search code using ast-grep structural pattern matching. Use this tool to find specific code structures like functions, classes, or methods.";
|
|
10305
|
-
extractDescription = "Extract code blocks from files based on file paths and optional line numbers. Use this tool to see complete context after finding relevant files.";
|
|
11014
|
+
extractDescription = "Extract code blocks from files based on file paths and optional line numbers. Use this tool to see complete context after finding relevant files. Line numbers from output can be used with edit start_line/end_line for precise editing.";
|
|
10306
11015
|
delegateDescription = "Automatically delegate big distinct tasks to specialized probe subagents within the agentic loop. Used by AI agents to break down complex requests into focused, parallel tasks.";
|
|
10307
11016
|
analyzeAllDescription = 'Answer questions that require analyzing ALL matching data in the codebase. Use for aggregate questions like "What features exist?", "List all API endpoints", "Count TODO comments". The AI automatically plans the search strategy, processes all results via map-reduce, and synthesizes a comprehensive answer. WARNING: Slower than search - only use when you need complete coverage.';
|
|
10308
11017
|
DEFAULT_VALID_TOOLS = [
|
|
@@ -10317,7 +11026,6 @@ Capabilities:
|
|
|
10317
11026
|
"useSkill",
|
|
10318
11027
|
"listFiles",
|
|
10319
11028
|
"searchFiles",
|
|
10320
|
-
"implement",
|
|
10321
11029
|
"bash",
|
|
10322
11030
|
"task",
|
|
10323
11031
|
"attempt_completion"
|
|
@@ -10442,6 +11150,7 @@ var init_vercel = __esm({
|
|
|
10442
11150
|
init_analyzeAll();
|
|
10443
11151
|
init_common();
|
|
10444
11152
|
init_error_types();
|
|
11153
|
+
init_hashline();
|
|
10445
11154
|
CODE_SEARCH_SCHEMA = {
|
|
10446
11155
|
type: "object",
|
|
10447
11156
|
properties: {
|
|
@@ -10460,8 +11169,15 @@ var init_vercel = __esm({
|
|
|
10460
11169
|
maxTokens = 2e4,
|
|
10461
11170
|
debug = false,
|
|
10462
11171
|
outline = false,
|
|
10463
|
-
searchDelegate = false
|
|
11172
|
+
searchDelegate = false,
|
|
11173
|
+
hashLines = false
|
|
10464
11174
|
} = options;
|
|
11175
|
+
const maybeAnnotate = (result) => {
|
|
11176
|
+
if (hashLines && typeof result === "string") {
|
|
11177
|
+
return annotateOutputWithHashes(result);
|
|
11178
|
+
}
|
|
11179
|
+
return result;
|
|
11180
|
+
};
|
|
10465
11181
|
return tool2({
|
|
10466
11182
|
name: "search",
|
|
10467
11183
|
description: searchDelegate ? `${searchDescription} (delegates code search to a subagent and returns extracted code blocks)` : searchDescription,
|
|
@@ -10503,7 +11219,12 @@ var init_vercel = __esm({
|
|
|
10503
11219
|
};
|
|
10504
11220
|
if (!searchDelegate) {
|
|
10505
11221
|
try {
|
|
10506
|
-
|
|
11222
|
+
const result = maybeAnnotate(await runRawSearch());
|
|
11223
|
+
if (options.fileTracker && typeof result === "string") {
|
|
11224
|
+
options.fileTracker.trackFilesFromOutput(result, options.cwd || ".").catch(() => {
|
|
11225
|
+
});
|
|
11226
|
+
}
|
|
11227
|
+
return result;
|
|
10507
11228
|
} catch (error) {
|
|
10508
11229
|
console.error("Error executing search command:", error);
|
|
10509
11230
|
return formatErrorForAI(error);
|
|
@@ -10546,7 +11267,12 @@ var init_vercel = __esm({
|
|
|
10546
11267
|
if (debug) {
|
|
10547
11268
|
console.error("Delegated search returned no targets; falling back to raw search");
|
|
10548
11269
|
}
|
|
10549
|
-
|
|
11270
|
+
const fallbackResult = maybeAnnotate(await runRawSearch());
|
|
11271
|
+
if (options.fileTracker && typeof fallbackResult === "string") {
|
|
11272
|
+
options.fileTracker.trackFilesFromOutput(fallbackResult, options.cwd || ".").catch(() => {
|
|
11273
|
+
});
|
|
11274
|
+
}
|
|
11275
|
+
return fallbackResult;
|
|
10550
11276
|
}
|
|
10551
11277
|
const resolutionBase = searchPaths[0] || options.cwd || ".";
|
|
10552
11278
|
const resolvedTargets = targets.map((target) => resolveTargetPath(target, resolutionBase));
|
|
@@ -10561,13 +11287,18 @@ var init_vercel = __esm({
|
|
|
10561
11287
|
const extractResult = await extract(extractOptions);
|
|
10562
11288
|
if (resolutionBase && typeof extractResult === "string") {
|
|
10563
11289
|
const wsPrefix = resolutionBase.endsWith("/") ? resolutionBase : resolutionBase + "/";
|
|
10564
|
-
return extractResult.split(wsPrefix).join("");
|
|
11290
|
+
return maybeAnnotate(extractResult.split(wsPrefix).join(""));
|
|
10565
11291
|
}
|
|
10566
|
-
return extractResult;
|
|
11292
|
+
return maybeAnnotate(extractResult);
|
|
10567
11293
|
} catch (error) {
|
|
10568
11294
|
console.error("Delegated search failed, falling back to raw search:", error);
|
|
10569
11295
|
try {
|
|
10570
|
-
|
|
11296
|
+
const fallbackResult2 = maybeAnnotate(await runRawSearch());
|
|
11297
|
+
if (options.fileTracker && typeof fallbackResult2 === "string") {
|
|
11298
|
+
options.fileTracker.trackFilesFromOutput(fallbackResult2, options.cwd || ".").catch(() => {
|
|
11299
|
+
});
|
|
11300
|
+
}
|
|
11301
|
+
return fallbackResult2;
|
|
10571
11302
|
} catch (fallbackError) {
|
|
10572
11303
|
console.error("Error executing search command:", fallbackError);
|
|
10573
11304
|
return formatErrorForAI(fallbackError);
|
|
@@ -10613,7 +11344,7 @@ var init_vercel = __esm({
|
|
|
10613
11344
|
});
|
|
10614
11345
|
};
|
|
10615
11346
|
extractTool = (options = {}) => {
|
|
10616
|
-
const { debug = false, outline = false } = options;
|
|
11347
|
+
const { debug = false, outline = false, hashLines = false } = options;
|
|
10617
11348
|
return tool2({
|
|
10618
11349
|
name: "extract",
|
|
10619
11350
|
description: extractDescription,
|
|
@@ -10630,6 +11361,7 @@ var init_vercel = __esm({
|
|
|
10630
11361
|
}
|
|
10631
11362
|
let tempFilePath = null;
|
|
10632
11363
|
let extractOptions = { cwd: effectiveCwd };
|
|
11364
|
+
let extractFiles = null;
|
|
10633
11365
|
if (input_content) {
|
|
10634
11366
|
const { writeFileSync: writeFileSync2, unlinkSync } = await import("fs");
|
|
10635
11367
|
const { join: join5 } = await import("path");
|
|
@@ -10653,13 +11385,13 @@ var init_vercel = __esm({
|
|
|
10653
11385
|
};
|
|
10654
11386
|
} else if (targets) {
|
|
10655
11387
|
const parsedTargets = parseTargets(targets);
|
|
10656
|
-
|
|
11388
|
+
extractFiles = parsedTargets.map((target) => resolveTargetPath(target, effectiveCwd));
|
|
10657
11389
|
let effectiveFormat = format;
|
|
10658
11390
|
if (outline && format === "outline-xml") {
|
|
10659
11391
|
effectiveFormat = "xml";
|
|
10660
11392
|
}
|
|
10661
11393
|
extractOptions = {
|
|
10662
|
-
files,
|
|
11394
|
+
files: extractFiles,
|
|
10663
11395
|
cwd: effectiveCwd,
|
|
10664
11396
|
allowTests: allow_tests ?? true,
|
|
10665
11397
|
contextLines: context_lines,
|
|
@@ -10669,6 +11401,10 @@ var init_vercel = __esm({
|
|
|
10669
11401
|
throw new Error("Either targets or input_content must be provided");
|
|
10670
11402
|
}
|
|
10671
11403
|
const results = await extract(extractOptions);
|
|
11404
|
+
if (options.fileTracker && extractFiles && extractFiles.length > 0) {
|
|
11405
|
+
options.fileTracker.trackFilesFromExtract(extractFiles, effectiveCwd).catch(() => {
|
|
11406
|
+
});
|
|
11407
|
+
}
|
|
10672
11408
|
if (tempFilePath) {
|
|
10673
11409
|
const { unlinkSync } = await import("fs");
|
|
10674
11410
|
try {
|
|
@@ -10680,6 +11416,9 @@ var init_vercel = __esm({
|
|
|
10680
11416
|
console.error(`Warning: Failed to remove temporary file: ${cleanupError.message}`);
|
|
10681
11417
|
}
|
|
10682
11418
|
}
|
|
11419
|
+
if (hashLines && typeof results === "string") {
|
|
11420
|
+
return annotateOutputWithHashes(results);
|
|
11421
|
+
}
|
|
10683
11422
|
return results;
|
|
10684
11423
|
} catch (error) {
|
|
10685
11424
|
console.error("Error executing extract command:", error);
|
|
@@ -12030,7 +12769,7 @@ async function executeBashCommand(command, options = {}) {
|
|
|
12030
12769
|
console.log(`[BashExecutor] Working directory: "${cwd}"`);
|
|
12031
12770
|
console.log(`[BashExecutor] Timeout: ${timeout}ms`);
|
|
12032
12771
|
}
|
|
12033
|
-
return new Promise((
|
|
12772
|
+
return new Promise((resolve9, reject2) => {
|
|
12034
12773
|
const processEnv = {
|
|
12035
12774
|
...process.env,
|
|
12036
12775
|
...env
|
|
@@ -12047,7 +12786,7 @@ async function executeBashCommand(command, options = {}) {
|
|
|
12047
12786
|
} else {
|
|
12048
12787
|
const args = parseCommandForExecution(command);
|
|
12049
12788
|
if (!args || args.length === 0) {
|
|
12050
|
-
|
|
12789
|
+
resolve9({
|
|
12051
12790
|
success: false,
|
|
12052
12791
|
error: "Failed to parse command",
|
|
12053
12792
|
stdout: "",
|
|
@@ -12132,7 +12871,7 @@ async function executeBashCommand(command, options = {}) {
|
|
|
12132
12871
|
success = false;
|
|
12133
12872
|
error = `Command exited with code ${code}`;
|
|
12134
12873
|
}
|
|
12135
|
-
|
|
12874
|
+
resolve9({
|
|
12136
12875
|
success,
|
|
12137
12876
|
error,
|
|
12138
12877
|
stdout: stdout.trim(),
|
|
@@ -12152,7 +12891,7 @@ async function executeBashCommand(command, options = {}) {
|
|
|
12152
12891
|
if (debug) {
|
|
12153
12892
|
console.log(`[BashExecutor] Spawn error:`, error);
|
|
12154
12893
|
}
|
|
12155
|
-
|
|
12894
|
+
resolve9({
|
|
12156
12895
|
success: false,
|
|
12157
12896
|
error: `Failed to execute command: ${error.message}`,
|
|
12158
12897
|
stdout: "",
|
|
@@ -13560,14 +14299,14 @@ var require_executor = __commonJS({
|
|
|
13560
14299
|
function asyncDone(callback) {
|
|
13561
14300
|
let isInstant = false;
|
|
13562
14301
|
let instant;
|
|
13563
|
-
const p = new Promise((
|
|
14302
|
+
const p = new Promise((resolve9, reject2) => {
|
|
13564
14303
|
callback((err, result) => {
|
|
13565
14304
|
if (err)
|
|
13566
14305
|
reject2(err);
|
|
13567
14306
|
else {
|
|
13568
14307
|
isInstant = true;
|
|
13569
14308
|
instant = result;
|
|
13570
|
-
|
|
14309
|
+
resolve9({ result });
|
|
13571
14310
|
}
|
|
13572
14311
|
});
|
|
13573
14312
|
});
|
|
@@ -13590,10 +14329,10 @@ var require_executor = __commonJS({
|
|
|
13590
14329
|
}
|
|
13591
14330
|
async function execAsync4(ticks, tree, scope, context, doneOriginal, inLoopOrSwitch) {
|
|
13592
14331
|
let done = doneOriginal;
|
|
13593
|
-
const p = new Promise((
|
|
14332
|
+
const p = new Promise((resolve9) => {
|
|
13594
14333
|
done = (e, r) => {
|
|
13595
14334
|
doneOriginal(e, r);
|
|
13596
|
-
|
|
14335
|
+
resolve9();
|
|
13597
14336
|
};
|
|
13598
14337
|
});
|
|
13599
14338
|
if (!_execNoneRecurse(ticks, tree, scope, context, done, true, inLoopOrSwitch) && utils.isLisp(tree)) {
|
|
@@ -21944,6 +22683,13 @@ function generateSandboxGlobals(options) {
|
|
|
21944
22683
|
if (i < keys2.length) params[keys2[i]] = arg;
|
|
21945
22684
|
});
|
|
21946
22685
|
}
|
|
22686
|
+
if (params.path && typeof params.path === "object") {
|
|
22687
|
+
const coercedPath = params.path.file_path || params.path.path || params.path.directory || params.path.filename;
|
|
22688
|
+
if (coercedPath && typeof coercedPath === "string") {
|
|
22689
|
+
logFn?.(`[${name}] Warning: Coerced object path to string "${coercedPath}" (issue #444)`);
|
|
22690
|
+
params.path = coercedPath;
|
|
22691
|
+
}
|
|
22692
|
+
}
|
|
21947
22693
|
const validated = schema.safeParse(params);
|
|
21948
22694
|
if (!validated.success) {
|
|
21949
22695
|
throw new Error(`Invalid parameters for ${name}: ${validated.error.message}`);
|
|
@@ -21980,6 +22726,11 @@ function generateSandboxGlobals(options) {
|
|
|
21980
22726
|
}
|
|
21981
22727
|
if (llmCall) {
|
|
21982
22728
|
const rawLLM = async (instruction, data2, opts = {}) => {
|
|
22729
|
+
const dataStr = typeof data2 === "string" ? data2 : JSON.stringify(data2);
|
|
22730
|
+
if (dataStr && dataStr.startsWith("ERROR:")) {
|
|
22731
|
+
logFn?.("[LLM] Blocked: data contains error from previous tool call");
|
|
22732
|
+
return "ERROR: Previous tool call failed - " + dataStr.substring(0, 200);
|
|
22733
|
+
}
|
|
21983
22734
|
const result = await llmCall(instruction, data2, opts);
|
|
21984
22735
|
if (opts.schema && typeof result === "string") {
|
|
21985
22736
|
try {
|
|
@@ -22345,33 +23096,31 @@ var init_runtime = __esm({
|
|
|
22345
23096
|
}
|
|
22346
23097
|
});
|
|
22347
23098
|
|
|
22348
|
-
// node_modules/balanced-match/index.js
|
|
22349
|
-
var
|
|
22350
|
-
|
|
22351
|
-
|
|
22352
|
-
|
|
22353
|
-
|
|
22354
|
-
|
|
22355
|
-
|
|
22356
|
-
var r = range(a, b, str);
|
|
23099
|
+
// node_modules/balanced-match/dist/esm/index.js
|
|
23100
|
+
var balanced, maybeMatch, range;
|
|
23101
|
+
var init_esm = __esm({
|
|
23102
|
+
"node_modules/balanced-match/dist/esm/index.js"() {
|
|
23103
|
+
balanced = (a, b, str) => {
|
|
23104
|
+
const ma = a instanceof RegExp ? maybeMatch(a, str) : a;
|
|
23105
|
+
const mb = b instanceof RegExp ? maybeMatch(b, str) : b;
|
|
23106
|
+
const r = ma !== null && mb != null && range(ma, mb, str);
|
|
22357
23107
|
return r && {
|
|
22358
23108
|
start: r[0],
|
|
22359
23109
|
end: r[1],
|
|
22360
23110
|
pre: str.slice(0, r[0]),
|
|
22361
|
-
body: str.slice(r[0] +
|
|
22362
|
-
post: str.slice(r[1] +
|
|
23111
|
+
body: str.slice(r[0] + ma.length, r[1]),
|
|
23112
|
+
post: str.slice(r[1] + mb.length)
|
|
22363
23113
|
};
|
|
22364
|
-
}
|
|
22365
|
-
|
|
22366
|
-
|
|
23114
|
+
};
|
|
23115
|
+
maybeMatch = (reg, str) => {
|
|
23116
|
+
const m = str.match(reg);
|
|
22367
23117
|
return m ? m[0] : null;
|
|
22368
|
-
}
|
|
22369
|
-
|
|
22370
|
-
|
|
22371
|
-
|
|
22372
|
-
|
|
22373
|
-
|
|
22374
|
-
var i = ai;
|
|
23118
|
+
};
|
|
23119
|
+
range = (a, b, str) => {
|
|
23120
|
+
let begs, beg, left, right = void 0, result;
|
|
23121
|
+
let ai = str.indexOf(a);
|
|
23122
|
+
let bi = str.indexOf(b, ai + 1);
|
|
23123
|
+
let i = ai;
|
|
22375
23124
|
if (ai >= 0 && bi > 0) {
|
|
22376
23125
|
if (a === b) {
|
|
22377
23126
|
return [ai, bi];
|
|
@@ -22379,14 +23128,16 @@ var require_balanced_match = __commonJS({
|
|
|
22379
23128
|
begs = [];
|
|
22380
23129
|
left = str.length;
|
|
22381
23130
|
while (i >= 0 && !result) {
|
|
22382
|
-
if (i
|
|
23131
|
+
if (i === ai) {
|
|
22383
23132
|
begs.push(i);
|
|
22384
23133
|
ai = str.indexOf(a, i + 1);
|
|
22385
|
-
} else if (begs.length
|
|
22386
|
-
|
|
23134
|
+
} else if (begs.length === 1) {
|
|
23135
|
+
const r = begs.pop();
|
|
23136
|
+
if (r !== void 0)
|
|
23137
|
+
result = [r, bi];
|
|
22387
23138
|
} else {
|
|
22388
23139
|
beg = begs.pop();
|
|
22389
|
-
if (beg < left) {
|
|
23140
|
+
if (beg !== void 0 && beg < left) {
|
|
22390
23141
|
left = beg;
|
|
22391
23142
|
right = bi;
|
|
22392
23143
|
}
|
|
@@ -22394,163 +23145,179 @@ var require_balanced_match = __commonJS({
|
|
|
22394
23145
|
}
|
|
22395
23146
|
i = ai < bi && ai >= 0 ? ai : bi;
|
|
22396
23147
|
}
|
|
22397
|
-
if (begs.length) {
|
|
23148
|
+
if (begs.length && right !== void 0) {
|
|
22398
23149
|
result = [left, right];
|
|
22399
23150
|
}
|
|
22400
23151
|
}
|
|
22401
23152
|
return result;
|
|
22402
|
-
}
|
|
23153
|
+
};
|
|
22403
23154
|
}
|
|
22404
23155
|
});
|
|
22405
23156
|
|
|
22406
|
-
// node_modules/brace-expansion/index.js
|
|
22407
|
-
|
|
22408
|
-
|
|
22409
|
-
|
|
22410
|
-
|
|
22411
|
-
|
|
22412
|
-
|
|
22413
|
-
|
|
22414
|
-
|
|
22415
|
-
|
|
22416
|
-
|
|
22417
|
-
|
|
22418
|
-
|
|
22419
|
-
|
|
22420
|
-
|
|
22421
|
-
|
|
22422
|
-
|
|
22423
|
-
|
|
22424
|
-
|
|
22425
|
-
|
|
22426
|
-
|
|
22427
|
-
|
|
22428
|
-
|
|
22429
|
-
|
|
22430
|
-
|
|
22431
|
-
|
|
22432
|
-
|
|
22433
|
-
|
|
22434
|
-
|
|
22435
|
-
|
|
22436
|
-
|
|
22437
|
-
|
|
22438
|
-
|
|
22439
|
-
|
|
22440
|
-
|
|
22441
|
-
|
|
22442
|
-
|
|
22443
|
-
|
|
22444
|
-
|
|
22445
|
-
|
|
22446
|
-
|
|
22447
|
-
|
|
22448
|
-
|
|
22449
|
-
|
|
22450
|
-
|
|
22451
|
-
|
|
22452
|
-
|
|
22453
|
-
|
|
22454
|
-
|
|
22455
|
-
|
|
22456
|
-
|
|
22457
|
-
|
|
22458
|
-
|
|
22459
|
-
|
|
22460
|
-
|
|
22461
|
-
|
|
22462
|
-
|
|
22463
|
-
|
|
23157
|
+
// node_modules/brace-expansion/dist/esm/index.js
|
|
23158
|
+
function numeric(str) {
|
|
23159
|
+
return !isNaN(str) ? parseInt(str, 10) : str.charCodeAt(0);
|
|
23160
|
+
}
|
|
23161
|
+
function escapeBraces(str) {
|
|
23162
|
+
return str.replace(slashPattern, escSlash).replace(openPattern, escOpen).replace(closePattern, escClose).replace(commaPattern, escComma).replace(periodPattern, escPeriod);
|
|
23163
|
+
}
|
|
23164
|
+
function unescapeBraces(str) {
|
|
23165
|
+
return str.replace(escSlashPattern, "\\").replace(escOpenPattern, "{").replace(escClosePattern, "}").replace(escCommaPattern, ",").replace(escPeriodPattern, ".");
|
|
23166
|
+
}
|
|
23167
|
+
function parseCommaParts(str) {
|
|
23168
|
+
if (!str) {
|
|
23169
|
+
return [""];
|
|
23170
|
+
}
|
|
23171
|
+
const parts = [];
|
|
23172
|
+
const m = balanced("{", "}", str);
|
|
23173
|
+
if (!m) {
|
|
23174
|
+
return str.split(",");
|
|
23175
|
+
}
|
|
23176
|
+
const { pre, body, post } = m;
|
|
23177
|
+
const p = pre.split(",");
|
|
23178
|
+
p[p.length - 1] += "{" + body + "}";
|
|
23179
|
+
const postParts = parseCommaParts(post);
|
|
23180
|
+
if (post.length) {
|
|
23181
|
+
;
|
|
23182
|
+
p[p.length - 1] += postParts.shift();
|
|
23183
|
+
p.push.apply(p, postParts);
|
|
23184
|
+
}
|
|
23185
|
+
parts.push.apply(parts, p);
|
|
23186
|
+
return parts;
|
|
23187
|
+
}
|
|
23188
|
+
function expand(str, options = {}) {
|
|
23189
|
+
if (!str) {
|
|
23190
|
+
return [];
|
|
23191
|
+
}
|
|
23192
|
+
const { max = EXPANSION_MAX } = options;
|
|
23193
|
+
if (str.slice(0, 2) === "{}") {
|
|
23194
|
+
str = "\\{\\}" + str.slice(2);
|
|
23195
|
+
}
|
|
23196
|
+
return expand_(escapeBraces(str), max, true).map(unescapeBraces);
|
|
23197
|
+
}
|
|
23198
|
+
function embrace(str) {
|
|
23199
|
+
return "{" + str + "}";
|
|
23200
|
+
}
|
|
23201
|
+
function isPadded(el) {
|
|
23202
|
+
return /^-?0\d/.test(el);
|
|
23203
|
+
}
|
|
23204
|
+
function lte(i, y) {
|
|
23205
|
+
return i <= y;
|
|
23206
|
+
}
|
|
23207
|
+
function gte(i, y) {
|
|
23208
|
+
return i >= y;
|
|
23209
|
+
}
|
|
23210
|
+
function expand_(str, max, isTop) {
|
|
23211
|
+
const expansions = [];
|
|
23212
|
+
const m = balanced("{", "}", str);
|
|
23213
|
+
if (!m)
|
|
23214
|
+
return [str];
|
|
23215
|
+
const pre = m.pre;
|
|
23216
|
+
const post = m.post.length ? expand_(m.post, max, false) : [""];
|
|
23217
|
+
if (/\$$/.test(m.pre)) {
|
|
23218
|
+
for (let k = 0; k < post.length && k < max; k++) {
|
|
23219
|
+
const expansion = pre + "{" + m.body + "}" + post[k];
|
|
23220
|
+
expansions.push(expansion);
|
|
22464
23221
|
}
|
|
22465
|
-
|
|
22466
|
-
|
|
22467
|
-
|
|
22468
|
-
|
|
22469
|
-
|
|
22470
|
-
|
|
22471
|
-
if (
|
|
22472
|
-
|
|
22473
|
-
|
|
22474
|
-
|
|
22475
|
-
|
|
22476
|
-
|
|
22477
|
-
|
|
22478
|
-
|
|
22479
|
-
|
|
22480
|
-
|
|
22481
|
-
|
|
22482
|
-
|
|
22483
|
-
|
|
22484
|
-
|
|
22485
|
-
|
|
22486
|
-
|
|
22487
|
-
|
|
22488
|
-
|
|
22489
|
-
|
|
22490
|
-
|
|
22491
|
-
|
|
22492
|
-
|
|
22493
|
-
|
|
22494
|
-
|
|
22495
|
-
|
|
22496
|
-
|
|
22497
|
-
|
|
22498
|
-
|
|
22499
|
-
|
|
23222
|
+
} else {
|
|
23223
|
+
const isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body);
|
|
23224
|
+
const isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body);
|
|
23225
|
+
const isSequence = isNumericSequence || isAlphaSequence;
|
|
23226
|
+
const isOptions = m.body.indexOf(",") >= 0;
|
|
23227
|
+
if (!isSequence && !isOptions) {
|
|
23228
|
+
if (m.post.match(/,(?!,).*\}/)) {
|
|
23229
|
+
str = m.pre + "{" + m.body + escClose + m.post;
|
|
23230
|
+
return expand_(str, max, true);
|
|
23231
|
+
}
|
|
23232
|
+
return [str];
|
|
23233
|
+
}
|
|
23234
|
+
let n;
|
|
23235
|
+
if (isSequence) {
|
|
23236
|
+
n = m.body.split(/\.\./);
|
|
23237
|
+
} else {
|
|
23238
|
+
n = parseCommaParts(m.body);
|
|
23239
|
+
if (n.length === 1 && n[0] !== void 0) {
|
|
23240
|
+
n = expand_(n[0], max, false).map(embrace);
|
|
23241
|
+
if (n.length === 1) {
|
|
23242
|
+
return post.map((p) => m.pre + n[0] + p);
|
|
23243
|
+
}
|
|
23244
|
+
}
|
|
23245
|
+
}
|
|
23246
|
+
let N;
|
|
23247
|
+
if (isSequence && n[0] !== void 0 && n[1] !== void 0) {
|
|
23248
|
+
const x = numeric(n[0]);
|
|
23249
|
+
const y = numeric(n[1]);
|
|
23250
|
+
const width = Math.max(n[0].length, n[1].length);
|
|
23251
|
+
let incr = n.length === 3 && n[2] !== void 0 ? Math.abs(numeric(n[2])) : 1;
|
|
23252
|
+
let test = lte;
|
|
23253
|
+
const reverse = y < x;
|
|
23254
|
+
if (reverse) {
|
|
23255
|
+
incr *= -1;
|
|
23256
|
+
test = gte;
|
|
23257
|
+
}
|
|
23258
|
+
const pad = n.some(isPadded);
|
|
23259
|
+
N = [];
|
|
23260
|
+
for (let i = x; test(i, y); i += incr) {
|
|
23261
|
+
let c;
|
|
23262
|
+
if (isAlphaSequence) {
|
|
23263
|
+
c = String.fromCharCode(i);
|
|
23264
|
+
if (c === "\\") {
|
|
23265
|
+
c = "";
|
|
22500
23266
|
}
|
|
22501
|
-
}
|
|
22502
|
-
|
|
22503
|
-
|
|
22504
|
-
|
|
22505
|
-
|
|
22506
|
-
|
|
22507
|
-
|
|
22508
|
-
|
|
22509
|
-
|
|
22510
|
-
|
|
22511
|
-
incr *= -1;
|
|
22512
|
-
test = gte;
|
|
22513
|
-
}
|
|
22514
|
-
var pad = n.some(isPadded);
|
|
22515
|
-
N = [];
|
|
22516
|
-
for (var i = x; test(i, y); i += incr) {
|
|
22517
|
-
var c;
|
|
22518
|
-
if (isAlphaSequence) {
|
|
22519
|
-
c = String.fromCharCode(i);
|
|
22520
|
-
if (c === "\\")
|
|
22521
|
-
c = "";
|
|
22522
|
-
} else {
|
|
22523
|
-
c = String(i);
|
|
22524
|
-
if (pad) {
|
|
22525
|
-
var need = width - c.length;
|
|
22526
|
-
if (need > 0) {
|
|
22527
|
-
var z = new Array(need + 1).join("0");
|
|
22528
|
-
if (i < 0)
|
|
22529
|
-
c = "-" + z + c.slice(1);
|
|
22530
|
-
else
|
|
22531
|
-
c = z + c;
|
|
22532
|
-
}
|
|
23267
|
+
} else {
|
|
23268
|
+
c = String(i);
|
|
23269
|
+
if (pad) {
|
|
23270
|
+
const need = width - c.length;
|
|
23271
|
+
if (need > 0) {
|
|
23272
|
+
const z = new Array(need + 1).join("0");
|
|
23273
|
+
if (i < 0) {
|
|
23274
|
+
c = "-" + z + c.slice(1);
|
|
23275
|
+
} else {
|
|
23276
|
+
c = z + c;
|
|
22533
23277
|
}
|
|
22534
23278
|
}
|
|
22535
|
-
N.push(c);
|
|
22536
|
-
}
|
|
22537
|
-
} else {
|
|
22538
|
-
N = [];
|
|
22539
|
-
for (var j = 0; j < n.length; j++) {
|
|
22540
|
-
N.push.apply(N, expand2(n[j], false));
|
|
22541
23279
|
}
|
|
22542
23280
|
}
|
|
22543
|
-
|
|
22544
|
-
|
|
22545
|
-
|
|
22546
|
-
|
|
22547
|
-
|
|
22548
|
-
|
|
23281
|
+
N.push(c);
|
|
23282
|
+
}
|
|
23283
|
+
} else {
|
|
23284
|
+
N = [];
|
|
23285
|
+
for (let j = 0; j < n.length; j++) {
|
|
23286
|
+
N.push.apply(N, expand_(n[j], max, false));
|
|
23287
|
+
}
|
|
23288
|
+
}
|
|
23289
|
+
for (let j = 0; j < N.length; j++) {
|
|
23290
|
+
for (let k = 0; k < post.length && expansions.length < max; k++) {
|
|
23291
|
+
const expansion = pre + N[j] + post[k];
|
|
23292
|
+
if (!isTop || isSequence || expansion) {
|
|
23293
|
+
expansions.push(expansion);
|
|
22549
23294
|
}
|
|
22550
23295
|
}
|
|
22551
|
-
return expansions;
|
|
22552
23296
|
}
|
|
22553
23297
|
}
|
|
23298
|
+
return expansions;
|
|
23299
|
+
}
|
|
23300
|
+
var escSlash, escOpen, escClose, escComma, escPeriod, escSlashPattern, escOpenPattern, escClosePattern, escCommaPattern, escPeriodPattern, slashPattern, openPattern, closePattern, commaPattern, periodPattern, EXPANSION_MAX;
|
|
23301
|
+
var init_esm2 = __esm({
|
|
23302
|
+
"node_modules/brace-expansion/dist/esm/index.js"() {
|
|
23303
|
+
init_esm();
|
|
23304
|
+
escSlash = "\0SLASH" + Math.random() + "\0";
|
|
23305
|
+
escOpen = "\0OPEN" + Math.random() + "\0";
|
|
23306
|
+
escClose = "\0CLOSE" + Math.random() + "\0";
|
|
23307
|
+
escComma = "\0COMMA" + Math.random() + "\0";
|
|
23308
|
+
escPeriod = "\0PERIOD" + Math.random() + "\0";
|
|
23309
|
+
escSlashPattern = new RegExp(escSlash, "g");
|
|
23310
|
+
escOpenPattern = new RegExp(escOpen, "g");
|
|
23311
|
+
escClosePattern = new RegExp(escClose, "g");
|
|
23312
|
+
escCommaPattern = new RegExp(escComma, "g");
|
|
23313
|
+
escPeriodPattern = new RegExp(escPeriod, "g");
|
|
23314
|
+
slashPattern = /\\\\/g;
|
|
23315
|
+
openPattern = /\\{/g;
|
|
23316
|
+
closePattern = /\\}/g;
|
|
23317
|
+
commaPattern = /\\,/g;
|
|
23318
|
+
periodPattern = /\\./g;
|
|
23319
|
+
EXPANSION_MAX = 1e5;
|
|
23320
|
+
}
|
|
22554
23321
|
});
|
|
22555
23322
|
|
|
22556
23323
|
// node_modules/minimatch/dist/esm/assert-valid-pattern.js
|
|
@@ -23133,11 +23900,13 @@ var init_ast = __esm({
|
|
|
23133
23900
|
let escaping = false;
|
|
23134
23901
|
let re = "";
|
|
23135
23902
|
let uflag = false;
|
|
23903
|
+
let inStar = false;
|
|
23136
23904
|
for (let i = 0; i < glob2.length; i++) {
|
|
23137
23905
|
const c = glob2.charAt(i);
|
|
23138
23906
|
if (escaping) {
|
|
23139
23907
|
escaping = false;
|
|
23140
23908
|
re += (reSpecials.has(c) ? "\\" : "") + c;
|
|
23909
|
+
inStar = false;
|
|
23141
23910
|
continue;
|
|
23142
23911
|
}
|
|
23143
23912
|
if (c === "\\") {
|
|
@@ -23155,16 +23924,19 @@ var init_ast = __esm({
|
|
|
23155
23924
|
uflag = uflag || needUflag;
|
|
23156
23925
|
i += consumed - 1;
|
|
23157
23926
|
hasMagic2 = hasMagic2 || magic;
|
|
23927
|
+
inStar = false;
|
|
23158
23928
|
continue;
|
|
23159
23929
|
}
|
|
23160
23930
|
}
|
|
23161
23931
|
if (c === "*") {
|
|
23162
|
-
if (
|
|
23163
|
-
|
|
23164
|
-
|
|
23165
|
-
|
|
23932
|
+
if (inStar)
|
|
23933
|
+
continue;
|
|
23934
|
+
inStar = true;
|
|
23935
|
+
re += noEmpty && /^[*]+$/.test(glob2) ? starNoEmpty : star;
|
|
23166
23936
|
hasMagic2 = true;
|
|
23167
23937
|
continue;
|
|
23938
|
+
} else {
|
|
23939
|
+
inStar = false;
|
|
23168
23940
|
}
|
|
23169
23941
|
if (c === "?") {
|
|
23170
23942
|
re += qmark;
|
|
@@ -23190,10 +23962,10 @@ var init_escape = __esm({
|
|
|
23190
23962
|
});
|
|
23191
23963
|
|
|
23192
23964
|
// node_modules/minimatch/dist/esm/index.js
|
|
23193
|
-
var
|
|
23194
|
-
var
|
|
23965
|
+
var minimatch, starDotExtRE, starDotExtTest, starDotExtTestDot, starDotExtTestNocase, starDotExtTestNocaseDot, starDotStarRE, starDotStarTest, starDotStarTestDot, dotStarRE, dotStarTest, starRE, starTest, starTestDot, qmarksRE, qmarksTestNocase, qmarksTestNocaseDot, qmarksTestDot, qmarksTest, qmarksTestNoExt, qmarksTestNoExtDot, defaultPlatform, path5, sep3, GLOBSTAR, qmark2, star2, twoStarDot, twoStarNoDot, filter, ext, defaults, braceExpand, makeRe, match, globMagic, regExpEscape2, Minimatch;
|
|
23966
|
+
var init_esm3 = __esm({
|
|
23195
23967
|
"node_modules/minimatch/dist/esm/index.js"() {
|
|
23196
|
-
|
|
23968
|
+
init_esm2();
|
|
23197
23969
|
init_assert_valid_pattern();
|
|
23198
23970
|
init_ast();
|
|
23199
23971
|
init_escape();
|
|
@@ -23316,7 +24088,7 @@ var init_esm = __esm({
|
|
|
23316
24088
|
if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) {
|
|
23317
24089
|
return [pattern];
|
|
23318
24090
|
}
|
|
23319
|
-
return (
|
|
24091
|
+
return expand(pattern);
|
|
23320
24092
|
};
|
|
23321
24093
|
minimatch.braceExpand = braceExpand;
|
|
23322
24094
|
makeRe = (pattern, options = {}) => new Minimatch(pattern, options).makeRe();
|
|
@@ -23922,7 +24694,7 @@ var init_esm = __esm({
|
|
|
23922
24694
|
|
|
23923
24695
|
// node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.js
|
|
23924
24696
|
var perf, warned, PROCESS, emitWarning, AC, AS, shouldWarn, TYPE, isPosInt, getUintArray, ZeroArray, Stack, LRUCache;
|
|
23925
|
-
var
|
|
24697
|
+
var init_esm4 = __esm({
|
|
23926
24698
|
"node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.js"() {
|
|
23927
24699
|
perf = typeof performance === "object" && performance && typeof performance.now === "function" ? performance : Date;
|
|
23928
24700
|
warned = /* @__PURE__ */ new Set();
|
|
@@ -25299,7 +26071,7 @@ import { EventEmitter } from "node:events";
|
|
|
25299
26071
|
import Stream from "node:stream";
|
|
25300
26072
|
import { StringDecoder } from "node:string_decoder";
|
|
25301
26073
|
var proc, isStream, isReadable, isWritable, EOF, MAYBE_EMIT_END, EMITTED_END, EMITTING_END, EMITTED_ERROR, CLOSED, READ, FLUSH, FLUSHCHUNK, ENCODING, DECODER, FLOWING, PAUSED, RESUME, BUFFER, PIPES, BUFFERLENGTH, BUFFERPUSH, BUFFERSHIFT, OBJECTMODE, DESTROYED, ERROR, EMITDATA, EMITEND, EMITEND2, ASYNC, ABORT, ABORTED, SIGNAL, DATALISTENERS, DISCARDED, defer, nodefer, isEndish, isArrayBufferLike, isArrayBufferView, Pipe, PipeProxyErrors, isObjectModeOptions, isEncodingOptions, Minipass;
|
|
25302
|
-
var
|
|
26074
|
+
var init_esm5 = __esm({
|
|
25303
26075
|
"node_modules/minipass/dist/esm/index.js"() {
|
|
25304
26076
|
proc = typeof process === "object" && process ? process : {
|
|
25305
26077
|
stdout: null,
|
|
@@ -26026,10 +26798,10 @@ var init_esm3 = __esm({
|
|
|
26026
26798
|
* Return a void Promise that resolves once the stream ends.
|
|
26027
26799
|
*/
|
|
26028
26800
|
async promise() {
|
|
26029
|
-
return new Promise((
|
|
26801
|
+
return new Promise((resolve9, reject2) => {
|
|
26030
26802
|
this.on(DESTROYED, () => reject2(new Error("stream destroyed")));
|
|
26031
26803
|
this.on("error", (er) => reject2(er));
|
|
26032
|
-
this.on("end", () =>
|
|
26804
|
+
this.on("end", () => resolve9());
|
|
26033
26805
|
});
|
|
26034
26806
|
}
|
|
26035
26807
|
/**
|
|
@@ -26053,7 +26825,7 @@ var init_esm3 = __esm({
|
|
|
26053
26825
|
return Promise.resolve({ done: false, value: res });
|
|
26054
26826
|
if (this[EOF])
|
|
26055
26827
|
return stop();
|
|
26056
|
-
let
|
|
26828
|
+
let resolve9;
|
|
26057
26829
|
let reject2;
|
|
26058
26830
|
const onerr = (er) => {
|
|
26059
26831
|
this.off("data", ondata);
|
|
@@ -26067,19 +26839,19 @@ var init_esm3 = __esm({
|
|
|
26067
26839
|
this.off("end", onend);
|
|
26068
26840
|
this.off(DESTROYED, ondestroy);
|
|
26069
26841
|
this.pause();
|
|
26070
|
-
|
|
26842
|
+
resolve9({ value, done: !!this[EOF] });
|
|
26071
26843
|
};
|
|
26072
26844
|
const onend = () => {
|
|
26073
26845
|
this.off("error", onerr);
|
|
26074
26846
|
this.off("data", ondata);
|
|
26075
26847
|
this.off(DESTROYED, ondestroy);
|
|
26076
26848
|
stop();
|
|
26077
|
-
|
|
26849
|
+
resolve9({ done: true, value: void 0 });
|
|
26078
26850
|
};
|
|
26079
26851
|
const ondestroy = () => onerr(new Error("stream destroyed"));
|
|
26080
26852
|
return new Promise((res2, rej) => {
|
|
26081
26853
|
reject2 = rej;
|
|
26082
|
-
|
|
26854
|
+
resolve9 = res2;
|
|
26083
26855
|
this.once(DESTROYED, ondestroy);
|
|
26084
26856
|
this.once("error", onerr);
|
|
26085
26857
|
this.once("end", onend);
|
|
@@ -26188,10 +26960,10 @@ import { lstatSync, readdir as readdirCB, readdirSync, readlinkSync, realpathSyn
|
|
|
26188
26960
|
import * as actualFS from "node:fs";
|
|
26189
26961
|
import { lstat, readdir, readlink, realpath } from "node:fs/promises";
|
|
26190
26962
|
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;
|
|
26191
|
-
var
|
|
26963
|
+
var init_esm6 = __esm({
|
|
26192
26964
|
"node_modules/path-scurry/dist/esm/index.js"() {
|
|
26193
|
-
|
|
26194
|
-
|
|
26965
|
+
init_esm4();
|
|
26966
|
+
init_esm5();
|
|
26195
26967
|
realpathSync2 = rps.native;
|
|
26196
26968
|
defaultFS = {
|
|
26197
26969
|
lstatSync,
|
|
@@ -27063,9 +27835,9 @@ var init_esm4 = __esm({
|
|
|
27063
27835
|
if (this.#asyncReaddirInFlight) {
|
|
27064
27836
|
await this.#asyncReaddirInFlight;
|
|
27065
27837
|
} else {
|
|
27066
|
-
let
|
|
27838
|
+
let resolve9 = () => {
|
|
27067
27839
|
};
|
|
27068
|
-
this.#asyncReaddirInFlight = new Promise((res) =>
|
|
27840
|
+
this.#asyncReaddirInFlight = new Promise((res) => resolve9 = res);
|
|
27069
27841
|
try {
|
|
27070
27842
|
for (const e of await this.#fs.promises.readdir(fullpath, {
|
|
27071
27843
|
withFileTypes: true
|
|
@@ -27078,7 +27850,7 @@ var init_esm4 = __esm({
|
|
|
27078
27850
|
children.provisional = 0;
|
|
27079
27851
|
}
|
|
27080
27852
|
this.#asyncReaddirInFlight = void 0;
|
|
27081
|
-
|
|
27853
|
+
resolve9();
|
|
27082
27854
|
}
|
|
27083
27855
|
return children.slice(0, children.provisional);
|
|
27084
27856
|
}
|
|
@@ -27921,7 +28693,7 @@ var init_esm4 = __esm({
|
|
|
27921
28693
|
var isPatternList, isGlobList, Pattern;
|
|
27922
28694
|
var init_pattern = __esm({
|
|
27923
28695
|
"node_modules/glob/dist/esm/pattern.js"() {
|
|
27924
|
-
|
|
28696
|
+
init_esm3();
|
|
27925
28697
|
isPatternList = (pl) => pl.length >= 1;
|
|
27926
28698
|
isGlobList = (gl) => gl.length >= 1;
|
|
27927
28699
|
Pattern = class _Pattern {
|
|
@@ -28092,7 +28864,7 @@ var init_pattern = __esm({
|
|
|
28092
28864
|
var defaultPlatform2, Ignore;
|
|
28093
28865
|
var init_ignore = __esm({
|
|
28094
28866
|
"node_modules/glob/dist/esm/ignore.js"() {
|
|
28095
|
-
|
|
28867
|
+
init_esm3();
|
|
28096
28868
|
init_pattern();
|
|
28097
28869
|
defaultPlatform2 = typeof process === "object" && process && typeof process.platform === "string" ? process.platform : "linux";
|
|
28098
28870
|
Ignore = class {
|
|
@@ -28186,7 +28958,7 @@ var init_ignore = __esm({
|
|
|
28186
28958
|
var HasWalkedCache, MatchRecord, SubWalks, Processor;
|
|
28187
28959
|
var init_processor = __esm({
|
|
28188
28960
|
"node_modules/glob/dist/esm/processor.js"() {
|
|
28189
|
-
|
|
28961
|
+
init_esm3();
|
|
28190
28962
|
HasWalkedCache = class _HasWalkedCache {
|
|
28191
28963
|
store;
|
|
28192
28964
|
constructor(store = /* @__PURE__ */ new Map()) {
|
|
@@ -28413,7 +29185,7 @@ var init_processor = __esm({
|
|
|
28413
29185
|
var makeIgnore, GlobUtil, GlobWalker, GlobStream;
|
|
28414
29186
|
var init_walker = __esm({
|
|
28415
29187
|
"node_modules/glob/dist/esm/walker.js"() {
|
|
28416
|
-
|
|
29188
|
+
init_esm5();
|
|
28417
29189
|
init_ignore();
|
|
28418
29190
|
init_processor();
|
|
28419
29191
|
makeIgnore = (ignore2, opts) => typeof ignore2 === "string" ? new Ignore([ignore2], opts) : Array.isArray(ignore2) ? new Ignore(ignore2, opts) : ignore2;
|
|
@@ -28749,8 +29521,8 @@ import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
|
28749
29521
|
var defaultPlatform3, Glob;
|
|
28750
29522
|
var init_glob = __esm({
|
|
28751
29523
|
"node_modules/glob/dist/esm/glob.js"() {
|
|
28752
|
-
|
|
28753
|
-
|
|
29524
|
+
init_esm3();
|
|
29525
|
+
init_esm6();
|
|
28754
29526
|
init_pattern();
|
|
28755
29527
|
init_walker();
|
|
28756
29528
|
defaultPlatform3 = typeof process === "object" && process && typeof process.platform === "string" ? process.platform : "linux";
|
|
@@ -28958,7 +29730,7 @@ var init_glob = __esm({
|
|
|
28958
29730
|
var hasMagic;
|
|
28959
29731
|
var init_has_magic = __esm({
|
|
28960
29732
|
"node_modules/glob/dist/esm/has-magic.js"() {
|
|
28961
|
-
|
|
29733
|
+
init_esm3();
|
|
28962
29734
|
hasMagic = (pattern, options = {}) => {
|
|
28963
29735
|
if (!Array.isArray(pattern)) {
|
|
28964
29736
|
pattern = [pattern];
|
|
@@ -28992,12 +29764,12 @@ function globIterate(pattern, options = {}) {
|
|
|
28992
29764
|
return new Glob(pattern, options).iterate();
|
|
28993
29765
|
}
|
|
28994
29766
|
var streamSync, stream, iterateSync, iterate, sync, glob;
|
|
28995
|
-
var
|
|
29767
|
+
var init_esm7 = __esm({
|
|
28996
29768
|
"node_modules/glob/dist/esm/index.js"() {
|
|
28997
|
-
|
|
29769
|
+
init_esm3();
|
|
28998
29770
|
init_glob();
|
|
28999
29771
|
init_has_magic();
|
|
29000
|
-
|
|
29772
|
+
init_esm3();
|
|
29001
29773
|
init_glob();
|
|
29002
29774
|
init_has_magic();
|
|
29003
29775
|
init_ignore();
|
|
@@ -29334,6 +30106,7 @@ ${lastError}
|
|
|
29334
30106
|
|
|
29335
30107
|
RULES REMINDER:
|
|
29336
30108
|
- search(query) is KEYWORD SEARCH \u2014 pass a search query, NOT a filename. Use extract(filepath) to read file contents.
|
|
30109
|
+
- search(query, path) \u2014 the path argument must be a STRING, not an object. Use field.file_path, not field.
|
|
29337
30110
|
- search() returns up to 20K tokens by default. Use search(query, path, {maxTokens: null}) for unlimited, or searchAll(query) to auto-paginate ALL results.
|
|
29338
30111
|
- search(), searchAll(), query(), extract(), listFiles(), bash() all return STRINGS, not arrays.
|
|
29339
30112
|
- Use chunk(stringData) to split a string into an array of chunks.
|
|
@@ -29342,7 +30115,8 @@ RULES REMINDER:
|
|
|
29342
30115
|
- Do NOT define helper functions that call tools \u2014 write logic inline.
|
|
29343
30116
|
- Do NOT use async/await, template literals, or shorthand properties.
|
|
29344
30117
|
- Do NOT use regex literals (/pattern/) \u2014 use String methods like indexOf, includes, startsWith instead.
|
|
29345
|
-
- String concatenation with +, not template literals
|
|
30118
|
+
- String concatenation with +, not template literals.
|
|
30119
|
+
- IMPORTANT: If a tool returns "ERROR: ...", do NOT pass that error string to LLM() \u2014 handle or skip it.`;
|
|
29346
30120
|
const fixedCode = await llmCallFn(fixPrompt, "", { maxTokens: 4e3, temperature: 0.2 });
|
|
29347
30121
|
currentCode = stripCodeWrapping(fixedCode);
|
|
29348
30122
|
planSpan?.addEvent?.("dsl.self_heal_complete", {
|
|
@@ -29955,7 +30729,7 @@ var init_executePlan = __esm({
|
|
|
29955
30729
|
init_query();
|
|
29956
30730
|
init_extract();
|
|
29957
30731
|
init_delegate();
|
|
29958
|
-
|
|
30732
|
+
init_esm7();
|
|
29959
30733
|
init_bash();
|
|
29960
30734
|
RAW_OUTPUT_START = "<<<RAW_OUTPUT>>>";
|
|
29961
30735
|
RAW_OUTPUT_END = "<<<END_RAW_OUTPUT>>>";
|
|
@@ -30227,6 +31001,264 @@ var init_file_lister = __esm({
|
|
|
30227
31001
|
}
|
|
30228
31002
|
});
|
|
30229
31003
|
|
|
31004
|
+
// src/tools/fileTracker.js
|
|
31005
|
+
import { createHash as createHash2 } from "crypto";
|
|
31006
|
+
import { resolve as resolve5, isAbsolute as isAbsolute4 } from "path";
|
|
31007
|
+
function computeContentHash(content) {
|
|
31008
|
+
const normalized = (content || "").split("\n").map((l) => l.trimEnd()).join("\n");
|
|
31009
|
+
return createHash2("sha256").update(normalized).digest("hex").slice(0, 16);
|
|
31010
|
+
}
|
|
31011
|
+
function extractFilePath(target) {
|
|
31012
|
+
const hashIdx = target.indexOf("#");
|
|
31013
|
+
if (hashIdx !== -1) {
|
|
31014
|
+
return target.slice(0, hashIdx);
|
|
31015
|
+
}
|
|
31016
|
+
const colonIdx = target.lastIndexOf(":");
|
|
31017
|
+
if (colonIdx !== -1) {
|
|
31018
|
+
const after = target.slice(colonIdx + 1);
|
|
31019
|
+
if (/^\d+(-\d+)?$/.test(after)) {
|
|
31020
|
+
return target.slice(0, colonIdx);
|
|
31021
|
+
}
|
|
31022
|
+
}
|
|
31023
|
+
return target;
|
|
31024
|
+
}
|
|
31025
|
+
function extractSymbolName(target) {
|
|
31026
|
+
const hashIdx = target.indexOf("#");
|
|
31027
|
+
if (hashIdx !== -1) {
|
|
31028
|
+
const symbol = target.slice(hashIdx + 1);
|
|
31029
|
+
return symbol || null;
|
|
31030
|
+
}
|
|
31031
|
+
return null;
|
|
31032
|
+
}
|
|
31033
|
+
function parseFilePathsFromOutput(output) {
|
|
31034
|
+
const paths = [];
|
|
31035
|
+
const regex = /^(?:File:\s+|---\s+)([^\s].*?)(?:\s+---)?$/gm;
|
|
31036
|
+
let match2;
|
|
31037
|
+
while ((match2 = regex.exec(output)) !== null) {
|
|
31038
|
+
const path9 = match2[1].trim();
|
|
31039
|
+
if (path9 && !path9.startsWith("Results") && !path9.startsWith("Page") && (path9.includes("/") || path9.includes(".") || path9.includes("\\"))) {
|
|
31040
|
+
paths.push(path9);
|
|
31041
|
+
}
|
|
31042
|
+
}
|
|
31043
|
+
return paths;
|
|
31044
|
+
}
|
|
31045
|
+
var FileTracker;
|
|
31046
|
+
var init_fileTracker = __esm({
|
|
31047
|
+
"src/tools/fileTracker.js"() {
|
|
31048
|
+
"use strict";
|
|
31049
|
+
init_symbolEdit();
|
|
31050
|
+
FileTracker = class {
|
|
31051
|
+
/**
|
|
31052
|
+
* @param {Object} [options]
|
|
31053
|
+
* @param {boolean} [options.debug=false] - Enable debug logging
|
|
31054
|
+
*/
|
|
31055
|
+
constructor(options = {}) {
|
|
31056
|
+
this.debug = options.debug || false;
|
|
31057
|
+
this._seenFiles = /* @__PURE__ */ new Set();
|
|
31058
|
+
this._contentRecords = /* @__PURE__ */ new Map();
|
|
31059
|
+
}
|
|
31060
|
+
/**
|
|
31061
|
+
* Mark a file as "seen" — the LLM has read its content.
|
|
31062
|
+
* @param {string} resolvedPath - Absolute path to the file
|
|
31063
|
+
*/
|
|
31064
|
+
markFileSeen(resolvedPath) {
|
|
31065
|
+
this._seenFiles.add(resolvedPath);
|
|
31066
|
+
if (this.debug) {
|
|
31067
|
+
console.error(`[FileTracker] Marked as seen: ${resolvedPath}`);
|
|
31068
|
+
}
|
|
31069
|
+
}
|
|
31070
|
+
/**
|
|
31071
|
+
* Check if a file has been seen in this session.
|
|
31072
|
+
* @param {string} resolvedPath - Absolute path to the file
|
|
31073
|
+
* @returns {boolean}
|
|
31074
|
+
*/
|
|
31075
|
+
isFileSeen(resolvedPath) {
|
|
31076
|
+
return this._seenFiles.has(resolvedPath);
|
|
31077
|
+
}
|
|
31078
|
+
/**
|
|
31079
|
+
* Store a content hash for a symbol in a file.
|
|
31080
|
+
* @param {string} resolvedPath - Absolute path to the file
|
|
31081
|
+
* @param {string} symbolName - Symbol name (e.g. "calculateTotal")
|
|
31082
|
+
* @param {string} code - The symbol's source code
|
|
31083
|
+
* @param {number} startLine - 1-indexed start line
|
|
31084
|
+
* @param {number} endLine - 1-indexed end line
|
|
31085
|
+
* @param {string} [source='extract'] - How the content was obtained
|
|
31086
|
+
*/
|
|
31087
|
+
trackSymbolContent(resolvedPath, symbolName, code, startLine, endLine, source = "extract") {
|
|
31088
|
+
const key = `${resolvedPath}#${symbolName}`;
|
|
31089
|
+
const contentHash = computeContentHash(code);
|
|
31090
|
+
this._contentRecords.set(key, {
|
|
31091
|
+
contentHash,
|
|
31092
|
+
startLine,
|
|
31093
|
+
endLine,
|
|
31094
|
+
symbolName,
|
|
31095
|
+
source,
|
|
31096
|
+
timestamp: Date.now()
|
|
31097
|
+
});
|
|
31098
|
+
if (this.debug) {
|
|
31099
|
+
console.error(`[FileTracker] Tracked symbol ${key} (hash: ${contentHash}, lines ${startLine}-${endLine})`);
|
|
31100
|
+
}
|
|
31101
|
+
}
|
|
31102
|
+
/**
|
|
31103
|
+
* Look up a stored content record for a symbol.
|
|
31104
|
+
* @param {string} resolvedPath - Absolute path to the file
|
|
31105
|
+
* @param {string} symbolName - Symbol name
|
|
31106
|
+
* @returns {Object|null} The stored record or null
|
|
31107
|
+
*/
|
|
31108
|
+
getSymbolRecord(resolvedPath, symbolName) {
|
|
31109
|
+
return this._contentRecords.get(`${resolvedPath}#${symbolName}`) || null;
|
|
31110
|
+
}
|
|
31111
|
+
/**
|
|
31112
|
+
* Check if a symbol's current content matches what was stored.
|
|
31113
|
+
* @param {string} resolvedPath - Absolute path to the file
|
|
31114
|
+
* @param {string} symbolName - Symbol name
|
|
31115
|
+
* @param {string} currentCode - The symbol's current source code (from findSymbol)
|
|
31116
|
+
* @returns {{ok: boolean, reason?: string, message?: string}}
|
|
31117
|
+
*/
|
|
31118
|
+
checkSymbolContent(resolvedPath, symbolName, currentCode) {
|
|
31119
|
+
const key = `${resolvedPath}#${symbolName}`;
|
|
31120
|
+
const record = this._contentRecords.get(key);
|
|
31121
|
+
if (!record) {
|
|
31122
|
+
return { ok: true };
|
|
31123
|
+
}
|
|
31124
|
+
const currentHash = computeContentHash(currentCode);
|
|
31125
|
+
if (currentHash === record.contentHash) {
|
|
31126
|
+
return { ok: true };
|
|
31127
|
+
}
|
|
31128
|
+
return {
|
|
31129
|
+
ok: false,
|
|
31130
|
+
reason: "stale",
|
|
31131
|
+
message: `Symbol "${symbolName}" has changed since you last read it (hash: ${record.contentHash} \u2192 ${currentHash}).`
|
|
31132
|
+
};
|
|
31133
|
+
}
|
|
31134
|
+
/**
|
|
31135
|
+
* Track files from extract target strings.
|
|
31136
|
+
* Marks each file as seen. For #symbol targets, calls findSymbol to get and hash the code.
|
|
31137
|
+
* @param {string[]} targets - Array of extract targets (e.g. ["file.js#fn", "file.js:10-20"])
|
|
31138
|
+
* @param {string} cwd - Working directory for resolving relative paths
|
|
31139
|
+
*/
|
|
31140
|
+
async trackFilesFromExtract(targets, cwd) {
|
|
31141
|
+
const seenPaths = /* @__PURE__ */ new Set();
|
|
31142
|
+
const symbolPromises = [];
|
|
31143
|
+
for (const target of targets) {
|
|
31144
|
+
const filePath = extractFilePath(target);
|
|
31145
|
+
const resolved = isAbsolute4(filePath) ? filePath : resolve5(cwd, filePath);
|
|
31146
|
+
if (!seenPaths.has(resolved)) {
|
|
31147
|
+
seenPaths.add(resolved);
|
|
31148
|
+
this.markFileSeen(resolved);
|
|
31149
|
+
}
|
|
31150
|
+
const symbolName = extractSymbolName(target);
|
|
31151
|
+
if (symbolName) {
|
|
31152
|
+
symbolPromises.push(
|
|
31153
|
+
findSymbol(resolved, symbolName, cwd).then((symbolInfo) => {
|
|
31154
|
+
if (symbolInfo) {
|
|
31155
|
+
this.trackSymbolContent(
|
|
31156
|
+
resolved,
|
|
31157
|
+
symbolName,
|
|
31158
|
+
symbolInfo.code,
|
|
31159
|
+
symbolInfo.startLine,
|
|
31160
|
+
symbolInfo.endLine,
|
|
31161
|
+
"extract"
|
|
31162
|
+
);
|
|
31163
|
+
}
|
|
31164
|
+
}).catch((err) => {
|
|
31165
|
+
if (this.debug) {
|
|
31166
|
+
console.error(`[FileTracker] Failed to track symbol "${symbolName}" in ${resolved}: ${err.message}`);
|
|
31167
|
+
}
|
|
31168
|
+
})
|
|
31169
|
+
);
|
|
31170
|
+
}
|
|
31171
|
+
}
|
|
31172
|
+
if (symbolPromises.length > 0) {
|
|
31173
|
+
await Promise.all(symbolPromises);
|
|
31174
|
+
}
|
|
31175
|
+
}
|
|
31176
|
+
/**
|
|
31177
|
+
* Track files discovered in probe search/extract output.
|
|
31178
|
+
* Parses "File: path" headers and "--- path ---" separators, marks each as "seen".
|
|
31179
|
+
* @param {string} output - Probe output text
|
|
31180
|
+
* @param {string} cwd - Working directory for resolving relative paths
|
|
31181
|
+
*/
|
|
31182
|
+
async trackFilesFromOutput(output, cwd) {
|
|
31183
|
+
const paths = parseFilePathsFromOutput(output);
|
|
31184
|
+
for (const filePath of paths) {
|
|
31185
|
+
const resolved = isAbsolute4(filePath) ? filePath : resolve5(cwd, filePath);
|
|
31186
|
+
this.markFileSeen(resolved);
|
|
31187
|
+
}
|
|
31188
|
+
}
|
|
31189
|
+
/**
|
|
31190
|
+
* Check if a file is safe to edit (seen-check only).
|
|
31191
|
+
* Mode-specific content verification happens in edit handlers.
|
|
31192
|
+
* @param {string} resolvedPath - Absolute path to the file
|
|
31193
|
+
* @returns {{ok: boolean, reason?: string, message?: string}}
|
|
31194
|
+
*/
|
|
31195
|
+
checkBeforeEdit(resolvedPath) {
|
|
31196
|
+
if (!this._seenFiles.has(resolvedPath)) {
|
|
31197
|
+
return {
|
|
31198
|
+
ok: false,
|
|
31199
|
+
reason: "untracked",
|
|
31200
|
+
message: "This file has not been read yet in this session. Use extract or search to read the file first."
|
|
31201
|
+
};
|
|
31202
|
+
}
|
|
31203
|
+
return { ok: true };
|
|
31204
|
+
}
|
|
31205
|
+
/**
|
|
31206
|
+
* Mark a file as seen after a successful write (backward compat).
|
|
31207
|
+
* Also invalidates content records for the file since its content changed.
|
|
31208
|
+
* @param {string} resolvedPath - Absolute path to the file
|
|
31209
|
+
*/
|
|
31210
|
+
async trackFileAfterWrite(resolvedPath) {
|
|
31211
|
+
this.markFileSeen(resolvedPath);
|
|
31212
|
+
this.invalidateFileRecords(resolvedPath);
|
|
31213
|
+
}
|
|
31214
|
+
/**
|
|
31215
|
+
* Update the stored hash for a symbol after a successful write.
|
|
31216
|
+
* Enables chained edits to the same symbol.
|
|
31217
|
+
* @param {string} resolvedPath - Absolute path to the file
|
|
31218
|
+
* @param {string} symbolName - Symbol name
|
|
31219
|
+
* @param {string} code - The symbol's new source code
|
|
31220
|
+
* @param {number} startLine - 1-indexed start line (new position)
|
|
31221
|
+
* @param {number} endLine - 1-indexed end line (new position)
|
|
31222
|
+
*/
|
|
31223
|
+
trackSymbolAfterWrite(resolvedPath, symbolName, code, startLine, endLine) {
|
|
31224
|
+
this.trackSymbolContent(resolvedPath, symbolName, code, startLine, endLine, "edit");
|
|
31225
|
+
}
|
|
31226
|
+
/**
|
|
31227
|
+
* Remove all content records for a file.
|
|
31228
|
+
* Called after non-symbol edits (text/line mode) since those change content
|
|
31229
|
+
* without providing a symbol-level update.
|
|
31230
|
+
* @param {string} resolvedPath - Absolute path to the file
|
|
31231
|
+
*/
|
|
31232
|
+
invalidateFileRecords(resolvedPath) {
|
|
31233
|
+
const prefix = resolvedPath + "#";
|
|
31234
|
+
for (const key of this._contentRecords.keys()) {
|
|
31235
|
+
if (key.startsWith(prefix)) {
|
|
31236
|
+
this._contentRecords.delete(key);
|
|
31237
|
+
}
|
|
31238
|
+
}
|
|
31239
|
+
if (this.debug) {
|
|
31240
|
+
console.error(`[FileTracker] Invalidated content records for ${resolvedPath}`);
|
|
31241
|
+
}
|
|
31242
|
+
}
|
|
31243
|
+
/**
|
|
31244
|
+
* Quick sync check if a file is being tracked (alias for isFileSeen).
|
|
31245
|
+
* @param {string} resolvedPath - Absolute path to the file
|
|
31246
|
+
* @returns {boolean}
|
|
31247
|
+
*/
|
|
31248
|
+
isTracked(resolvedPath) {
|
|
31249
|
+
return this.isFileSeen(resolvedPath);
|
|
31250
|
+
}
|
|
31251
|
+
/**
|
|
31252
|
+
* Clear all tracking state.
|
|
31253
|
+
*/
|
|
31254
|
+
clear() {
|
|
31255
|
+
this._seenFiles.clear();
|
|
31256
|
+
this._contentRecords.clear();
|
|
31257
|
+
}
|
|
31258
|
+
};
|
|
31259
|
+
}
|
|
31260
|
+
});
|
|
31261
|
+
|
|
30230
31262
|
// src/agent/simpleTelemetry.js
|
|
30231
31263
|
import { existsSync as existsSync3, mkdirSync, createWriteStream } from "fs";
|
|
30232
31264
|
import { dirname as dirname2 } from "path";
|
|
@@ -30321,20 +31353,20 @@ var init_simpleTelemetry = __esm({
|
|
|
30321
31353
|
}
|
|
30322
31354
|
async flush() {
|
|
30323
31355
|
if (this.stream) {
|
|
30324
|
-
return new Promise((
|
|
30325
|
-
this.stream.once("drain",
|
|
31356
|
+
return new Promise((resolve9) => {
|
|
31357
|
+
this.stream.once("drain", resolve9);
|
|
30326
31358
|
if (!this.stream.writableNeedDrain) {
|
|
30327
|
-
|
|
31359
|
+
resolve9();
|
|
30328
31360
|
}
|
|
30329
31361
|
});
|
|
30330
31362
|
}
|
|
30331
31363
|
}
|
|
30332
31364
|
async shutdown() {
|
|
30333
31365
|
if (this.stream) {
|
|
30334
|
-
return new Promise((
|
|
31366
|
+
return new Promise((resolve9) => {
|
|
30335
31367
|
this.stream.end(() => {
|
|
30336
31368
|
console.log(`[SimpleTelemetry] File stream closed: ${this.filePath}`);
|
|
30337
|
-
|
|
31369
|
+
resolve9();
|
|
30338
31370
|
});
|
|
30339
31371
|
});
|
|
30340
31372
|
}
|
|
@@ -30779,7 +31811,7 @@ var init_probeTool = __esm({
|
|
|
30779
31811
|
"src/agent/probeTool.js"() {
|
|
30780
31812
|
"use strict";
|
|
30781
31813
|
init_index();
|
|
30782
|
-
|
|
31814
|
+
init_esm7();
|
|
30783
31815
|
init_symlink_utils();
|
|
30784
31816
|
toolCallEmitter = new EventEmitter2();
|
|
30785
31817
|
activeToolExecutions = /* @__PURE__ */ new Map();
|
|
@@ -31517,6 +32549,7 @@ var init_index = __esm({
|
|
|
31517
32549
|
init_executePlan();
|
|
31518
32550
|
init_bash();
|
|
31519
32551
|
init_edit();
|
|
32552
|
+
init_fileTracker();
|
|
31520
32553
|
init_ProbeAgent();
|
|
31521
32554
|
init_simpleTelemetry();
|
|
31522
32555
|
init_probeTool();
|
|
@@ -31699,38 +32732,13 @@ function parseXmlToolCallWithThinking(xmlString, validTools) {
|
|
|
31699
32732
|
const toolCall = parseXmlToolCall(cleanedXmlString, validTools);
|
|
31700
32733
|
return toolCall ? { ...toolCall, thinkingContent } : null;
|
|
31701
32734
|
}
|
|
31702
|
-
var
|
|
32735
|
+
var listFilesToolDefinition, searchFilesToolDefinition, listSkillsToolDefinition, useSkillToolDefinition, readImageToolDefinition;
|
|
31703
32736
|
var init_tools2 = __esm({
|
|
31704
32737
|
"src/agent/tools.js"() {
|
|
31705
32738
|
"use strict";
|
|
31706
32739
|
init_index();
|
|
31707
32740
|
init_xmlParsingUtils();
|
|
31708
32741
|
init_tasks();
|
|
31709
|
-
implementToolDefinition = `
|
|
31710
|
-
## implement
|
|
31711
|
-
Description: Implement a given task. Can modify files. Can be used ONLY if task explicitly stated that something requires modification or implementation.
|
|
31712
|
-
|
|
31713
|
-
Parameters:
|
|
31714
|
-
- task: (required) The task description. Should be as detailed as possible, ideally pointing to exact files which needs be modified or created.
|
|
31715
|
-
- autoCommits: (optional) Whether to enable auto-commits in aider. Default is false.
|
|
31716
|
-
|
|
31717
|
-
Usage Example:
|
|
31718
|
-
|
|
31719
|
-
<examples>
|
|
31720
|
-
|
|
31721
|
-
User: Can you implement a function to calculate Fibonacci numbers in main.js?
|
|
31722
|
-
<implement>
|
|
31723
|
-
<task>Implement a recursive function to calculate the nth Fibonacci number in main.js</task>
|
|
31724
|
-
</implement>
|
|
31725
|
-
|
|
31726
|
-
User: Can you implement a function to calculate Fibonacci numbers in main.js with auto-commits?
|
|
31727
|
-
<implement>
|
|
31728
|
-
<task>Implement a recursive function to calculate the nth Fibonacci number in main.js</task>
|
|
31729
|
-
<autoCommits>true</autoCommits>
|
|
31730
|
-
</implement>
|
|
31731
|
-
|
|
31732
|
-
</examples>
|
|
31733
|
-
`;
|
|
31734
32742
|
listFilesToolDefinition = `
|
|
31735
32743
|
## listFiles
|
|
31736
32744
|
Description: List files and directories in a specified location.
|
|
@@ -31854,7 +32862,7 @@ function createMockProvider() {
|
|
|
31854
32862
|
provider: "mock",
|
|
31855
32863
|
// Mock the doGenerate method used by Vercel AI SDK
|
|
31856
32864
|
doGenerate: async ({ messages, tools: tools2 }) => {
|
|
31857
|
-
await new Promise((
|
|
32865
|
+
await new Promise((resolve9) => setTimeout(resolve9, 10));
|
|
31858
32866
|
return {
|
|
31859
32867
|
text: "This is a mock response for testing",
|
|
31860
32868
|
toolCalls: [],
|
|
@@ -37057,23 +38065,23 @@ var init_regexp_parser = __esm({
|
|
|
37057
38065
|
return ASSERT_NEVER_REACH_HERE();
|
|
37058
38066
|
}
|
|
37059
38067
|
quantifier(isBacktracking = false) {
|
|
37060
|
-
let
|
|
38068
|
+
let range2 = void 0;
|
|
37061
38069
|
const begin = this.idx;
|
|
37062
38070
|
switch (this.popChar()) {
|
|
37063
38071
|
case "*":
|
|
37064
|
-
|
|
38072
|
+
range2 = {
|
|
37065
38073
|
atLeast: 0,
|
|
37066
38074
|
atMost: Infinity
|
|
37067
38075
|
};
|
|
37068
38076
|
break;
|
|
37069
38077
|
case "+":
|
|
37070
|
-
|
|
38078
|
+
range2 = {
|
|
37071
38079
|
atLeast: 1,
|
|
37072
38080
|
atMost: Infinity
|
|
37073
38081
|
};
|
|
37074
38082
|
break;
|
|
37075
38083
|
case "?":
|
|
37076
|
-
|
|
38084
|
+
range2 = {
|
|
37077
38085
|
atLeast: 0,
|
|
37078
38086
|
atMost: 1
|
|
37079
38087
|
};
|
|
@@ -37082,7 +38090,7 @@ var init_regexp_parser = __esm({
|
|
|
37082
38090
|
const atLeast = this.integerIncludingZero();
|
|
37083
38091
|
switch (this.popChar()) {
|
|
37084
38092
|
case "}":
|
|
37085
|
-
|
|
38093
|
+
range2 = {
|
|
37086
38094
|
atLeast,
|
|
37087
38095
|
atMost: atLeast
|
|
37088
38096
|
};
|
|
@@ -37091,12 +38099,12 @@ var init_regexp_parser = __esm({
|
|
|
37091
38099
|
let atMost;
|
|
37092
38100
|
if (this.isDigit()) {
|
|
37093
38101
|
atMost = this.integerIncludingZero();
|
|
37094
|
-
|
|
38102
|
+
range2 = {
|
|
37095
38103
|
atLeast,
|
|
37096
38104
|
atMost
|
|
37097
38105
|
};
|
|
37098
38106
|
} else {
|
|
37099
|
-
|
|
38107
|
+
range2 = {
|
|
37100
38108
|
atLeast,
|
|
37101
38109
|
atMost: Infinity
|
|
37102
38110
|
};
|
|
@@ -37104,25 +38112,25 @@ var init_regexp_parser = __esm({
|
|
|
37104
38112
|
this.consumeChar("}");
|
|
37105
38113
|
break;
|
|
37106
38114
|
}
|
|
37107
|
-
if (isBacktracking === true &&
|
|
38115
|
+
if (isBacktracking === true && range2 === void 0) {
|
|
37108
38116
|
return void 0;
|
|
37109
38117
|
}
|
|
37110
|
-
ASSERT_EXISTS(
|
|
38118
|
+
ASSERT_EXISTS(range2);
|
|
37111
38119
|
break;
|
|
37112
38120
|
}
|
|
37113
|
-
if (isBacktracking === true &&
|
|
38121
|
+
if (isBacktracking === true && range2 === void 0) {
|
|
37114
38122
|
return void 0;
|
|
37115
38123
|
}
|
|
37116
|
-
if (ASSERT_EXISTS(
|
|
38124
|
+
if (ASSERT_EXISTS(range2)) {
|
|
37117
38125
|
if (this.peekChar(0) === "?") {
|
|
37118
38126
|
this.consumeChar("?");
|
|
37119
|
-
|
|
38127
|
+
range2.greedy = false;
|
|
37120
38128
|
} else {
|
|
37121
|
-
|
|
38129
|
+
range2.greedy = true;
|
|
37122
38130
|
}
|
|
37123
|
-
|
|
37124
|
-
|
|
37125
|
-
return
|
|
38131
|
+
range2.type = "Quantifier";
|
|
38132
|
+
range2.loc = this.loc(begin);
|
|
38133
|
+
return range2;
|
|
37126
38134
|
}
|
|
37127
38135
|
}
|
|
37128
38136
|
atom() {
|
|
@@ -37824,18 +38832,18 @@ function firstCharOptimizedIndices(ast, result, ignoreCase) {
|
|
|
37824
38832
|
if (typeof code === "number") {
|
|
37825
38833
|
addOptimizedIdxToResult(code, result, ignoreCase);
|
|
37826
38834
|
} else {
|
|
37827
|
-
const
|
|
38835
|
+
const range2 = code;
|
|
37828
38836
|
if (ignoreCase === true) {
|
|
37829
|
-
for (let rangeCode =
|
|
38837
|
+
for (let rangeCode = range2.from; rangeCode <= range2.to; rangeCode++) {
|
|
37830
38838
|
addOptimizedIdxToResult(rangeCode, result, ignoreCase);
|
|
37831
38839
|
}
|
|
37832
38840
|
} else {
|
|
37833
|
-
for (let rangeCode =
|
|
38841
|
+
for (let rangeCode = range2.from; rangeCode <= range2.to && rangeCode < minOptimizationVal; rangeCode++) {
|
|
37834
38842
|
addOptimizedIdxToResult(rangeCode, result, ignoreCase);
|
|
37835
38843
|
}
|
|
37836
|
-
if (
|
|
37837
|
-
const minUnOptVal =
|
|
37838
|
-
const maxUnOptVal =
|
|
38844
|
+
if (range2.to >= minOptimizationVal) {
|
|
38845
|
+
const minUnOptVal = range2.from >= minOptimizationVal ? range2.from : minOptimizationVal;
|
|
38846
|
+
const maxUnOptVal = range2.to;
|
|
37839
38847
|
const minOptIdx = charCodeToOptimizedIndex(minUnOptVal);
|
|
37840
38848
|
const maxOptIdx = charCodeToOptimizedIndex(maxUnOptVal);
|
|
37841
38849
|
for (let currOptIdx = minOptIdx; currOptIdx <= maxOptIdx; currOptIdx++) {
|
|
@@ -37896,8 +38904,8 @@ function findCode(setNode, targetCharCodes) {
|
|
|
37896
38904
|
if (typeof codeOrRange === "number") {
|
|
37897
38905
|
return includes_default(targetCharCodes, codeOrRange);
|
|
37898
38906
|
} else {
|
|
37899
|
-
const
|
|
37900
|
-
return find_default(targetCharCodes, (targetCode) =>
|
|
38907
|
+
const range2 = codeOrRange;
|
|
38908
|
+
return find_default(targetCharCodes, (targetCode) => range2.from <= targetCode && targetCode <= range2.to) !== void 0;
|
|
37901
38909
|
}
|
|
37902
38910
|
});
|
|
37903
38911
|
}
|
|
@@ -55802,8 +56810,8 @@ var require_createRange = __commonJS({
|
|
|
55802
56810
|
var require_range = __commonJS({
|
|
55803
56811
|
"node_modules/lodash/range.js"(exports2, module2) {
|
|
55804
56812
|
var createRange = require_createRange();
|
|
55805
|
-
var
|
|
55806
|
-
module2.exports =
|
|
56813
|
+
var range2 = createRange();
|
|
56814
|
+
module2.exports = range2;
|
|
55807
56815
|
}
|
|
55808
56816
|
});
|
|
55809
56817
|
|
|
@@ -65044,7 +66052,7 @@ var require_compile = __commonJS({
|
|
|
65044
66052
|
const schOrFunc = root2.refs[ref2];
|
|
65045
66053
|
if (schOrFunc)
|
|
65046
66054
|
return schOrFunc;
|
|
65047
|
-
let _sch =
|
|
66055
|
+
let _sch = resolve9.call(this, root2, ref2);
|
|
65048
66056
|
if (_sch === void 0) {
|
|
65049
66057
|
const schema = (_a = root2.localRefs) === null || _a === void 0 ? void 0 : _a[ref2];
|
|
65050
66058
|
const { schemaId } = this.opts;
|
|
@@ -65071,7 +66079,7 @@ var require_compile = __commonJS({
|
|
|
65071
66079
|
function sameSchemaEnv(s1, s2) {
|
|
65072
66080
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
65073
66081
|
}
|
|
65074
|
-
function
|
|
66082
|
+
function resolve9(root2, ref2) {
|
|
65075
66083
|
let sch;
|
|
65076
66084
|
while (typeof (sch = this.refs[ref2]) == "string")
|
|
65077
66085
|
ref2 = sch;
|
|
@@ -65646,7 +66654,7 @@ var require_fast_uri = __commonJS({
|
|
|
65646
66654
|
}
|
|
65647
66655
|
return uri;
|
|
65648
66656
|
}
|
|
65649
|
-
function
|
|
66657
|
+
function resolve9(baseURI, relativeURI, options) {
|
|
65650
66658
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
65651
66659
|
const resolved = resolveComponent(parse9(baseURI, schemelessOptions), parse9(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
65652
66660
|
schemelessOptions.skipEscape = true;
|
|
@@ -65873,7 +66881,7 @@ var require_fast_uri = __commonJS({
|
|
|
65873
66881
|
var fastUri = {
|
|
65874
66882
|
SCHEMES,
|
|
65875
66883
|
normalize: normalize3,
|
|
65876
|
-
resolve:
|
|
66884
|
+
resolve: resolve9,
|
|
65877
66885
|
resolveComponent,
|
|
65878
66886
|
equal,
|
|
65879
66887
|
serialize,
|
|
@@ -68566,6 +69574,7 @@ __export(schemaUtils_exports, {
|
|
|
68566
69574
|
processSchemaResponse: () => processSchemaResponse,
|
|
68567
69575
|
replaceMermaidDiagramsInJson: () => replaceMermaidDiagramsInJson,
|
|
68568
69576
|
replaceMermaidDiagramsInMarkdown: () => replaceMermaidDiagramsInMarkdown,
|
|
69577
|
+
sanitizeMarkdownEscapesInJson: () => sanitizeMarkdownEscapesInJson,
|
|
68569
69578
|
tryAutoWrapForSimpleSchema: () => tryAutoWrapForSimpleSchema,
|
|
68570
69579
|
tryMaidAutoFix: () => tryMaidAutoFix,
|
|
68571
69580
|
validateAndFixMermaidResponse: () => validateAndFixMermaidResponse,
|
|
@@ -68669,6 +69678,17 @@ function decodeHtmlEntities2(text) {
|
|
|
68669
69678
|
}
|
|
68670
69679
|
return decoded;
|
|
68671
69680
|
}
|
|
69681
|
+
function sanitizeMarkdownEscapesInJson(jsonString) {
|
|
69682
|
+
if (!jsonString || typeof jsonString !== "string") {
|
|
69683
|
+
return jsonString;
|
|
69684
|
+
}
|
|
69685
|
+
return jsonString.replace(/\\\\|\\([^"\\\/bfnrtu])/g, (match2, captured) => {
|
|
69686
|
+
if (match2 === "\\\\") {
|
|
69687
|
+
return "\\\\";
|
|
69688
|
+
}
|
|
69689
|
+
return captured;
|
|
69690
|
+
});
|
|
69691
|
+
}
|
|
68672
69692
|
function normalizeJsonQuotes(str) {
|
|
68673
69693
|
if (!str || typeof str !== "string") {
|
|
68674
69694
|
return str;
|
|
@@ -68721,6 +69741,15 @@ function cleanSchemaResponse(response) {
|
|
|
68721
69741
|
if (resultWrapperMatch) {
|
|
68722
69742
|
return cleanSchemaResponse(resultWrapperMatch[1]);
|
|
68723
69743
|
}
|
|
69744
|
+
const toolCodeMatch = trimmed.match(/<tool_code>\s*([\s\S]*?)\s*<\/tool_code>/);
|
|
69745
|
+
if (toolCodeMatch) {
|
|
69746
|
+
let innerContent = toolCodeMatch[1].trim();
|
|
69747
|
+
const funcCallMatch = innerContent.match(/(?:print|attempt_completion)\s*\(\s*([{\[][\s\S]*[}\]])\s*\)/);
|
|
69748
|
+
if (funcCallMatch) {
|
|
69749
|
+
return cleanSchemaResponse(funcCallMatch[1]);
|
|
69750
|
+
}
|
|
69751
|
+
return cleanSchemaResponse(innerContent);
|
|
69752
|
+
}
|
|
68724
69753
|
const jsonBlockMatch = trimmed.match(/```json\s*\n([\s\S]*?)\n```/);
|
|
68725
69754
|
if (jsonBlockMatch) {
|
|
68726
69755
|
return normalizeJsonQuotes(jsonBlockMatch[1].trim());
|
|
@@ -68788,9 +69817,25 @@ function validateJsonResponse(response, options = {}) {
|
|
|
68788
69817
|
console.log(`[DEBUG] JSON validation: Schema validation enabled`);
|
|
68789
69818
|
}
|
|
68790
69819
|
}
|
|
69820
|
+
let responseToValidate = response;
|
|
69821
|
+
try {
|
|
69822
|
+
JSON.parse(response);
|
|
69823
|
+
} catch (initialError) {
|
|
69824
|
+
if (initialError.message && initialError.message.includes("escape")) {
|
|
69825
|
+
const sanitized = sanitizeMarkdownEscapesInJson(response);
|
|
69826
|
+
try {
|
|
69827
|
+
JSON.parse(sanitized);
|
|
69828
|
+
responseToValidate = sanitized;
|
|
69829
|
+
if (debug) {
|
|
69830
|
+
console.log(`[DEBUG] JSON validation: Fixed Markdown escapes in JSON (issue #441)`);
|
|
69831
|
+
}
|
|
69832
|
+
} catch {
|
|
69833
|
+
}
|
|
69834
|
+
}
|
|
69835
|
+
}
|
|
68791
69836
|
try {
|
|
68792
69837
|
const parseStart = Date.now();
|
|
68793
|
-
const parsed = JSON.parse(
|
|
69838
|
+
const parsed = JSON.parse(responseToValidate);
|
|
68794
69839
|
const parseTime = Date.now() - parseStart;
|
|
68795
69840
|
if (debug) {
|
|
68796
69841
|
console.log(`[DEBUG] JSON validation: Successfully parsed in ${parseTime}ms`);
|
|
@@ -69132,7 +70177,21 @@ function tryAutoWrapForSimpleSchema(response, schema, options = {}) {
|
|
|
69132
70177
|
console.log(`[DEBUG] Auto-wrap: Response is already valid JSON, skipping`);
|
|
69133
70178
|
}
|
|
69134
70179
|
return null;
|
|
69135
|
-
} catch {
|
|
70180
|
+
} catch (initialError) {
|
|
70181
|
+
if (initialError.message && initialError.message.includes("escape")) {
|
|
70182
|
+
try {
|
|
70183
|
+
const sanitized = sanitizeMarkdownEscapesInJson(response);
|
|
70184
|
+
JSON.parse(sanitized);
|
|
70185
|
+
if (debug) {
|
|
70186
|
+
console.log(`[DEBUG] Auto-wrap: Fixed Markdown escapes in JSON (issue #441), returning sanitized JSON`);
|
|
70187
|
+
}
|
|
70188
|
+
return sanitized;
|
|
70189
|
+
} catch {
|
|
70190
|
+
if (debug) {
|
|
70191
|
+
console.log(`[DEBUG] Auto-wrap: Markdown escape sanitization didn't fix JSON, proceeding with wrapping`);
|
|
70192
|
+
}
|
|
70193
|
+
}
|
|
70194
|
+
}
|
|
69136
70195
|
}
|
|
69137
70196
|
const wrapped = JSON.stringify({ [wrapperInfo.fieldName]: response });
|
|
69138
70197
|
if (debug) {
|
|
@@ -76084,7 +77143,7 @@ var require_compose_scalar = __commonJS({
|
|
|
76084
77143
|
var resolveBlockScalar = require_resolve_block_scalar();
|
|
76085
77144
|
var resolveFlowScalar = require_resolve_flow_scalar();
|
|
76086
77145
|
function composeScalar(ctx, token, tagToken, onError) {
|
|
76087
|
-
const { value, type, comment, range } = token.type === "block-scalar" ? resolveBlockScalar.resolveBlockScalar(ctx, token, onError) : resolveFlowScalar.resolveFlowScalar(token, ctx.options.strict, onError);
|
|
77146
|
+
const { value, type, comment, range: range2 } = token.type === "block-scalar" ? resolveBlockScalar.resolveBlockScalar(ctx, token, onError) : resolveFlowScalar.resolveFlowScalar(token, ctx.options.strict, onError);
|
|
76088
77147
|
const tagName = tagToken ? ctx.directives.tagName(tagToken.source, (msg) => onError(tagToken, "TAG_RESOLVE_FAILED", msg)) : null;
|
|
76089
77148
|
let tag;
|
|
76090
77149
|
if (ctx.options.stringKeys && ctx.atKey) {
|
|
@@ -76104,7 +77163,7 @@ var require_compose_scalar = __commonJS({
|
|
|
76104
77163
|
onError(tagToken ?? token, "TAG_RESOLVE_FAILED", msg);
|
|
76105
77164
|
scalar = new Scalar.Scalar(value);
|
|
76106
77165
|
}
|
|
76107
|
-
scalar.range =
|
|
77166
|
+
scalar.range = range2;
|
|
76108
77167
|
scalar.source = value;
|
|
76109
77168
|
if (type)
|
|
76110
77169
|
scalar.type = type;
|
|
@@ -78716,14 +79775,14 @@ var init_parser7 = __esm({
|
|
|
78716
79775
|
// src/agent/skills/registry.js
|
|
78717
79776
|
import { existsSync as existsSync5 } from "fs";
|
|
78718
79777
|
import { readdir as readdir2, readFile as readFile2, realpath as realpath2, lstat as lstat2 } from "fs/promises";
|
|
78719
|
-
import { resolve as
|
|
79778
|
+
import { resolve as resolve6, join as join3, isAbsolute as isAbsolute5, sep as sep4, relative } from "path";
|
|
78720
79779
|
function isPathInside(basePath, targetPath) {
|
|
78721
|
-
const base2 =
|
|
78722
|
-
const target =
|
|
79780
|
+
const base2 = resolve6(basePath);
|
|
79781
|
+
const target = resolve6(targetPath);
|
|
78723
79782
|
const rel = relative(base2, target);
|
|
78724
79783
|
if (rel === "") return true;
|
|
78725
79784
|
if (rel === ".." || rel.startsWith(`..${sep4}`)) return false;
|
|
78726
|
-
if (
|
|
79785
|
+
if (isAbsolute5(rel)) return false;
|
|
78727
79786
|
return true;
|
|
78728
79787
|
}
|
|
78729
79788
|
function isSafeEntryName(name) {
|
|
@@ -78740,7 +79799,7 @@ var init_registry = __esm({
|
|
|
78740
79799
|
SKILL_FILE_NAME = "SKILL.md";
|
|
78741
79800
|
SkillRegistry = class {
|
|
78742
79801
|
constructor({ repoRoot, skillDirs = DEFAULT_SKILL_DIRS, debug = false } = {}) {
|
|
78743
|
-
this.repoRoot = repoRoot ?
|
|
79802
|
+
this.repoRoot = repoRoot ? resolve6(repoRoot) : process.cwd();
|
|
78744
79803
|
this.repoRootReal = null;
|
|
78745
79804
|
this.skillDirs = Array.isArray(skillDirs) && skillDirs.length > 0 ? skillDirs : DEFAULT_SKILL_DIRS;
|
|
78746
79805
|
this.debug = debug;
|
|
@@ -78794,8 +79853,8 @@ var init_registry = __esm({
|
|
|
78794
79853
|
}
|
|
78795
79854
|
}
|
|
78796
79855
|
async _resolveSkillDir(skillDir) {
|
|
78797
|
-
const resolved =
|
|
78798
|
-
const repoRoot = this.repoRootReal ||
|
|
79856
|
+
const resolved = isAbsolute5(skillDir) ? resolve6(skillDir) : resolve6(this.repoRoot, skillDir);
|
|
79857
|
+
const repoRoot = this.repoRootReal || resolve6(this.repoRoot);
|
|
78799
79858
|
const resolvedReal = await this._resolveRealPath(resolved);
|
|
78800
79859
|
if (!resolvedReal) return null;
|
|
78801
79860
|
if (!isPathInside(repoRoot, resolvedReal)) {
|
|
@@ -78985,7 +80044,7 @@ function extractErrorInfo(error) {
|
|
|
78985
80044
|
};
|
|
78986
80045
|
}
|
|
78987
80046
|
function sleep(ms) {
|
|
78988
|
-
return new Promise((
|
|
80047
|
+
return new Promise((resolve9) => setTimeout(resolve9, ms));
|
|
78989
80048
|
}
|
|
78990
80049
|
var DEFAULT_RETRYABLE_ERRORS, RetryManager;
|
|
78991
80050
|
var init_RetryManager = __esm({
|
|
@@ -79917,7 +80976,7 @@ var init_built_in_server = __esm({
|
|
|
79917
80976
|
}
|
|
79918
80977
|
});
|
|
79919
80978
|
this.registerHandlers();
|
|
79920
|
-
return new Promise((
|
|
80979
|
+
return new Promise((resolve9, reject2) => {
|
|
79921
80980
|
this.httpServer.listen(this.port, this.host, async () => {
|
|
79922
80981
|
const address = this.httpServer.address();
|
|
79923
80982
|
this.port = address.port;
|
|
@@ -79927,7 +80986,7 @@ var init_built_in_server = __esm({
|
|
|
79927
80986
|
console.log(`[MCP] Messages endpoint: http://${this.host}:${this.port}/messages`);
|
|
79928
80987
|
}
|
|
79929
80988
|
this.emit("ready", { host: this.host, port: this.port });
|
|
79930
|
-
|
|
80989
|
+
resolve9({ host: this.host, port: this.port });
|
|
79931
80990
|
});
|
|
79932
80991
|
this.httpServer.on("error", reject2);
|
|
79933
80992
|
});
|
|
@@ -80146,7 +81205,7 @@ var init_built_in_server = __esm({
|
|
|
80146
81205
|
* Parse request body as JSON
|
|
80147
81206
|
*/
|
|
80148
81207
|
async parseRequestBody(req) {
|
|
80149
|
-
return new Promise((
|
|
81208
|
+
return new Promise((resolve9, reject2) => {
|
|
80150
81209
|
let body = "";
|
|
80151
81210
|
req.on("data", (chunk) => {
|
|
80152
81211
|
body += chunk.toString();
|
|
@@ -80154,7 +81213,7 @@ var init_built_in_server = __esm({
|
|
|
80154
81213
|
req.on("end", () => {
|
|
80155
81214
|
try {
|
|
80156
81215
|
const parsed = body ? JSON.parse(body) : null;
|
|
80157
|
-
|
|
81216
|
+
resolve9(parsed);
|
|
80158
81217
|
} catch (error) {
|
|
80159
81218
|
reject2(error);
|
|
80160
81219
|
}
|
|
@@ -80461,12 +81520,12 @@ data: ${JSON.stringify(data2)}
|
|
|
80461
81520
|
}
|
|
80462
81521
|
this.connections.clear();
|
|
80463
81522
|
if (this.httpServer) {
|
|
80464
|
-
return new Promise((
|
|
81523
|
+
return new Promise((resolve9) => {
|
|
80465
81524
|
this.httpServer.close(() => {
|
|
80466
81525
|
if (this.debug) {
|
|
80467
81526
|
console.log("[MCP] Built-in server stopped");
|
|
80468
81527
|
}
|
|
80469
|
-
|
|
81528
|
+
resolve9();
|
|
80470
81529
|
});
|
|
80471
81530
|
});
|
|
80472
81531
|
}
|
|
@@ -80801,8 +81860,8 @@ ${opts.schema}`;
|
|
|
80801
81860
|
break;
|
|
80802
81861
|
}
|
|
80803
81862
|
} else if (!processEnded) {
|
|
80804
|
-
await new Promise((
|
|
80805
|
-
resolver =
|
|
81863
|
+
await new Promise((resolve9) => {
|
|
81864
|
+
resolver = resolve9;
|
|
80806
81865
|
});
|
|
80807
81866
|
}
|
|
80808
81867
|
}
|
|
@@ -81062,12 +82121,12 @@ async function createCodexEngine(options = {}) {
|
|
|
81062
82121
|
}
|
|
81063
82122
|
}
|
|
81064
82123
|
if (message.id !== void 0 && pendingRequests.has(message.id)) {
|
|
81065
|
-
const { resolve:
|
|
82124
|
+
const { resolve: resolve9, reject: reject2 } = pendingRequests.get(message.id);
|
|
81066
82125
|
pendingRequests.delete(message.id);
|
|
81067
82126
|
if (message.error) {
|
|
81068
82127
|
reject2(new Error(message.error.message || JSON.stringify(message.error)));
|
|
81069
82128
|
} else {
|
|
81070
|
-
|
|
82129
|
+
resolve9(message.result);
|
|
81071
82130
|
}
|
|
81072
82131
|
}
|
|
81073
82132
|
if (message.method === "codex/event" && message.params) {
|
|
@@ -81088,7 +82147,7 @@ async function createCodexEngine(options = {}) {
|
|
|
81088
82147
|
});
|
|
81089
82148
|
}
|
|
81090
82149
|
function sendRequest(method, params = {}) {
|
|
81091
|
-
return new Promise((
|
|
82150
|
+
return new Promise((resolve9, reject2) => {
|
|
81092
82151
|
const id = ++requestId;
|
|
81093
82152
|
const request = {
|
|
81094
82153
|
jsonrpc: "2.0",
|
|
@@ -81096,7 +82155,7 @@ async function createCodexEngine(options = {}) {
|
|
|
81096
82155
|
method,
|
|
81097
82156
|
params
|
|
81098
82157
|
};
|
|
81099
|
-
pendingRequests.set(id, { resolve:
|
|
82158
|
+
pendingRequests.set(id, { resolve: resolve9, reject: reject2 });
|
|
81100
82159
|
setTimeout(() => {
|
|
81101
82160
|
if (pendingRequests.has(id)) {
|
|
81102
82161
|
pendingRequests.delete(id);
|
|
@@ -81159,7 +82218,7 @@ ${prompt}`;
|
|
|
81159
82218
|
const reqId = requestId + 1;
|
|
81160
82219
|
let fullResponse = "";
|
|
81161
82220
|
let gotSessionId = false;
|
|
81162
|
-
const eventPromise = new Promise((
|
|
82221
|
+
const eventPromise = new Promise((resolve9) => {
|
|
81163
82222
|
eventHandlers.set(reqId, (eventParams) => {
|
|
81164
82223
|
const msg = eventParams.msg;
|
|
81165
82224
|
if (msg.type === "session_configured" && msg.session_id && !gotSessionId) {
|
|
@@ -81179,7 +82238,7 @@ ${prompt}`;
|
|
|
81179
82238
|
});
|
|
81180
82239
|
setTimeout(() => {
|
|
81181
82240
|
eventHandlers.delete(reqId);
|
|
81182
|
-
|
|
82241
|
+
resolve9();
|
|
81183
82242
|
}, 6e5);
|
|
81184
82243
|
});
|
|
81185
82244
|
const resultPromise = sendRequest("tools/call", {
|
|
@@ -81369,7 +82428,7 @@ import { randomUUID as randomUUID6 } from "crypto";
|
|
|
81369
82428
|
import { EventEmitter as EventEmitter5 } from "events";
|
|
81370
82429
|
import { existsSync as existsSync6 } from "fs";
|
|
81371
82430
|
import { readFile as readFile3, stat, readdir as readdir3 } from "fs/promises";
|
|
81372
|
-
import { resolve as
|
|
82431
|
+
import { resolve as resolve7, isAbsolute as isAbsolute6, dirname as dirname5, basename, normalize as normalize2, sep as sep5 } from "path";
|
|
81373
82432
|
function extractWrappedToolName(wrappedToolError) {
|
|
81374
82433
|
if (!wrappedToolError || typeof wrappedToolError !== "string") {
|
|
81375
82434
|
return "unknown";
|
|
@@ -81401,6 +82460,7 @@ var init_ProbeAgent = __esm({
|
|
|
81401
82460
|
init_imageConfig();
|
|
81402
82461
|
init_tools2();
|
|
81403
82462
|
init_common();
|
|
82463
|
+
init_fileTracker();
|
|
81404
82464
|
init_probeTool();
|
|
81405
82465
|
init_mockProvider();
|
|
81406
82466
|
init_index();
|
|
@@ -81442,7 +82502,7 @@ var init_ProbeAgent = __esm({
|
|
|
81442
82502
|
* @param {string} [options.customPrompt] - Custom prompt to replace the default system message
|
|
81443
82503
|
* @param {string} [options.systemPrompt] - Alias for customPrompt; takes precedence when both are provided
|
|
81444
82504
|
* @param {string} [options.promptType] - Predefined prompt type (code-explorer, code-searcher, architect, code-review, support)
|
|
81445
|
-
* @param {boolean} [options.allowEdit=false] - Allow the use of the '
|
|
82505
|
+
* @param {boolean} [options.allowEdit=false] - Allow the use of the 'edit' and 'create' tools
|
|
81446
82506
|
* @param {boolean} [options.enableDelegate=false] - Enable the delegate tool for task distribution to subagents
|
|
81447
82507
|
* @param {boolean} [options.enableExecutePlan=false] - Enable the execute_plan DSL orchestration tool
|
|
81448
82508
|
* @param {string} [options.architectureFileName] - Architecture context filename to embed from repo root (defaults to AGENTS.md with CLAUDE.md fallback; ARCHITECTURE.md is always included when present)
|
|
@@ -81491,6 +82551,7 @@ var init_ProbeAgent = __esm({
|
|
|
81491
82551
|
this.customPrompt = options.systemPrompt || options.customPrompt || null;
|
|
81492
82552
|
this.promptType = options.promptType || "code-explorer";
|
|
81493
82553
|
this.allowEdit = !!options.allowEdit;
|
|
82554
|
+
this.hashLines = options.hashLines !== void 0 ? !!options.hashLines : this.allowEdit;
|
|
81494
82555
|
this.enableDelegate = !!options.enableDelegate;
|
|
81495
82556
|
this.enableExecutePlan = !!options.enableExecutePlan;
|
|
81496
82557
|
this.debug = options.debug || process.env.DEBUG === "1";
|
|
@@ -81552,7 +82613,8 @@ var init_ProbeAgent = __esm({
|
|
|
81552
82613
|
if (this.debug) {
|
|
81553
82614
|
console.log(`[DEBUG] Generated session ID for agent: ${this.sessionId}`);
|
|
81554
82615
|
console.log(`[DEBUG] Maximum tool iterations configured: ${MAX_TOOL_ITERATIONS}`);
|
|
81555
|
-
console.log(`[DEBUG] Allow Edit
|
|
82616
|
+
console.log(`[DEBUG] Allow Edit: ${this.allowEdit}`);
|
|
82617
|
+
console.log(`[DEBUG] Hash Lines: ${this.hashLines}`);
|
|
81556
82618
|
console.log(`[DEBUG] Search delegation enabled: ${this.searchDelegate}`);
|
|
81557
82619
|
console.log(`[DEBUG] Workspace root: ${this.workspaceRoot}`);
|
|
81558
82620
|
console.log(`[DEBUG] Working directory (cwd): ${this.cwd}`);
|
|
@@ -81937,9 +82999,12 @@ var init_ProbeAgent = __esm({
|
|
|
81937
82999
|
cwd: this.cwd,
|
|
81938
83000
|
workspaceRoot: this.workspaceRoot,
|
|
81939
83001
|
allowedFolders: this.allowedFolders,
|
|
83002
|
+
// File state tracking for safe multi-edit workflows (only when editing is enabled)
|
|
83003
|
+
fileTracker: this.allowEdit ? new FileTracker({ debug: this.debug }) : null,
|
|
81940
83004
|
outline: this.outline,
|
|
81941
83005
|
searchDelegate: this.searchDelegate,
|
|
81942
83006
|
allowEdit: this.allowEdit,
|
|
83007
|
+
hashLines: this.hashLines,
|
|
81943
83008
|
enableDelegate: this.enableDelegate,
|
|
81944
83009
|
enableExecutePlan: this.enableExecutePlan,
|
|
81945
83010
|
enableBash: this.enableBash,
|
|
@@ -82724,7 +83789,7 @@ var init_ProbeAgent = __esm({
|
|
|
82724
83789
|
let resolvedPath = imagePath;
|
|
82725
83790
|
if (!imagePath.includes("/") && !imagePath.includes("\\")) {
|
|
82726
83791
|
for (const dir of listFilesDirectories) {
|
|
82727
|
-
const potentialPath =
|
|
83792
|
+
const potentialPath = resolve7(dir, imagePath);
|
|
82728
83793
|
const loaded = await this.loadImageIfValid(potentialPath);
|
|
82729
83794
|
if (loaded) {
|
|
82730
83795
|
if (this.debug) {
|
|
@@ -82794,8 +83859,8 @@ var init_ProbeAgent = __esm({
|
|
|
82794
83859
|
const allowedDirs = this.allowedFolders && this.allowedFolders.length > 0 ? this.allowedFolders : [process.cwd()];
|
|
82795
83860
|
let absolutePath;
|
|
82796
83861
|
let isPathAllowed2 = false;
|
|
82797
|
-
if (
|
|
82798
|
-
absolutePath = safeRealpath(
|
|
83862
|
+
if (isAbsolute6(imagePath)) {
|
|
83863
|
+
absolutePath = safeRealpath(resolve7(imagePath));
|
|
82799
83864
|
isPathAllowed2 = allowedDirs.some((dir) => {
|
|
82800
83865
|
const resolvedDir = safeRealpath(dir);
|
|
82801
83866
|
return absolutePath === resolvedDir || absolutePath.startsWith(resolvedDir + sep5);
|
|
@@ -82803,7 +83868,7 @@ var init_ProbeAgent = __esm({
|
|
|
82803
83868
|
} else {
|
|
82804
83869
|
for (const dir of allowedDirs) {
|
|
82805
83870
|
const resolvedDir = safeRealpath(dir);
|
|
82806
|
-
const resolvedPath = safeRealpath(
|
|
83871
|
+
const resolvedPath = safeRealpath(resolve7(dir, imagePath));
|
|
82807
83872
|
if (resolvedPath === resolvedDir || resolvedPath.startsWith(resolvedDir + sep5)) {
|
|
82808
83873
|
absolutePath = resolvedPath;
|
|
82809
83874
|
isPathAllowed2 = true;
|
|
@@ -82993,7 +84058,7 @@ var init_ProbeAgent = __esm({
|
|
|
82993
84058
|
let guidanceCandidates = [];
|
|
82994
84059
|
if (hasConfiguredName) {
|
|
82995
84060
|
const targetName = basename(configuredName);
|
|
82996
|
-
if (configuredName !== targetName || configuredName.includes("/") || configuredName.includes("\\") || configuredName.includes("..") ||
|
|
84061
|
+
if (configuredName !== targetName || configuredName.includes("/") || configuredName.includes("\\") || configuredName.includes("..") || isAbsolute6(configuredName)) {
|
|
82997
84062
|
console.warn(`[WARN] Invalid architectureFileName (must be a simple filename): ${configuredName}`);
|
|
82998
84063
|
} else if (targetName) {
|
|
82999
84064
|
const targetLower = targetName.toLowerCase();
|
|
@@ -83060,7 +84125,7 @@ var init_ProbeAgent = __esm({
|
|
|
83060
84125
|
pushEntry(architectureMatch);
|
|
83061
84126
|
const contexts = [];
|
|
83062
84127
|
for (const entry of uniqueEntries) {
|
|
83063
|
-
const filePath =
|
|
84128
|
+
const filePath = resolve7(rootDirectory, entry.name);
|
|
83064
84129
|
try {
|
|
83065
84130
|
const content = await readFile3(filePath, "utf8");
|
|
83066
84131
|
let kind = "other";
|
|
@@ -83125,10 +84190,10 @@ ${this.architectureContext.content}
|
|
|
83125
84190
|
}
|
|
83126
84191
|
_getSkillsRepoRoot() {
|
|
83127
84192
|
if (this.workspaceRoot) {
|
|
83128
|
-
return
|
|
84193
|
+
return resolve7(this.workspaceRoot);
|
|
83129
84194
|
}
|
|
83130
84195
|
if (this.allowedFolders && this.allowedFolders.length > 0) {
|
|
83131
|
-
return
|
|
84196
|
+
return resolve7(this.allowedFolders[0]);
|
|
83132
84197
|
}
|
|
83133
84198
|
return process.cwd();
|
|
83134
84199
|
}
|
|
@@ -83317,10 +84382,6 @@ Workspace: ${this.allowedFolders.join(", ")}`;
|
|
|
83317
84382
|
}
|
|
83318
84383
|
if (isToolAllowed("readImage")) {
|
|
83319
84384
|
toolDefinitions += `${readImageToolDefinition}
|
|
83320
|
-
`;
|
|
83321
|
-
}
|
|
83322
|
-
if (this.allowEdit && isToolAllowed("implement")) {
|
|
83323
|
-
toolDefinitions += `${implementToolDefinition}
|
|
83324
84385
|
`;
|
|
83325
84386
|
}
|
|
83326
84387
|
if (this.allowEdit && isToolAllowed("edit")) {
|
|
@@ -83402,7 +84463,7 @@ The configuration is loaded from src/config.js lines 15-25 which contains the da
|
|
|
83402
84463
|
availableToolsList += "- query: Search code using structural AST patterns.\n";
|
|
83403
84464
|
}
|
|
83404
84465
|
if (isToolAllowed("extract")) {
|
|
83405
|
-
availableToolsList +=
|
|
84466
|
+
availableToolsList += '- extract: Extract specific code blocks or lines from files. Use with symbol targets (e.g. "file.js#funcName") to get line numbers for line-targeted editing.\n';
|
|
83406
84467
|
}
|
|
83407
84468
|
if (isToolAllowed("listFiles")) {
|
|
83408
84469
|
availableToolsList += "- listFiles: List files and directories in a specified location.\n";
|
|
@@ -83419,11 +84480,8 @@ The configuration is loaded from src/config.js lines 15-25 which contains the da
|
|
|
83419
84480
|
if (isToolAllowed("readImage")) {
|
|
83420
84481
|
availableToolsList += "- readImage: Read and load an image file for AI analysis.\n";
|
|
83421
84482
|
}
|
|
83422
|
-
if (this.allowEdit && isToolAllowed("implement")) {
|
|
83423
|
-
availableToolsList += "- implement: Implement a feature or fix a bug using aider.\n";
|
|
83424
|
-
}
|
|
83425
84483
|
if (this.allowEdit && isToolAllowed("edit")) {
|
|
83426
|
-
availableToolsList += "- edit: Edit files using
|
|
84484
|
+
availableToolsList += "- edit: Edit files using text replacement, AST-aware symbol operations, or line-targeted editing.\n";
|
|
83427
84485
|
}
|
|
83428
84486
|
if (this.allowEdit && isToolAllowed("create")) {
|
|
83429
84487
|
availableToolsList += "- create: Create new files with specified content.\n";
|
|
@@ -83511,8 +84569,14 @@ Follow these instructions carefully:
|
|
|
83511
84569
|
8. Once the task is fully completed, use the '<attempt_completion>' tool to provide the final result. This is the ONLY way to signal completion.
|
|
83512
84570
|
9. Prefer concise and focused search queries. Use specific keywords and phrases to narrow down results.${this.allowEdit ? `
|
|
83513
84571
|
10. When modifying files, choose the appropriate tool:
|
|
83514
|
-
- Use 'edit' for
|
|
83515
|
-
|
|
84572
|
+
- Use 'edit' for all code modifications:
|
|
84573
|
+
* For small changes (a line or a few lines), use old_string + new_string \u2014 copy old_string verbatim from the file.
|
|
84574
|
+
* For rewriting entire functions/classes/methods, use the symbol parameter instead (no exact text matching needed).
|
|
84575
|
+
* For editing specific lines from search/extract output, use start_line (and optionally end_line) with the line numbers shown in the output.${this.hashLines ? ' Line references include content hashes (e.g. "42:ab") for integrity verification.' : ""}
|
|
84576
|
+
* For editing inside large functions: first use extract with the symbol target (e.g. "file.js#myFunction") to see the function with line numbers${this.hashLines ? " and hashes" : ""}, then use start_line/end_line to surgically edit specific lines within it.
|
|
84577
|
+
- Use 'create' for new files or complete file rewrites.
|
|
84578
|
+
- If an edit fails, read the error message \u2014 it tells you exactly how to fix the call and retry.
|
|
84579
|
+
- The system tracks which files you've seen via search/extract. If you try to edit a file you haven't read, or one that changed since you last read it, the edit will fail with instructions to re-read first. Always use extract before editing to ensure you have current file content.` : ""}
|
|
83516
84580
|
</instructions>
|
|
83517
84581
|
`;
|
|
83518
84582
|
let systemMessage = "";
|
|
@@ -84012,8 +85076,11 @@ You are working with a workspace. Available paths: ${workspaceDesc}
|
|
|
84012
85076
|
if (this.enableSkills && this.allowedTools.isEnabled("useSkill")) validTools.push("useSkill");
|
|
84013
85077
|
if (this.allowedTools.isEnabled("readImage")) validTools.push("readImage");
|
|
84014
85078
|
validTools.push("attempt_completion");
|
|
84015
|
-
if (this.allowEdit && this.allowedTools.isEnabled("
|
|
84016
|
-
validTools.push("
|
|
85079
|
+
if (this.allowEdit && this.allowedTools.isEnabled("edit")) {
|
|
85080
|
+
validTools.push("edit");
|
|
85081
|
+
}
|
|
85082
|
+
if (this.allowEdit && this.allowedTools.isEnabled("create")) {
|
|
85083
|
+
validTools.push("create");
|
|
84017
85084
|
}
|
|
84018
85085
|
if (this.enableBash && this.allowedTools.isEnabled("bash")) {
|
|
84019
85086
|
validTools.push("bash");
|
|
@@ -84235,7 +85302,7 @@ ${errorXml}
|
|
|
84235
85302
|
try {
|
|
84236
85303
|
let resolvedWorkingDirectory = this.workspaceRoot || this.cwd || this.allowedFolders && this.allowedFolders[0] || process.cwd();
|
|
84237
85304
|
if (params.workingDirectory) {
|
|
84238
|
-
const requestedDir = safeRealpath(
|
|
85305
|
+
const requestedDir = safeRealpath(isAbsolute6(params.workingDirectory) ? resolve7(params.workingDirectory) : resolve7(resolvedWorkingDirectory, params.workingDirectory));
|
|
84239
85306
|
const isWithinAllowed = !this.allowedFolders || this.allowedFolders.length === 0 || this.allowedFolders.some((folder) => {
|
|
84240
85307
|
const resolvedFolder = safeRealpath(folder);
|
|
84241
85308
|
return requestedDir === resolvedFolder || requestedDir.startsWith(resolvedFolder + sep5);
|
|
@@ -84306,6 +85373,8 @@ ${errorXml}
|
|
|
84306
85373
|
// Inherit bash enablement
|
|
84307
85374
|
bashConfig: this.bashConfig,
|
|
84308
85375
|
// Inherit bash configuration
|
|
85376
|
+
allowEdit: this.allowEdit,
|
|
85377
|
+
// Inherit edit/create permission
|
|
84309
85378
|
allowedTools: allowedToolsForDelegate,
|
|
84310
85379
|
// Inherit allowed tools from parent
|
|
84311
85380
|
debug: this.debug,
|
|
@@ -84466,6 +85535,25 @@ ${errorXml}
|
|
|
84466
85535
|
}
|
|
84467
85536
|
break;
|
|
84468
85537
|
}
|
|
85538
|
+
if (options.schema) {
|
|
85539
|
+
let contentToCheck = assistantResponseContent;
|
|
85540
|
+
contentToCheck = contentToCheck.replace(/<thinking>[\s\S]*?<\/thinking>/gi, "").trim();
|
|
85541
|
+
contentToCheck = contentToCheck.replace(/<thinking>[\s\S]*$/gi, "").trim();
|
|
85542
|
+
const cleanedJson = cleanSchemaResponse(contentToCheck);
|
|
85543
|
+
try {
|
|
85544
|
+
JSON.parse(cleanedJson);
|
|
85545
|
+
const validation = validateJsonResponse(cleanedJson, { debug: this.debug, schema: options.schema });
|
|
85546
|
+
if (validation.isValid) {
|
|
85547
|
+
if (this.debug) {
|
|
85548
|
+
console.log(`[DEBUG] Issue #443: Accepting valid JSON response without attempt_completion (${cleanedJson.length} chars)`);
|
|
85549
|
+
}
|
|
85550
|
+
finalResult = cleanedJson;
|
|
85551
|
+
completionAttempted = true;
|
|
85552
|
+
break;
|
|
85553
|
+
}
|
|
85554
|
+
} catch {
|
|
85555
|
+
}
|
|
85556
|
+
}
|
|
84469
85557
|
consecutiveNoToolCount++;
|
|
84470
85558
|
const isIdentical = lastNoToolResponse !== null && assistantResponseContent === lastNoToolResponse;
|
|
84471
85559
|
const isSemanticallyStuck = lastNoToolResponse !== null && areBothStuckResponses(lastNoToolResponse, assistantResponseContent);
|
|
@@ -85443,7 +86531,7 @@ import {
|
|
|
85443
86531
|
McpError
|
|
85444
86532
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
85445
86533
|
import { readFileSync as readFileSync2, existsSync as existsSync7 } from "fs";
|
|
85446
|
-
import { resolve as
|
|
86534
|
+
import { resolve as resolve8 } from "path";
|
|
85447
86535
|
|
|
85448
86536
|
// src/agent/acp/server.js
|
|
85449
86537
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
@@ -85702,8 +86790,8 @@ var ACPConnection = class extends EventEmitter6 {
|
|
|
85702
86790
|
if (params !== null) {
|
|
85703
86791
|
message.params = params;
|
|
85704
86792
|
}
|
|
85705
|
-
return new Promise((
|
|
85706
|
-
this.pendingRequests.set(id, { resolve:
|
|
86793
|
+
return new Promise((resolve9, reject2) => {
|
|
86794
|
+
this.pendingRequests.set(id, { resolve: resolve9, reject: reject2 });
|
|
85707
86795
|
this.sendMessage(message);
|
|
85708
86796
|
setTimeout(() => {
|
|
85709
86797
|
if (this.pendingRequests.has(id)) {
|
|
@@ -86117,7 +87205,7 @@ dotenv3.config();
|
|
|
86117
87205
|
function readInputContent(input) {
|
|
86118
87206
|
if (!input) return null;
|
|
86119
87207
|
try {
|
|
86120
|
-
const resolvedPath =
|
|
87208
|
+
const resolvedPath = resolve8(input);
|
|
86121
87209
|
if (existsSync7(resolvedPath)) {
|
|
86122
87210
|
return readFileSync2(resolvedPath, "utf-8").trim();
|
|
86123
87211
|
}
|
|
@@ -86126,7 +87214,7 @@ function readInputContent(input) {
|
|
|
86126
87214
|
return input;
|
|
86127
87215
|
}
|
|
86128
87216
|
function readFromStdin() {
|
|
86129
|
-
return new Promise((
|
|
87217
|
+
return new Promise((resolve9, reject2) => {
|
|
86130
87218
|
let data2 = "";
|
|
86131
87219
|
let hasReceivedData = false;
|
|
86132
87220
|
let dataChunks = [];
|
|
@@ -86151,7 +87239,7 @@ function readFromStdin() {
|
|
|
86151
87239
|
if (!trimmed && dataChunks.length === 0) {
|
|
86152
87240
|
reject2(new Error("No input received from stdin"));
|
|
86153
87241
|
} else {
|
|
86154
|
-
|
|
87242
|
+
resolve9(trimmed);
|
|
86155
87243
|
}
|
|
86156
87244
|
});
|
|
86157
87245
|
process.stdin.on("error", (error) => {
|
|
@@ -86183,7 +87271,8 @@ function parseArgs() {
|
|
|
86183
87271
|
schema: null,
|
|
86184
87272
|
provider: null,
|
|
86185
87273
|
model: null,
|
|
86186
|
-
allowEdit: false,
|
|
87274
|
+
allowEdit: process.env.ALLOW_EDIT === "1" || false,
|
|
87275
|
+
hashLines: process.env.HASH_LINES !== void 0 ? process.env.HASH_LINES === "1" : void 0,
|
|
86187
87276
|
enableDelegate: false,
|
|
86188
87277
|
verbose: false,
|
|
86189
87278
|
help: false,
|
|
@@ -86232,6 +87321,10 @@ function parseArgs() {
|
|
|
86232
87321
|
config.verbose = true;
|
|
86233
87322
|
} else if (arg === "--allow-edit") {
|
|
86234
87323
|
config.allowEdit = true;
|
|
87324
|
+
} else if (arg === "--hash-lines") {
|
|
87325
|
+
config.hashLines = true;
|
|
87326
|
+
} else if (arg === "--no-hash-lines") {
|
|
87327
|
+
config.hashLines = false;
|
|
86235
87328
|
} else if (arg === "--enable-delegate") {
|
|
86236
87329
|
config.enableDelegate = true;
|
|
86237
87330
|
} else if (arg === "--no-delegate") {
|
|
@@ -86328,12 +87421,14 @@ Options:
|
|
|
86328
87421
|
--schema <schema|file> Output schema (JSON, XML, any format - text or file path)
|
|
86329
87422
|
--provider <name> Force AI provider: anthropic, openai, google
|
|
86330
87423
|
--model <name> Override model name
|
|
86331
|
-
--allow-edit Enable code modification capabilities
|
|
87424
|
+
--allow-edit Enable code modification capabilities (edit + create tools)
|
|
87425
|
+
--hash-lines Annotate search/extract output with line hashes (default: on when --allow-edit)
|
|
87426
|
+
--no-hash-lines Disable line hash annotations even with --allow-edit
|
|
86332
87427
|
--enable-delegate Enable delegate tool for task distribution to subagents
|
|
86333
87428
|
--allowed-tools <tools> Filter available tools (comma-separated list)
|
|
86334
87429
|
Use '*' or 'all' for all tools (default)
|
|
86335
87430
|
Use 'none' or '' for no tools (raw AI mode)
|
|
86336
|
-
Specific tools: search,query,extract,listFiles,searchFiles,listSkills,useSkill
|
|
87431
|
+
Specific tools: search,query,extract,edit,create,listFiles,searchFiles,listSkills,useSkill
|
|
86337
87432
|
Supports exclusion: '*,!bash' (all except bash)
|
|
86338
87433
|
--disable-tools Disable all tools (raw AI mode, no code analysis)
|
|
86339
87434
|
Convenience flag equivalent to --allowed-tools none
|
|
@@ -86371,6 +87466,8 @@ Environment Variables:
|
|
|
86371
87466
|
FORCE_PROVIDER Force specific provider (anthropic, openai, google)
|
|
86372
87467
|
MODEL_NAME Override model name
|
|
86373
87468
|
MAX_RESPONSE_TOKENS Maximum tokens for AI response
|
|
87469
|
+
ALLOW_EDIT Enable code modification (set to '1')
|
|
87470
|
+
HASH_LINES Annotate output with line hashes (set to '1'; default: on with ALLOW_EDIT)
|
|
86374
87471
|
DEBUG Enable verbose mode (set to '1')
|
|
86375
87472
|
|
|
86376
87473
|
Examples:
|
|
@@ -86387,6 +87484,8 @@ Examples:
|
|
|
86387
87484
|
probe agent "Explain this code" --allowed-tools search,extract # Only search and extract
|
|
86388
87485
|
probe agent "What is this project about?" --allowed-tools none # Raw AI mode (no tools)
|
|
86389
87486
|
probe agent "Tell me about this project" --disable-tools # Raw AI mode (convenience flag)
|
|
87487
|
+
probe agent "Fix the off-by-one error" --allow-edit --path ./src # Enable code editing
|
|
87488
|
+
ALLOW_EDIT=1 probe agent "Refactor the login flow" # Edit via env var
|
|
86390
87489
|
probe agent --mcp # Start MCP server mode
|
|
86391
87490
|
probe agent --acp # Start ACP server mode
|
|
86392
87491
|
|