@probelabs/probe 0.6.0-rc198 → 0.6.0-rc200
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/binaries/probe-v0.6.0-rc200-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc200-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc200-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc200-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc200-x86_64-unknown-linux-musl.tar.gz +0 -0
- package/build/agent/index.js +1588 -1530
- package/build/agent/xmlParsingUtils.js +6 -3
- package/build/delegate.js +5 -1
- package/build/tools/common.js +29 -4
- package/build/tools/index.js +3 -1
- package/build/tools/vercel.js +17 -4
- package/cjs/agent/ProbeAgent.cjs +2240 -2182
- package/cjs/index.cjs +690 -670
- package/package.json +1 -1
- package/src/agent/xmlParsingUtils.js +6 -3
- package/src/delegate.js +5 -1
- package/src/tools/common.js +29 -4
- package/src/tools/index.js +3 -1
- package/src/tools/vercel.js +17 -4
- package/bin/binaries/probe-v0.6.0-rc198-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc198-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc198-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc198-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc198-x86_64-unknown-linux-musl.tar.gz +0 -0
package/cjs/agent/ProbeAgent.cjs
CHANGED
|
@@ -30505,7 +30505,9 @@ async function delegate({
|
|
|
30505
30505
|
debug,
|
|
30506
30506
|
tracer,
|
|
30507
30507
|
path: path9,
|
|
30508
|
-
//
|
|
30508
|
+
// Workspace root (from delegateTool)
|
|
30509
|
+
cwd: path9,
|
|
30510
|
+
// Explicitly set cwd to workspace root to prevent path doubling
|
|
30509
30511
|
provider,
|
|
30510
30512
|
// Inherit from parent
|
|
30511
30513
|
model,
|
|
@@ -34821,2311 +34823,2367 @@ var init_zod = __esm({
|
|
|
34821
34823
|
}
|
|
34822
34824
|
});
|
|
34823
34825
|
|
|
34824
|
-
// src/tools/
|
|
34825
|
-
function
|
|
34826
|
-
|
|
34827
|
-
|
|
34828
|
-
|
|
34829
|
-
|
|
34830
|
-
delegate: delegateSchema,
|
|
34831
|
-
bash: bashSchema,
|
|
34832
|
-
attempt_completion: attemptCompletionSchema
|
|
34833
|
-
};
|
|
34834
|
-
const schema = schemaMap[toolName];
|
|
34835
|
-
if (!schema) {
|
|
34836
|
-
return ["path", "directory", "pattern", "recursive", "includeHidden", "task", "files", "autoCommits", "result"];
|
|
34837
|
-
}
|
|
34838
|
-
if (toolName === "attempt_completion") {
|
|
34839
|
-
return ["result"];
|
|
34840
|
-
}
|
|
34841
|
-
if (schema && schema._def && schema._def.shape) {
|
|
34842
|
-
return Object.keys(schema._def.shape());
|
|
34843
|
-
}
|
|
34844
|
-
return [];
|
|
34845
|
-
}
|
|
34846
|
-
function parseXmlToolCall(xmlString, validTools = DEFAULT_VALID_TOOLS) {
|
|
34847
|
-
for (const toolName of validTools) {
|
|
34848
|
-
const openTag = `<${toolName}>`;
|
|
34849
|
-
const closeTag = `</${toolName}>`;
|
|
34850
|
-
const openIndex = xmlString.indexOf(openTag);
|
|
34851
|
-
if (openIndex === -1) {
|
|
34852
|
-
continue;
|
|
34853
|
-
}
|
|
34854
|
-
let closeIndex;
|
|
34855
|
-
if (toolName === "attempt_completion") {
|
|
34856
|
-
closeIndex = xmlString.lastIndexOf(closeTag);
|
|
34857
|
-
if (closeIndex !== -1 && closeIndex <= openIndex + openTag.length) {
|
|
34858
|
-
closeIndex = -1;
|
|
34859
|
-
}
|
|
34860
|
-
} else {
|
|
34861
|
-
closeIndex = xmlString.indexOf(closeTag, openIndex + openTag.length);
|
|
34862
|
-
}
|
|
34863
|
-
let hasClosingTag = closeIndex !== -1;
|
|
34864
|
-
if (closeIndex === -1) {
|
|
34865
|
-
closeIndex = xmlString.length;
|
|
34866
|
-
}
|
|
34867
|
-
const innerContent = xmlString.substring(
|
|
34868
|
-
openIndex + openTag.length,
|
|
34869
|
-
closeIndex
|
|
34870
|
-
);
|
|
34871
|
-
const params = {};
|
|
34872
|
-
const validParams = getValidParamsForTool(toolName);
|
|
34873
|
-
for (const paramName of validParams) {
|
|
34874
|
-
const paramOpenTag = `<${paramName}>`;
|
|
34875
|
-
const paramCloseTag = `</${paramName}>`;
|
|
34876
|
-
const paramOpenIndex = innerContent.indexOf(paramOpenTag);
|
|
34877
|
-
if (paramOpenIndex === -1) {
|
|
34878
|
-
continue;
|
|
34879
|
-
}
|
|
34880
|
-
let paramCloseIndex = innerContent.indexOf(paramCloseTag, paramOpenIndex + paramOpenTag.length);
|
|
34881
|
-
if (paramCloseIndex === -1) {
|
|
34882
|
-
let nextTagIndex = innerContent.length;
|
|
34883
|
-
for (const nextParam of validParams) {
|
|
34884
|
-
const nextOpenTag = `<${nextParam}>`;
|
|
34885
|
-
const nextIndex = innerContent.indexOf(nextOpenTag, paramOpenIndex + paramOpenTag.length);
|
|
34886
|
-
if (nextIndex !== -1 && nextIndex < nextTagIndex) {
|
|
34887
|
-
nextTagIndex = nextIndex;
|
|
34888
|
-
}
|
|
34889
|
-
}
|
|
34890
|
-
paramCloseIndex = nextTagIndex;
|
|
34891
|
-
}
|
|
34892
|
-
let paramValue = innerContent.substring(
|
|
34893
|
-
paramOpenIndex + paramOpenTag.length,
|
|
34894
|
-
paramCloseIndex
|
|
34895
|
-
).trim();
|
|
34896
|
-
if (paramValue.toLowerCase() === "true") {
|
|
34897
|
-
paramValue = true;
|
|
34898
|
-
} else if (paramValue.toLowerCase() === "false") {
|
|
34899
|
-
paramValue = false;
|
|
34900
|
-
} else if (!isNaN(paramValue) && paramValue.trim() !== "") {
|
|
34901
|
-
const num = Number(paramValue);
|
|
34902
|
-
if (Number.isFinite(num)) {
|
|
34903
|
-
paramValue = num;
|
|
34904
|
-
}
|
|
34905
|
-
}
|
|
34906
|
-
params[paramName] = paramValue;
|
|
34907
|
-
}
|
|
34908
|
-
if (toolName === "attempt_completion") {
|
|
34909
|
-
params["result"] = innerContent.trim();
|
|
34910
|
-
if (params.command) {
|
|
34911
|
-
delete params.command;
|
|
34912
|
-
}
|
|
34913
|
-
}
|
|
34914
|
-
return { toolName, params };
|
|
34915
|
-
}
|
|
34916
|
-
return null;
|
|
34917
|
-
}
|
|
34918
|
-
function createMessagePreview(message, charsPerSide = 200) {
|
|
34919
|
-
if (message === null || message === void 0) {
|
|
34920
|
-
return "null/undefined";
|
|
34921
|
-
}
|
|
34922
|
-
if (typeof message !== "string") {
|
|
34923
|
-
return "null/undefined";
|
|
34924
|
-
}
|
|
34925
|
-
const totalChars = charsPerSide * 2;
|
|
34926
|
-
if (message.length <= totalChars) {
|
|
34927
|
-
return message;
|
|
34928
|
-
}
|
|
34929
|
-
const start = message.substring(0, charsPerSide);
|
|
34930
|
-
const end = message.substring(message.length - charsPerSide);
|
|
34931
|
-
return `${start}...${end}`;
|
|
34932
|
-
}
|
|
34933
|
-
function parseTargets(targets) {
|
|
34934
|
-
if (!targets || typeof targets !== "string") {
|
|
34935
|
-
return [];
|
|
34826
|
+
// src/tools/edit.js
|
|
34827
|
+
function isPathAllowed(filePath, allowedFolders) {
|
|
34828
|
+
if (!allowedFolders || allowedFolders.length === 0) {
|
|
34829
|
+
const resolvedPath3 = (0, import_path5.resolve)(filePath);
|
|
34830
|
+
const cwd = (0, import_path5.resolve)(process.cwd());
|
|
34831
|
+
return resolvedPath3 === cwd || resolvedPath3.startsWith(cwd + import_path5.sep);
|
|
34936
34832
|
}
|
|
34937
|
-
|
|
34938
|
-
|
|
34939
|
-
|
|
34940
|
-
|
|
34941
|
-
const paths = pathStr.split(",").map((p4) => p4.trim()).filter((p4) => p4.length > 0);
|
|
34942
|
-
return paths.map((p4) => {
|
|
34943
|
-
if ((0, import_path5.isAbsolute)(p4)) {
|
|
34944
|
-
return p4;
|
|
34945
|
-
}
|
|
34946
|
-
return cwd ? (0, import_path5.resolve)(cwd, p4) : p4;
|
|
34833
|
+
const resolvedPath2 = (0, import_path5.resolve)(filePath);
|
|
34834
|
+
return allowedFolders.some((folder) => {
|
|
34835
|
+
const allowedPath = (0, import_path5.resolve)(folder);
|
|
34836
|
+
return resolvedPath2 === allowedPath || resolvedPath2.startsWith(allowedPath + import_path5.sep);
|
|
34947
34837
|
});
|
|
34948
34838
|
}
|
|
34949
|
-
function
|
|
34950
|
-
|
|
34951
|
-
|
|
34952
|
-
|
|
34953
|
-
|
|
34954
|
-
|
|
34955
|
-
filePart = target.substring(0, colonIdx);
|
|
34956
|
-
suffix = target.substring(colonIdx);
|
|
34957
|
-
} else if (hashIdx !== -1) {
|
|
34958
|
-
filePart = target.substring(0, hashIdx);
|
|
34959
|
-
suffix = target.substring(hashIdx);
|
|
34960
|
-
} else {
|
|
34961
|
-
filePart = target;
|
|
34962
|
-
suffix = "";
|
|
34963
|
-
}
|
|
34964
|
-
if (!(0, import_path5.isAbsolute)(filePart) && cwd) {
|
|
34965
|
-
filePart = (0, import_path5.resolve)(cwd, filePart);
|
|
34966
|
-
}
|
|
34967
|
-
return filePart + suffix;
|
|
34839
|
+
function parseFileToolOptions(options = {}) {
|
|
34840
|
+
return {
|
|
34841
|
+
debug: options.debug || false,
|
|
34842
|
+
allowedFolders: options.allowedFolders || [],
|
|
34843
|
+
cwd: options.cwd
|
|
34844
|
+
};
|
|
34968
34845
|
}
|
|
34969
|
-
var
|
|
34970
|
-
var
|
|
34971
|
-
"src/tools/
|
|
34846
|
+
var import_ai, import_fs4, import_path5, import_fs5, editTool, createTool, editSchema, createSchema, editDescription, createDescription, editToolDefinition, createToolDefinition;
|
|
34847
|
+
var init_edit = __esm({
|
|
34848
|
+
"src/tools/edit.js"() {
|
|
34972
34849
|
"use strict";
|
|
34973
|
-
|
|
34850
|
+
import_ai = require("ai");
|
|
34851
|
+
import_fs4 = require("fs");
|
|
34974
34852
|
import_path5 = require("path");
|
|
34975
|
-
|
|
34976
|
-
|
|
34977
|
-
|
|
34978
|
-
|
|
34979
|
-
|
|
34980
|
-
|
|
34981
|
-
path: external_exports.string().optional().default(".").describe("Path to search in"),
|
|
34982
|
-
language: external_exports.string().optional().default("rust").describe("Programming language to use for parsing"),
|
|
34983
|
-
allow_tests: external_exports.boolean().optional().default(true).describe("Allow test files in search results")
|
|
34984
|
-
});
|
|
34985
|
-
extractSchema = external_exports.object({
|
|
34986
|
-
targets: external_exports.string().optional().describe('File paths or symbols to extract from. Formats: "file.js" (whole file), "file.js:42" (line 42), "file.js:10-20" (lines 10-20), "file.js#funcName" (symbol). Multiple targets separated by spaces.'),
|
|
34987
|
-
input_content: external_exports.string().optional().describe("Text content to extract file paths from (alternative to targets)"),
|
|
34988
|
-
allow_tests: external_exports.boolean().optional().default(true).describe("Include test files in extraction results")
|
|
34989
|
-
});
|
|
34990
|
-
delegateSchema = external_exports.object({
|
|
34991
|
-
task: external_exports.string().describe("The task to delegate to a subagent. Be specific about what needs to be accomplished.")
|
|
34992
|
-
});
|
|
34993
|
-
bashSchema = external_exports.object({
|
|
34994
|
-
command: external_exports.string().describe("The bash command to execute"),
|
|
34995
|
-
workingDirectory: external_exports.string().optional().describe("Directory to execute the command in (optional)"),
|
|
34996
|
-
timeout: external_exports.number().optional().describe("Command timeout in milliseconds (optional)"),
|
|
34997
|
-
env: external_exports.record(external_exports.string()).optional().describe("Additional environment variables (optional)")
|
|
34998
|
-
});
|
|
34999
|
-
attemptCompletionSchema = {
|
|
35000
|
-
// Custom validation that requires result parameter but allows direct XML response
|
|
35001
|
-
safeParse: (params) => {
|
|
35002
|
-
if (!params || typeof params !== "object") {
|
|
35003
|
-
return {
|
|
35004
|
-
success: false,
|
|
35005
|
-
error: {
|
|
35006
|
-
issues: [{
|
|
35007
|
-
code: "invalid_type",
|
|
35008
|
-
expected: "object",
|
|
35009
|
-
received: typeof params,
|
|
35010
|
-
path: [],
|
|
35011
|
-
message: "Expected object"
|
|
35012
|
-
}]
|
|
35013
|
-
}
|
|
35014
|
-
};
|
|
35015
|
-
}
|
|
35016
|
-
if (!("result" in params)) {
|
|
35017
|
-
return {
|
|
35018
|
-
success: false,
|
|
35019
|
-
error: {
|
|
35020
|
-
issues: [{
|
|
35021
|
-
code: "invalid_type",
|
|
35022
|
-
expected: "string",
|
|
35023
|
-
received: "undefined",
|
|
35024
|
-
path: ["result"],
|
|
35025
|
-
message: "Required"
|
|
35026
|
-
}]
|
|
35027
|
-
}
|
|
35028
|
-
};
|
|
35029
|
-
}
|
|
35030
|
-
if (typeof params.result !== "string") {
|
|
35031
|
-
return {
|
|
35032
|
-
success: false,
|
|
35033
|
-
error: {
|
|
35034
|
-
issues: [{
|
|
35035
|
-
code: "invalid_type",
|
|
35036
|
-
expected: "string",
|
|
35037
|
-
received: typeof params.result,
|
|
35038
|
-
path: ["result"],
|
|
35039
|
-
message: "Expected string"
|
|
35040
|
-
}]
|
|
35041
|
-
}
|
|
35042
|
-
};
|
|
35043
|
-
}
|
|
35044
|
-
const filteredData = { result: params.result };
|
|
35045
|
-
return {
|
|
35046
|
-
success: true,
|
|
35047
|
-
data: filteredData
|
|
35048
|
-
};
|
|
35049
|
-
}
|
|
35050
|
-
};
|
|
35051
|
-
searchToolDefinition = `
|
|
35052
|
-
## search
|
|
35053
|
-
Description: Search code in the repository using Elasticsearch query syntax (except field based queries, e.g. "filename:..." NOT supported).
|
|
35054
|
-
|
|
35055
|
-
You need to focus on main keywords when constructing the query, and always use elastic search syntax like OR AND and brackets to group keywords.
|
|
34853
|
+
import_fs5 = require("fs");
|
|
34854
|
+
editTool = (options = {}) => {
|
|
34855
|
+
const { debug, allowedFolders, cwd } = parseFileToolOptions(options);
|
|
34856
|
+
return (0, import_ai.tool)({
|
|
34857
|
+
name: "edit",
|
|
34858
|
+
description: `Edit files using exact string replacement (Claude Code style).
|
|
35056
34859
|
|
|
35057
|
-
|
|
35058
|
-
- Ensure not to re-read the same symbols twice - reuse context from previous tool calls
|
|
35059
|
-
- Probe returns a session ID on first run - reuse it for subsequent calls to avoid redundant searches
|
|
35060
|
-
- Once data is returned, it's cached and won't return on next runs (this is expected behavior)
|
|
34860
|
+
This tool performs exact string replacements in files. It requires the old_string to match exactly what's in the file, including all whitespace and indentation.
|
|
35061
34861
|
|
|
35062
34862
|
Parameters:
|
|
35063
|
-
-
|
|
35064
|
-
-
|
|
35065
|
-
|
|
35066
|
-
|
|
35067
|
-
|
|
35068
|
-
Usage Example:
|
|
34863
|
+
- file_path: Path to the file to edit (absolute or relative)
|
|
34864
|
+
- old_string: Exact text to find and replace (must be unique in the file unless replace_all is true)
|
|
34865
|
+
- new_string: Text to replace with
|
|
34866
|
+
- replace_all: (optional) Replace all occurrences instead of requiring uniqueness
|
|
35069
34867
|
|
|
35070
|
-
|
|
34868
|
+
Important:
|
|
34869
|
+
- The old_string must match EXACTLY including whitespace
|
|
34870
|
+
- If old_string appears multiple times and replace_all is false, the edit will fail
|
|
34871
|
+
- Use larger context around the string to ensure uniqueness when needed`,
|
|
34872
|
+
inputSchema: {
|
|
34873
|
+
type: "object",
|
|
34874
|
+
properties: {
|
|
34875
|
+
file_path: {
|
|
34876
|
+
type: "string",
|
|
34877
|
+
description: "Path to the file to edit"
|
|
34878
|
+
},
|
|
34879
|
+
old_string: {
|
|
34880
|
+
type: "string",
|
|
34881
|
+
description: "Exact text to find and replace"
|
|
34882
|
+
},
|
|
34883
|
+
new_string: {
|
|
34884
|
+
type: "string",
|
|
34885
|
+
description: "Text to replace with"
|
|
34886
|
+
},
|
|
34887
|
+
replace_all: {
|
|
34888
|
+
type: "boolean",
|
|
34889
|
+
description: "Replace all occurrences (default: false)",
|
|
34890
|
+
default: false
|
|
34891
|
+
}
|
|
34892
|
+
},
|
|
34893
|
+
required: ["file_path", "old_string", "new_string"]
|
|
34894
|
+
},
|
|
34895
|
+
execute: async ({ file_path, old_string, new_string, replace_all = false }) => {
|
|
34896
|
+
try {
|
|
34897
|
+
if (!file_path || typeof file_path !== "string" || file_path.trim() === "") {
|
|
34898
|
+
return `Error editing file: Invalid file_path - must be a non-empty string`;
|
|
34899
|
+
}
|
|
34900
|
+
if (old_string === void 0 || old_string === null || typeof old_string !== "string") {
|
|
34901
|
+
return `Error editing file: Invalid old_string - must be a string`;
|
|
34902
|
+
}
|
|
34903
|
+
if (new_string === void 0 || new_string === null || typeof new_string !== "string") {
|
|
34904
|
+
return `Error editing file: Invalid new_string - must be a string`;
|
|
34905
|
+
}
|
|
34906
|
+
const resolvedPath2 = (0, import_path5.isAbsolute)(file_path) ? file_path : (0, import_path5.resolve)(cwd || process.cwd(), file_path);
|
|
34907
|
+
if (debug) {
|
|
34908
|
+
console.error(`[Edit] Attempting to edit file: ${resolvedPath2}`);
|
|
34909
|
+
}
|
|
34910
|
+
if (!isPathAllowed(resolvedPath2, allowedFolders)) {
|
|
34911
|
+
return `Error editing file: Permission denied - ${file_path} is outside allowed directories`;
|
|
34912
|
+
}
|
|
34913
|
+
if (!(0, import_fs5.existsSync)(resolvedPath2)) {
|
|
34914
|
+
return `Error editing file: File not found - ${file_path}`;
|
|
34915
|
+
}
|
|
34916
|
+
const content = await import_fs4.promises.readFile(resolvedPath2, "utf-8");
|
|
34917
|
+
if (!content.includes(old_string)) {
|
|
34918
|
+
return `Error editing file: String not found - the specified old_string was not found in ${file_path}`;
|
|
34919
|
+
}
|
|
34920
|
+
const occurrences = content.split(old_string).length - 1;
|
|
34921
|
+
if (!replace_all && occurrences > 1) {
|
|
34922
|
+
return `Error editing file: Multiple occurrences found - the old_string appears ${occurrences} times. Use replace_all: true to replace all occurrences, or provide more context to make the string unique.`;
|
|
34923
|
+
}
|
|
34924
|
+
let newContent;
|
|
34925
|
+
if (replace_all) {
|
|
34926
|
+
newContent = content.replaceAll(old_string, new_string);
|
|
34927
|
+
} else {
|
|
34928
|
+
newContent = content.replace(old_string, new_string);
|
|
34929
|
+
}
|
|
34930
|
+
if (newContent === content) {
|
|
34931
|
+
return `Error editing file: No changes made - old_string and new_string might be the same`;
|
|
34932
|
+
}
|
|
34933
|
+
await import_fs4.promises.writeFile(resolvedPath2, newContent, "utf-8");
|
|
34934
|
+
const replacedCount = replace_all ? occurrences : 1;
|
|
34935
|
+
if (debug) {
|
|
34936
|
+
console.error(`[Edit] Successfully edited ${resolvedPath2}, replaced ${replacedCount} occurrence(s)`);
|
|
34937
|
+
}
|
|
34938
|
+
return `Successfully edited ${file_path} (${replacedCount} replacement${replacedCount !== 1 ? "s" : ""})`;
|
|
34939
|
+
} catch (error2) {
|
|
34940
|
+
console.error("[Edit] Error:", error2);
|
|
34941
|
+
return `Error editing file: ${error2.message}`;
|
|
34942
|
+
}
|
|
34943
|
+
}
|
|
34944
|
+
});
|
|
34945
|
+
};
|
|
34946
|
+
createTool = (options = {}) => {
|
|
34947
|
+
const { debug, allowedFolders, cwd } = parseFileToolOptions(options);
|
|
34948
|
+
return (0, import_ai.tool)({
|
|
34949
|
+
name: "create",
|
|
34950
|
+
description: `Create new files with specified content.
|
|
35071
34951
|
|
|
35072
|
-
|
|
35073
|
-
Assistant workflow:
|
|
35074
|
-
1. <search>
|
|
35075
|
-
<query>login AND auth AND token</query>
|
|
35076
|
-
<path>.</path>
|
|
35077
|
-
</search>
|
|
35078
|
-
2. Now lets look closer: <extract>
|
|
35079
|
-
<targets>session.rs#AuthService.login auth.rs:2-100</targets>
|
|
35080
|
-
</extract>
|
|
34952
|
+
This tool creates new files in the filesystem. It will create parent directories if they don't exist.
|
|
35081
34953
|
|
|
35082
|
-
|
|
35083
|
-
|
|
35084
|
-
|
|
35085
|
-
|
|
35086
|
-
</search>
|
|
34954
|
+
Parameters:
|
|
34955
|
+
- file_path: Path where the file should be created (absolute or relative)
|
|
34956
|
+
- content: Content to write to the file
|
|
34957
|
+
- overwrite: (optional) Whether to overwrite if file exists (default: false)
|
|
35087
34958
|
|
|
35088
|
-
|
|
35089
|
-
|
|
35090
|
-
|
|
35091
|
-
|
|
35092
|
-
|
|
34959
|
+
Important:
|
|
34960
|
+
- By default, will fail if the file already exists
|
|
34961
|
+
- Set overwrite: true to replace existing files
|
|
34962
|
+
- Parent directories will be created automatically if needed`,
|
|
34963
|
+
inputSchema: {
|
|
34964
|
+
type: "object",
|
|
34965
|
+
properties: {
|
|
34966
|
+
file_path: {
|
|
34967
|
+
type: "string",
|
|
34968
|
+
description: "Path where the file should be created"
|
|
34969
|
+
},
|
|
34970
|
+
content: {
|
|
34971
|
+
type: "string",
|
|
34972
|
+
description: "Content to write to the file"
|
|
34973
|
+
},
|
|
34974
|
+
overwrite: {
|
|
34975
|
+
type: "boolean",
|
|
34976
|
+
description: "Overwrite if file exists (default: false)",
|
|
34977
|
+
default: false
|
|
34978
|
+
}
|
|
34979
|
+
},
|
|
34980
|
+
required: ["file_path", "content"]
|
|
34981
|
+
},
|
|
34982
|
+
execute: async ({ file_path, content, overwrite = false }) => {
|
|
34983
|
+
try {
|
|
34984
|
+
if (!file_path || typeof file_path !== "string" || file_path.trim() === "") {
|
|
34985
|
+
return `Error creating file: Invalid file_path - must be a non-empty string`;
|
|
34986
|
+
}
|
|
34987
|
+
if (content === void 0 || content === null || typeof content !== "string") {
|
|
34988
|
+
return `Error creating file: Invalid content - must be a string`;
|
|
34989
|
+
}
|
|
34990
|
+
const resolvedPath2 = (0, import_path5.isAbsolute)(file_path) ? file_path : (0, import_path5.resolve)(cwd || process.cwd(), file_path);
|
|
34991
|
+
if (debug) {
|
|
34992
|
+
console.error(`[Create] Attempting to create file: ${resolvedPath2}`);
|
|
34993
|
+
}
|
|
34994
|
+
if (!isPathAllowed(resolvedPath2, allowedFolders)) {
|
|
34995
|
+
return `Error creating file: Permission denied - ${file_path} is outside allowed directories`;
|
|
34996
|
+
}
|
|
34997
|
+
if ((0, import_fs5.existsSync)(resolvedPath2) && !overwrite) {
|
|
34998
|
+
return `Error creating file: File already exists - ${file_path}. Use overwrite: true to replace it.`;
|
|
34999
|
+
}
|
|
35000
|
+
const dir = (0, import_path5.dirname)(resolvedPath2);
|
|
35001
|
+
await import_fs4.promises.mkdir(dir, { recursive: true });
|
|
35002
|
+
await import_fs4.promises.writeFile(resolvedPath2, content, "utf-8");
|
|
35003
|
+
const action = (0, import_fs5.existsSync)(resolvedPath2) && overwrite ? "overwrote" : "created";
|
|
35004
|
+
const bytes = Buffer.byteLength(content, "utf-8");
|
|
35005
|
+
if (debug) {
|
|
35006
|
+
console.error(`[Create] Successfully ${action} ${resolvedPath2}`);
|
|
35007
|
+
}
|
|
35008
|
+
return `Successfully ${action} ${file_path} (${bytes} bytes)`;
|
|
35009
|
+
} catch (error2) {
|
|
35010
|
+
console.error("[Create] Error:", error2);
|
|
35011
|
+
return `Error creating file: ${error2.message}`;
|
|
35012
|
+
}
|
|
35013
|
+
}
|
|
35014
|
+
});
|
|
35015
|
+
};
|
|
35016
|
+
editSchema = {
|
|
35017
|
+
type: "object",
|
|
35018
|
+
properties: {
|
|
35019
|
+
file_path: {
|
|
35020
|
+
type: "string",
|
|
35021
|
+
description: "Path to the file to edit"
|
|
35022
|
+
},
|
|
35023
|
+
old_string: {
|
|
35024
|
+
type: "string",
|
|
35025
|
+
description: "Exact text to find and replace"
|
|
35026
|
+
},
|
|
35027
|
+
new_string: {
|
|
35028
|
+
type: "string",
|
|
35029
|
+
description: "Text to replace with"
|
|
35030
|
+
},
|
|
35031
|
+
replace_all: {
|
|
35032
|
+
type: "boolean",
|
|
35033
|
+
description: "Replace all occurrences (default: false)"
|
|
35034
|
+
}
|
|
35035
|
+
},
|
|
35036
|
+
required: ["file_path", "old_string", "new_string"]
|
|
35037
|
+
};
|
|
35038
|
+
createSchema = {
|
|
35039
|
+
type: "object",
|
|
35040
|
+
properties: {
|
|
35041
|
+
file_path: {
|
|
35042
|
+
type: "string",
|
|
35043
|
+
description: "Path where the file should be created"
|
|
35044
|
+
},
|
|
35045
|
+
content: {
|
|
35046
|
+
type: "string",
|
|
35047
|
+
description: "Content to write to the file"
|
|
35048
|
+
},
|
|
35049
|
+
overwrite: {
|
|
35050
|
+
type: "boolean",
|
|
35051
|
+
description: "Overwrite if file exists (default: false)"
|
|
35052
|
+
}
|
|
35053
|
+
},
|
|
35054
|
+
required: ["file_path", "content"]
|
|
35055
|
+
};
|
|
35056
|
+
editDescription = "Edit files using exact string replacement. Requires exact match including whitespace.";
|
|
35057
|
+
createDescription = "Create new files with specified content. Will create parent directories if needed.";
|
|
35058
|
+
editToolDefinition = `
|
|
35059
|
+
## edit
|
|
35060
|
+
Description: ${editDescription}
|
|
35093
35061
|
|
|
35094
|
-
|
|
35095
|
-
|
|
35096
|
-
|
|
35097
|
-
|
|
35098
|
-
|
|
35062
|
+
When to use:
|
|
35063
|
+
- For precise, surgical edits to existing files
|
|
35064
|
+
- When you need to change specific lines or blocks of code
|
|
35065
|
+
- For renaming functions, variables, or updating configuration values
|
|
35066
|
+
- When the exact text to replace is known and unique (or use replace_all for multiple occurrences)
|
|
35099
35067
|
|
|
35100
|
-
|
|
35101
|
-
|
|
35102
|
-
|
|
35103
|
-
|
|
35104
|
-
</search>
|
|
35068
|
+
When NOT to use:
|
|
35069
|
+
- For creating new files (use 'create' tool instead)
|
|
35070
|
+
- When you cannot determine the exact text to replace
|
|
35071
|
+
- When changes span multiple locations that would be better handled together
|
|
35105
35072
|
|
|
35106
|
-
</examples>
|
|
35107
|
-
`;
|
|
35108
|
-
queryToolDefinition = `
|
|
35109
|
-
## query
|
|
35110
|
-
Description: Search code using ast-grep structural pattern matching. Use this tool to find specific code structures like functions, classes, or methods.
|
|
35111
35073
|
Parameters:
|
|
35112
|
-
-
|
|
35113
|
-
-
|
|
35114
|
-
-
|
|
35115
|
-
-
|
|
35116
|
-
Usage Example:
|
|
35074
|
+
- file_path: (required) Path to the file to edit
|
|
35075
|
+
- old_string: (required) Exact text to find and replace (must match including whitespace, newlines, and indentation)
|
|
35076
|
+
- new_string: (required) Text to replace with
|
|
35077
|
+
- replace_all: (optional, default: false) Replace all occurrences if the string appears multiple times
|
|
35117
35078
|
|
|
35118
|
-
|
|
35079
|
+
Important notes:
|
|
35080
|
+
- The old_string MUST match EXACTLY, including all whitespace, indentation, and line breaks
|
|
35081
|
+
- If old_string appears multiple times and replace_all is false, the tool will fail
|
|
35082
|
+
- Always verify the exact formatting of the text you want to replace
|
|
35119
35083
|
|
|
35120
|
-
|
|
35121
|
-
<
|
|
35122
|
-
<
|
|
35123
|
-
<
|
|
35124
|
-
|
|
35084
|
+
Examples:
|
|
35085
|
+
<edit>
|
|
35086
|
+
<file_path>src/main.js</file_path>
|
|
35087
|
+
<old_string>function oldName() {
|
|
35088
|
+
return 42;
|
|
35089
|
+
}</old_string>
|
|
35090
|
+
<new_string>function newName() {
|
|
35091
|
+
return 42;
|
|
35092
|
+
}</new_string>
|
|
35093
|
+
</edit>
|
|
35125
35094
|
|
|
35126
|
-
|
|
35127
|
-
|
|
35128
|
-
|
|
35129
|
-
|
|
35130
|
-
|
|
35131
|
-
|
|
35095
|
+
<edit>
|
|
35096
|
+
<file_path>config.json</file_path>
|
|
35097
|
+
<old_string>"debug": false</old_string>
|
|
35098
|
+
<new_string>"debug": true</new_string>
|
|
35099
|
+
<replace_all>true</replace_all>
|
|
35100
|
+
</edit>`;
|
|
35101
|
+
createToolDefinition = `
|
|
35102
|
+
## create
|
|
35103
|
+
Description: ${createDescription}
|
|
35132
35104
|
|
|
35133
|
-
|
|
35105
|
+
When to use:
|
|
35106
|
+
- For creating brand new files from scratch
|
|
35107
|
+
- When you need to add configuration files, documentation, or new modules
|
|
35108
|
+
- For generating boilerplate code or templates
|
|
35109
|
+
- When you have the complete content ready to write
|
|
35134
35110
|
|
|
35135
|
-
|
|
35136
|
-
|
|
35137
|
-
|
|
35138
|
-
- targets: (required) File paths or symbols to extract from. Formats: "file.js" (whole file), "file.js:42" (code block at line 42), "file.js:10-20" (lines 10-20), "file.js#funcName" (specific symbol). Multiple targets separated by spaces.
|
|
35139
|
-
- input_content: (optional) Text content to extract file paths from (alternative to targets for processing diffs/logs).
|
|
35140
|
-
- allow_tests: (optional, default: true) Include test files in extraction results.
|
|
35141
|
-
|
|
35142
|
-
Usage Example:
|
|
35143
|
-
|
|
35144
|
-
<examples>
|
|
35145
|
-
|
|
35146
|
-
User: Where is the login logic? (After search found relevant files)
|
|
35147
|
-
<extract>
|
|
35148
|
-
<targets>session.rs#AuthService.login auth.rs:2-100 config.rs#DatabaseConfig</targets>
|
|
35149
|
-
</extract>
|
|
35150
|
-
|
|
35151
|
-
User: How does error handling work? (After search identified files)
|
|
35152
|
-
<extract>
|
|
35153
|
-
<targets>error.rs#ErrorType utils.rs#handle_error src/main.rs:50-80</targets>
|
|
35154
|
-
</extract>
|
|
35155
|
-
|
|
35156
|
-
User: How RankManager works
|
|
35157
|
-
<extract>
|
|
35158
|
-
<targets>src/search/ranking.rs#RankManager</targets>
|
|
35159
|
-
</extract>
|
|
35160
|
-
|
|
35161
|
-
User: Lets read the whole file
|
|
35162
|
-
<extract>
|
|
35163
|
-
<targets>src/search/ranking.rs</targets>
|
|
35164
|
-
</extract>
|
|
35165
|
-
|
|
35166
|
-
User: Read the first 10 lines of the file
|
|
35167
|
-
<extract>
|
|
35168
|
-
<targets>src/search/ranking.rs:1-10</targets>
|
|
35169
|
-
</extract>
|
|
35170
|
-
|
|
35171
|
-
User: Read file inside the dependency
|
|
35172
|
-
<extract>
|
|
35173
|
-
<targets>/dep/go/github.com/gorilla/mux/router.go</targets>
|
|
35174
|
-
</extract>
|
|
35175
|
-
|
|
35176
|
-
</examples>
|
|
35177
|
-
`;
|
|
35178
|
-
delegateToolDefinition = `
|
|
35179
|
-
## delegate
|
|
35180
|
-
Description: Automatically delegate big distinct tasks to specialized probe subagents within the agentic loop. Use this when you recognize that a user's request involves multiple large, distinct components that would benefit from parallel processing or specialized focus. The AI agent should automatically identify opportunities for task separation and use delegation without explicit user instruction.
|
|
35181
|
-
|
|
35182
|
-
Parameters:
|
|
35183
|
-
- task: (required) A complete, self-contained task that can be executed independently by a subagent. Should be specific and focused on one area of expertise.
|
|
35184
|
-
|
|
35185
|
-
Usage Pattern:
|
|
35186
|
-
When the AI agent encounters complex multi-part requests, it should automatically break them down and delegate:
|
|
35187
|
-
|
|
35188
|
-
<delegate>
|
|
35189
|
-
<task>Analyze all authentication and authorization code in the codebase for security vulnerabilities and provide specific remediation recommendations</task>
|
|
35190
|
-
</delegate>
|
|
35191
|
-
|
|
35192
|
-
<delegate>
|
|
35193
|
-
<task>Review database queries and API endpoints for performance bottlenecks and suggest optimization strategies</task>
|
|
35194
|
-
</delegate>
|
|
35195
|
-
|
|
35196
|
-
The agent uses this tool automatically when it identifies that work can be separated into distinct, parallel tasks for more efficient processing.
|
|
35197
|
-
`;
|
|
35198
|
-
attemptCompletionToolDefinition = `
|
|
35199
|
-
## attempt_completion
|
|
35200
|
-
Description: Use this tool ONLY when the task is fully complete and you have received confirmation of success for all previous tool uses. Presents the final result to the user. You can provide your response directly inside the XML tags without any parameter wrapper.
|
|
35201
|
-
Parameters:
|
|
35202
|
-
- No validation required - provide your complete answer directly inside the XML tags.
|
|
35203
|
-
Usage Example:
|
|
35204
|
-
<attempt_completion>
|
|
35205
|
-
I have refactored the search module according to the requirements and verified the tests pass. The module now uses the new BM25 ranking algorithm and has improved error handling.
|
|
35206
|
-
</attempt_completion>
|
|
35207
|
-
`;
|
|
35208
|
-
bashToolDefinition = `
|
|
35209
|
-
## bash
|
|
35210
|
-
Description: Execute bash commands for system exploration and development tasks. This tool has built-in security with allow/deny lists. By default, only safe read-only commands are allowed for code exploration.
|
|
35111
|
+
When NOT to use:
|
|
35112
|
+
- For editing existing files (use 'edit' tool instead)
|
|
35113
|
+
- When a file already exists unless you explicitly want to overwrite it
|
|
35211
35114
|
|
|
35212
35115
|
Parameters:
|
|
35213
|
-
-
|
|
35214
|
-
-
|
|
35215
|
-
-
|
|
35216
|
-
- env: (optional) Additional environment variables as an object
|
|
35217
|
-
|
|
35218
|
-
Security: Commands are filtered through allow/deny lists for safety:
|
|
35219
|
-
- Allowed by default: ls, cat, git status, npm list, find, grep, etc.
|
|
35220
|
-
- Denied by default: rm -rf, sudo, npm install, dangerous system commands
|
|
35221
|
-
|
|
35222
|
-
Usage Examples:
|
|
35223
|
-
|
|
35224
|
-
<examples>
|
|
35225
|
-
|
|
35226
|
-
User: What files are in the src directory?
|
|
35227
|
-
<bash>
|
|
35228
|
-
<command>ls -la src/</command>
|
|
35229
|
-
</bash>
|
|
35230
|
-
|
|
35231
|
-
User: Show me the git status
|
|
35232
|
-
<bash>
|
|
35233
|
-
<command>git status</command>
|
|
35234
|
-
</bash>
|
|
35235
|
-
|
|
35236
|
-
User: Find all TypeScript files
|
|
35237
|
-
<bash>
|
|
35238
|
-
<command>find . -name "*.ts" -type f</command>
|
|
35239
|
-
</bash>
|
|
35240
|
-
|
|
35241
|
-
User: Check installed npm packages
|
|
35242
|
-
<bash>
|
|
35243
|
-
<command>npm list --depth=0</command>
|
|
35244
|
-
</bash>
|
|
35116
|
+
- file_path: (required) Path where the file should be created
|
|
35117
|
+
- content: (required) Complete content to write to the file
|
|
35118
|
+
- overwrite: (optional, default: false) Whether to overwrite if file already exists
|
|
35245
35119
|
|
|
35246
|
-
|
|
35247
|
-
|
|
35248
|
-
|
|
35249
|
-
|
|
35120
|
+
Important notes:
|
|
35121
|
+
- Parent directories will be created automatically if they don't exist
|
|
35122
|
+
- The tool will fail if the file already exists and overwrite is false
|
|
35123
|
+
- Be careful with the overwrite option as it completely replaces existing files
|
|
35250
35124
|
|
|
35251
|
-
|
|
35252
|
-
<
|
|
35253
|
-
<
|
|
35254
|
-
|
|
35125
|
+
Examples:
|
|
35126
|
+
<create>
|
|
35127
|
+
<file_path>src/newFile.js</file_path>
|
|
35128
|
+
<content>export function hello() {
|
|
35129
|
+
return "Hello, world!";
|
|
35130
|
+
}</content>
|
|
35131
|
+
</create>
|
|
35255
35132
|
|
|
35256
|
-
|
|
35257
|
-
<
|
|
35258
|
-
<
|
|
35259
|
-
</bash>
|
|
35133
|
+
<create>
|
|
35134
|
+
<file_path>README.md</file_path>
|
|
35135
|
+
<content># My Project
|
|
35260
35136
|
|
|
35261
|
-
|
|
35262
|
-
|
|
35263
|
-
|
|
35264
|
-
queryDescription = "Search code using ast-grep structural pattern matching. Use this tool to find specific code structures like functions, classes, or methods.";
|
|
35265
|
-
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.";
|
|
35266
|
-
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.";
|
|
35267
|
-
DEFAULT_VALID_TOOLS = [
|
|
35268
|
-
"search",
|
|
35269
|
-
"query",
|
|
35270
|
-
"extract",
|
|
35271
|
-
"delegate",
|
|
35272
|
-
"listFiles",
|
|
35273
|
-
"searchFiles",
|
|
35274
|
-
"implement",
|
|
35275
|
-
"attempt_completion"
|
|
35276
|
-
];
|
|
35137
|
+
This is a new project.</content>
|
|
35138
|
+
<overwrite>true</overwrite>
|
|
35139
|
+
</create>`;
|
|
35277
35140
|
}
|
|
35278
35141
|
});
|
|
35279
35142
|
|
|
35280
|
-
// src/tools/
|
|
35281
|
-
|
|
35282
|
-
|
|
35283
|
-
"
|
|
35284
|
-
"
|
|
35285
|
-
|
|
35286
|
-
|
|
35287
|
-
|
|
35288
|
-
|
|
35289
|
-
|
|
35290
|
-
|
|
35291
|
-
|
|
35292
|
-
|
|
35293
|
-
|
|
35294
|
-
|
|
35295
|
-
|
|
35296
|
-
|
|
35297
|
-
|
|
35298
|
-
|
|
35299
|
-
|
|
35300
|
-
|
|
35301
|
-
|
|
35302
|
-
|
|
35303
|
-
|
|
35304
|
-
|
|
35305
|
-
|
|
35306
|
-
|
|
35307
|
-
|
|
35308
|
-
|
|
35309
|
-
|
|
35310
|
-
|
|
35311
|
-
|
|
35312
|
-
|
|
35313
|
-
|
|
35314
|
-
|
|
35315
|
-
|
|
35316
|
-
|
|
35317
|
-
|
|
35318
|
-
|
|
35319
|
-
|
|
35320
|
-
|
|
35321
|
-
|
|
35322
|
-
|
|
35323
|
-
|
|
35324
|
-
|
|
35325
|
-
|
|
35326
|
-
|
|
35327
|
-
|
|
35328
|
-
|
|
35329
|
-
|
|
35330
|
-
|
|
35331
|
-
|
|
35332
|
-
|
|
35333
|
-
|
|
35334
|
-
|
|
35335
|
-
|
|
35336
|
-
|
|
35337
|
-
|
|
35338
|
-
|
|
35339
|
-
|
|
35340
|
-
|
|
35341
|
-
|
|
35342
|
-
|
|
35343
|
-
|
|
35344
|
-
|
|
35345
|
-
|
|
35346
|
-
|
|
35347
|
-
|
|
35348
|
-
|
|
35349
|
-
|
|
35350
|
-
|
|
35351
|
-
|
|
35352
|
-
|
|
35353
|
-
|
|
35354
|
-
|
|
35355
|
-
|
|
35356
|
-
|
|
35357
|
-
pattern,
|
|
35358
|
-
path: queryPath,
|
|
35359
|
-
cwd: options.cwd,
|
|
35360
|
-
// Working directory for resolving relative paths
|
|
35361
|
-
language,
|
|
35362
|
-
allowTests: allow_tests ?? true,
|
|
35363
|
-
json: false
|
|
35364
|
-
});
|
|
35365
|
-
return results;
|
|
35366
|
-
} catch (error2) {
|
|
35367
|
-
console.error("Error executing query command:", error2);
|
|
35368
|
-
return `Error executing query command: ${error2.message}`;
|
|
35369
|
-
}
|
|
35370
|
-
}
|
|
35371
|
-
});
|
|
35372
|
-
};
|
|
35373
|
-
extractTool = (options = {}) => {
|
|
35374
|
-
const { debug = false, outline = false } = options;
|
|
35375
|
-
return (0, import_ai.tool)({
|
|
35376
|
-
name: "extract",
|
|
35377
|
-
description: extractDescription,
|
|
35378
|
-
inputSchema: extractSchema,
|
|
35379
|
-
execute: async ({ targets, input_content, line, end_line, allow_tests, context_lines, format: format2 }) => {
|
|
35380
|
-
try {
|
|
35381
|
-
const effectiveCwd = options.cwd || ".";
|
|
35382
|
-
if (debug) {
|
|
35383
|
-
if (targets) {
|
|
35384
|
-
console.error(`Executing extract with targets: "${targets}", cwd: "${effectiveCwd}", context lines: ${context_lines || 10}`);
|
|
35385
|
-
} else if (input_content) {
|
|
35386
|
-
console.error(`Executing extract with input content, cwd: "${effectiveCwd}", context lines: ${context_lines || 10}`);
|
|
35387
|
-
}
|
|
35388
|
-
}
|
|
35389
|
-
let tempFilePath = null;
|
|
35390
|
-
let extractOptions = { cwd: effectiveCwd };
|
|
35391
|
-
if (input_content) {
|
|
35392
|
-
const { writeFileSync: writeFileSync2, unlinkSync } = await import("fs");
|
|
35393
|
-
const { join: join3 } = await import("path");
|
|
35394
|
-
const { tmpdir } = await import("os");
|
|
35395
|
-
const { randomUUID: randomUUID6 } = await import("crypto");
|
|
35396
|
-
tempFilePath = join3(tmpdir(), `probe-extract-${randomUUID6()}.txt`);
|
|
35397
|
-
writeFileSync2(tempFilePath, input_content);
|
|
35398
|
-
if (debug) {
|
|
35399
|
-
console.error(`Created temporary file for input content: ${tempFilePath}`);
|
|
35400
|
-
}
|
|
35401
|
-
let effectiveFormat = format2;
|
|
35402
|
-
if (outline && format2 === "outline-xml") {
|
|
35403
|
-
effectiveFormat = "xml";
|
|
35404
|
-
}
|
|
35405
|
-
extractOptions = {
|
|
35406
|
-
inputFile: tempFilePath,
|
|
35407
|
-
cwd: effectiveCwd,
|
|
35408
|
-
allowTests: allow_tests ?? true,
|
|
35409
|
-
contextLines: context_lines,
|
|
35410
|
-
format: effectiveFormat
|
|
35411
|
-
};
|
|
35412
|
-
} else if (targets) {
|
|
35413
|
-
const parsedTargets = parseTargets(targets);
|
|
35414
|
-
const files = parsedTargets.map((target) => resolveTargetPath(target, effectiveCwd));
|
|
35415
|
-
let effectiveFormat = format2;
|
|
35416
|
-
if (outline && format2 === "outline-xml") {
|
|
35417
|
-
effectiveFormat = "xml";
|
|
35418
|
-
}
|
|
35419
|
-
extractOptions = {
|
|
35420
|
-
files,
|
|
35421
|
-
cwd: effectiveCwd,
|
|
35422
|
-
allowTests: allow_tests ?? true,
|
|
35423
|
-
contextLines: context_lines,
|
|
35424
|
-
format: effectiveFormat
|
|
35425
|
-
};
|
|
35426
|
-
} else {
|
|
35427
|
-
throw new Error("Either targets or input_content must be provided");
|
|
35428
|
-
}
|
|
35429
|
-
const results = await extract(extractOptions);
|
|
35430
|
-
if (tempFilePath) {
|
|
35431
|
-
const { unlinkSync } = await import("fs");
|
|
35432
|
-
try {
|
|
35433
|
-
unlinkSync(tempFilePath);
|
|
35434
|
-
if (debug) {
|
|
35435
|
-
console.error(`Removed temporary file: ${tempFilePath}`);
|
|
35436
|
-
}
|
|
35437
|
-
} catch (cleanupError) {
|
|
35438
|
-
console.error(`Warning: Failed to remove temporary file: ${cleanupError.message}`);
|
|
35439
|
-
}
|
|
35440
|
-
}
|
|
35441
|
-
return results;
|
|
35442
|
-
} catch (error2) {
|
|
35443
|
-
console.error("Error executing extract command:", error2);
|
|
35444
|
-
return `Error executing extract command: ${error2.message}`;
|
|
35143
|
+
// src/tools/common.js
|
|
35144
|
+
function buildToolTagPattern(tools2 = DEFAULT_VALID_TOOLS) {
|
|
35145
|
+
const allTools = [...tools2];
|
|
35146
|
+
if (allTools.includes("attempt_completion") && !allTools.includes("attempt_complete")) {
|
|
35147
|
+
allTools.push("attempt_complete");
|
|
35148
|
+
}
|
|
35149
|
+
const escaped = allTools.map((t4) => t4.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
|
|
35150
|
+
return new RegExp(`<(${escaped.join("|")})>`);
|
|
35151
|
+
}
|
|
35152
|
+
function getValidParamsForTool(toolName) {
|
|
35153
|
+
const schemaMap = {
|
|
35154
|
+
search: searchSchema,
|
|
35155
|
+
query: querySchema,
|
|
35156
|
+
extract: extractSchema,
|
|
35157
|
+
delegate: delegateSchema,
|
|
35158
|
+
bash: bashSchema,
|
|
35159
|
+
attempt_completion: attemptCompletionSchema,
|
|
35160
|
+
edit: editSchema,
|
|
35161
|
+
create: createSchema
|
|
35162
|
+
};
|
|
35163
|
+
const schema = schemaMap[toolName];
|
|
35164
|
+
if (!schema) {
|
|
35165
|
+
return ["path", "directory", "pattern", "recursive", "includeHidden", "task", "files", "autoCommits", "result"];
|
|
35166
|
+
}
|
|
35167
|
+
if (toolName === "attempt_completion") {
|
|
35168
|
+
return ["result"];
|
|
35169
|
+
}
|
|
35170
|
+
if (schema._def && schema._def.shape) {
|
|
35171
|
+
return Object.keys(schema._def.shape());
|
|
35172
|
+
}
|
|
35173
|
+
if (schema.properties) {
|
|
35174
|
+
return Object.keys(schema.properties);
|
|
35175
|
+
}
|
|
35176
|
+
return [];
|
|
35177
|
+
}
|
|
35178
|
+
function parseXmlToolCall(xmlString, validTools = DEFAULT_VALID_TOOLS) {
|
|
35179
|
+
for (const toolName of validTools) {
|
|
35180
|
+
const openTag = `<${toolName}>`;
|
|
35181
|
+
const closeTag = `</${toolName}>`;
|
|
35182
|
+
const openIndex = xmlString.indexOf(openTag);
|
|
35183
|
+
if (openIndex === -1) {
|
|
35184
|
+
continue;
|
|
35185
|
+
}
|
|
35186
|
+
let closeIndex;
|
|
35187
|
+
if (toolName === "attempt_completion") {
|
|
35188
|
+
closeIndex = xmlString.lastIndexOf(closeTag);
|
|
35189
|
+
if (closeIndex !== -1 && closeIndex <= openIndex + openTag.length) {
|
|
35190
|
+
closeIndex = -1;
|
|
35191
|
+
}
|
|
35192
|
+
} else {
|
|
35193
|
+
closeIndex = xmlString.indexOf(closeTag, openIndex + openTag.length);
|
|
35194
|
+
}
|
|
35195
|
+
let hasClosingTag = closeIndex !== -1;
|
|
35196
|
+
if (closeIndex === -1) {
|
|
35197
|
+
closeIndex = xmlString.length;
|
|
35198
|
+
}
|
|
35199
|
+
const innerContent = xmlString.substring(
|
|
35200
|
+
openIndex + openTag.length,
|
|
35201
|
+
closeIndex
|
|
35202
|
+
);
|
|
35203
|
+
const params = {};
|
|
35204
|
+
const validParams = getValidParamsForTool(toolName);
|
|
35205
|
+
for (const paramName of validParams) {
|
|
35206
|
+
const paramOpenTag = `<${paramName}>`;
|
|
35207
|
+
const paramCloseTag = `</${paramName}>`;
|
|
35208
|
+
const paramOpenIndex = innerContent.indexOf(paramOpenTag);
|
|
35209
|
+
if (paramOpenIndex === -1) {
|
|
35210
|
+
continue;
|
|
35211
|
+
}
|
|
35212
|
+
let paramCloseIndex = innerContent.indexOf(paramCloseTag, paramOpenIndex + paramOpenTag.length);
|
|
35213
|
+
if (paramCloseIndex === -1) {
|
|
35214
|
+
let nextTagIndex = innerContent.length;
|
|
35215
|
+
for (const nextParam of validParams) {
|
|
35216
|
+
const nextOpenTag = `<${nextParam}>`;
|
|
35217
|
+
const nextIndex = innerContent.indexOf(nextOpenTag, paramOpenIndex + paramOpenTag.length);
|
|
35218
|
+
if (nextIndex !== -1 && nextIndex < nextTagIndex) {
|
|
35219
|
+
nextTagIndex = nextIndex;
|
|
35445
35220
|
}
|
|
35446
35221
|
}
|
|
35447
|
-
|
|
35448
|
-
|
|
35449
|
-
|
|
35450
|
-
|
|
35451
|
-
|
|
35452
|
-
|
|
35453
|
-
|
|
35454
|
-
|
|
35455
|
-
|
|
35456
|
-
|
|
35457
|
-
|
|
35458
|
-
|
|
35459
|
-
|
|
35460
|
-
|
|
35461
|
-
}
|
|
35462
|
-
if (currentIteration !== void 0 && (typeof currentIteration !== "number" || currentIteration < 0)) {
|
|
35463
|
-
throw new Error("currentIteration must be a non-negative number");
|
|
35464
|
-
}
|
|
35465
|
-
if (maxIterations !== void 0 && (typeof maxIterations !== "number" || maxIterations < 1)) {
|
|
35466
|
-
throw new Error("maxIterations must be a positive number");
|
|
35467
|
-
}
|
|
35468
|
-
if (parentSessionId !== void 0 && parentSessionId !== null && typeof parentSessionId !== "string") {
|
|
35469
|
-
throw new TypeError("parentSessionId must be a string, null, or undefined");
|
|
35470
|
-
}
|
|
35471
|
-
if (path9 !== void 0 && path9 !== null && typeof path9 !== "string") {
|
|
35472
|
-
throw new TypeError("path must be a string, null, or undefined");
|
|
35473
|
-
}
|
|
35474
|
-
if (provider !== void 0 && provider !== null && typeof provider !== "string") {
|
|
35475
|
-
throw new TypeError("provider must be a string, null, or undefined");
|
|
35476
|
-
}
|
|
35477
|
-
if (model !== void 0 && model !== null && typeof model !== "string") {
|
|
35478
|
-
throw new TypeError("model must be a string, null, or undefined");
|
|
35479
|
-
}
|
|
35480
|
-
const effectivePath = path9 || cwd || allowedFolders && allowedFolders[0];
|
|
35481
|
-
if (debug) {
|
|
35482
|
-
console.error(`Executing delegate with task: "${task.substring(0, 100)}${task.length > 100 ? "..." : ""}"`);
|
|
35483
|
-
if (parentSessionId) {
|
|
35484
|
-
console.error(`Parent session: ${parentSessionId}`);
|
|
35485
|
-
}
|
|
35486
|
-
if (effectivePath && effectivePath !== path9) {
|
|
35487
|
-
console.error(`Using inherited path: ${effectivePath}`);
|
|
35488
|
-
}
|
|
35489
|
-
}
|
|
35490
|
-
const result = await delegate({
|
|
35491
|
-
task,
|
|
35492
|
-
timeout,
|
|
35493
|
-
debug,
|
|
35494
|
-
currentIteration: currentIteration || 0,
|
|
35495
|
-
maxIterations: maxIterations || 30,
|
|
35496
|
-
parentSessionId,
|
|
35497
|
-
path: effectivePath,
|
|
35498
|
-
provider,
|
|
35499
|
-
model,
|
|
35500
|
-
tracer,
|
|
35501
|
-
enableBash,
|
|
35502
|
-
bashConfig
|
|
35503
|
-
});
|
|
35504
|
-
return result;
|
|
35222
|
+
paramCloseIndex = nextTagIndex;
|
|
35223
|
+
}
|
|
35224
|
+
let paramValue = innerContent.substring(
|
|
35225
|
+
paramOpenIndex + paramOpenTag.length,
|
|
35226
|
+
paramCloseIndex
|
|
35227
|
+
).trim();
|
|
35228
|
+
if (paramValue.toLowerCase() === "true") {
|
|
35229
|
+
paramValue = true;
|
|
35230
|
+
} else if (paramValue.toLowerCase() === "false") {
|
|
35231
|
+
paramValue = false;
|
|
35232
|
+
} else if (!isNaN(paramValue) && paramValue.trim() !== "") {
|
|
35233
|
+
const num = Number(paramValue);
|
|
35234
|
+
if (Number.isFinite(num)) {
|
|
35235
|
+
paramValue = num;
|
|
35505
35236
|
}
|
|
35506
|
-
}
|
|
35507
|
-
|
|
35237
|
+
}
|
|
35238
|
+
params[paramName] = paramValue;
|
|
35239
|
+
}
|
|
35240
|
+
if (toolName === "attempt_completion") {
|
|
35241
|
+
params["result"] = innerContent.trim();
|
|
35242
|
+
if (params.command) {
|
|
35243
|
+
delete params.command;
|
|
35244
|
+
}
|
|
35245
|
+
}
|
|
35246
|
+
return { toolName, params };
|
|
35508
35247
|
}
|
|
35509
|
-
|
|
35510
|
-
|
|
35511
|
-
|
|
35512
|
-
|
|
35513
|
-
|
|
35514
|
-
"src/agent/bashDefaults.js"() {
|
|
35515
|
-
"use strict";
|
|
35516
|
-
DEFAULT_ALLOW_PATTERNS = [
|
|
35517
|
-
// Basic navigation and listing
|
|
35518
|
-
"ls",
|
|
35519
|
-
"dir",
|
|
35520
|
-
"pwd",
|
|
35521
|
-
"cd",
|
|
35522
|
-
"cd:*",
|
|
35523
|
-
// File reading commands
|
|
35524
|
-
"cat",
|
|
35525
|
-
"cat:*",
|
|
35526
|
-
"head",
|
|
35527
|
-
"head:*",
|
|
35528
|
-
"tail",
|
|
35529
|
-
"tail:*",
|
|
35530
|
-
"less",
|
|
35531
|
-
"more",
|
|
35532
|
-
"view",
|
|
35533
|
-
// File information and metadata
|
|
35534
|
-
"file",
|
|
35535
|
-
"file:*",
|
|
35536
|
-
"stat",
|
|
35537
|
-
"stat:*",
|
|
35538
|
-
"wc",
|
|
35539
|
-
"wc:*",
|
|
35540
|
-
"du",
|
|
35541
|
-
"du:*",
|
|
35542
|
-
"df",
|
|
35543
|
-
"df:*",
|
|
35544
|
-
"realpath",
|
|
35545
|
-
"realpath:*",
|
|
35546
|
-
// Search and find commands (read-only) - find restricted to safe operations
|
|
35547
|
-
"find",
|
|
35548
|
-
"find:-name:*",
|
|
35549
|
-
"find:-type:*",
|
|
35550
|
-
"find:-size:*",
|
|
35551
|
-
"find:-mtime:*",
|
|
35552
|
-
"find:-newer:*",
|
|
35553
|
-
"find:-path:*",
|
|
35554
|
-
"find:-iname:*",
|
|
35555
|
-
"find:-maxdepth:*",
|
|
35556
|
-
"find:-mindepth:*",
|
|
35557
|
-
"find:-print",
|
|
35558
|
-
"grep",
|
|
35559
|
-
"grep:*",
|
|
35560
|
-
"egrep",
|
|
35561
|
-
"egrep:*",
|
|
35562
|
-
"fgrep",
|
|
35563
|
-
"fgrep:*",
|
|
35564
|
-
"rg",
|
|
35565
|
-
"rg:*",
|
|
35566
|
-
"ag",
|
|
35567
|
-
"ag:*",
|
|
35568
|
-
"ack",
|
|
35569
|
-
"ack:*",
|
|
35570
|
-
"which",
|
|
35571
|
-
"which:*",
|
|
35572
|
-
"whereis",
|
|
35573
|
-
"whereis:*",
|
|
35574
|
-
"locate",
|
|
35575
|
-
"locate:*",
|
|
35576
|
-
"type",
|
|
35577
|
-
"type:*",
|
|
35578
|
-
"command",
|
|
35579
|
-
"command:*",
|
|
35580
|
-
// Tree and structure visualization
|
|
35581
|
-
"tree",
|
|
35582
|
-
"tree:*",
|
|
35583
|
-
// Git read-only operations
|
|
35584
|
-
"git:status",
|
|
35585
|
-
"git:log",
|
|
35586
|
-
"git:log:*",
|
|
35587
|
-
"git:diff",
|
|
35588
|
-
"git:diff:*",
|
|
35589
|
-
"git:show",
|
|
35590
|
-
"git:show:*",
|
|
35591
|
-
"git:branch",
|
|
35592
|
-
"git:branch:*",
|
|
35593
|
-
"git:tag",
|
|
35594
|
-
"git:tag:*",
|
|
35595
|
-
"git:describe",
|
|
35596
|
-
"git:describe:*",
|
|
35597
|
-
"git:remote",
|
|
35598
|
-
"git:remote:*",
|
|
35599
|
-
"git:config:*",
|
|
35600
|
-
"git:blame",
|
|
35601
|
-
"git:blame:*",
|
|
35602
|
-
"git:shortlog",
|
|
35603
|
-
"git:reflog",
|
|
35604
|
-
"git:ls-files",
|
|
35605
|
-
"git:ls-tree",
|
|
35606
|
-
"git:rev-parse",
|
|
35607
|
-
"git:rev-list",
|
|
35608
|
-
"git:--version",
|
|
35609
|
-
"git:help",
|
|
35610
|
-
"git:help:*",
|
|
35611
|
-
// Package managers (information only)
|
|
35612
|
-
"npm:list",
|
|
35613
|
-
"npm:ls",
|
|
35614
|
-
"npm:view",
|
|
35615
|
-
"npm:info",
|
|
35616
|
-
"npm:show",
|
|
35617
|
-
"npm:outdated",
|
|
35618
|
-
"npm:audit",
|
|
35619
|
-
"npm:--version",
|
|
35620
|
-
"yarn:list",
|
|
35621
|
-
"yarn:info",
|
|
35622
|
-
"yarn:--version",
|
|
35623
|
-
"pnpm:list",
|
|
35624
|
-
"pnpm:--version",
|
|
35625
|
-
"pip:list",
|
|
35626
|
-
"pip:show",
|
|
35627
|
-
"pip:--version",
|
|
35628
|
-
"pip3:list",
|
|
35629
|
-
"pip3:show",
|
|
35630
|
-
"pip3:--version",
|
|
35631
|
-
"gem:list",
|
|
35632
|
-
"gem:--version",
|
|
35633
|
-
"bundle:list",
|
|
35634
|
-
"bundle:show",
|
|
35635
|
-
"bundle:--version",
|
|
35636
|
-
"composer:show",
|
|
35637
|
-
"composer:--version",
|
|
35638
|
-
// Language and runtime versions
|
|
35639
|
-
"node:--version",
|
|
35640
|
-
"node:-v",
|
|
35641
|
-
"python:--version",
|
|
35642
|
-
"python:-V",
|
|
35643
|
-
"python3:--version",
|
|
35644
|
-
"python3:-V",
|
|
35645
|
-
"ruby:--version",
|
|
35646
|
-
"ruby:-v",
|
|
35647
|
-
"go:version",
|
|
35648
|
-
"go:env",
|
|
35649
|
-
"go:list",
|
|
35650
|
-
"go:mod:graph",
|
|
35651
|
-
"rustc:--version",
|
|
35652
|
-
"cargo:--version",
|
|
35653
|
-
"cargo:tree",
|
|
35654
|
-
"cargo:metadata",
|
|
35655
|
-
"java:--version",
|
|
35656
|
-
"java:-version",
|
|
35657
|
-
"javac:--version",
|
|
35658
|
-
"mvn:--version",
|
|
35659
|
-
"gradle:--version",
|
|
35660
|
-
"php:--version",
|
|
35661
|
-
"dotnet:--version",
|
|
35662
|
-
"dotnet:list",
|
|
35663
|
-
// Database client versions (connection info only)
|
|
35664
|
-
"psql:--version",
|
|
35665
|
-
"mysql:--version",
|
|
35666
|
-
"redis-cli:--version",
|
|
35667
|
-
"mongo:--version",
|
|
35668
|
-
"sqlite3:--version",
|
|
35669
|
-
// System information
|
|
35670
|
-
"uname",
|
|
35671
|
-
"uname:*",
|
|
35672
|
-
"hostname",
|
|
35673
|
-
"whoami",
|
|
35674
|
-
"id",
|
|
35675
|
-
"groups",
|
|
35676
|
-
"date",
|
|
35677
|
-
"cal",
|
|
35678
|
-
"uptime",
|
|
35679
|
-
"w",
|
|
35680
|
-
"users",
|
|
35681
|
-
"sleep",
|
|
35682
|
-
"sleep:*",
|
|
35683
|
-
// Environment and shell
|
|
35684
|
-
"env",
|
|
35685
|
-
"printenv",
|
|
35686
|
-
"echo",
|
|
35687
|
-
"echo:*",
|
|
35688
|
-
"printf",
|
|
35689
|
-
"printf:*",
|
|
35690
|
-
"export",
|
|
35691
|
-
"export:*",
|
|
35692
|
-
"set",
|
|
35693
|
-
"unset",
|
|
35694
|
-
// Process information (read-only)
|
|
35695
|
-
"ps",
|
|
35696
|
-
"ps:*",
|
|
35697
|
-
"pgrep",
|
|
35698
|
-
"pgrep:*",
|
|
35699
|
-
"jobs",
|
|
35700
|
-
"top:-n:1",
|
|
35701
|
-
// Network information (read-only)
|
|
35702
|
-
"ifconfig",
|
|
35703
|
-
"ip:addr",
|
|
35704
|
-
"ip:link",
|
|
35705
|
-
"hostname:-I",
|
|
35706
|
-
"ping:-c:*",
|
|
35707
|
-
"traceroute",
|
|
35708
|
-
"nslookup",
|
|
35709
|
-
"dig",
|
|
35710
|
-
// Text processing and utilities (awk removed - too powerful)
|
|
35711
|
-
"sed:-n:*",
|
|
35712
|
-
"cut",
|
|
35713
|
-
"cut:*",
|
|
35714
|
-
"sort",
|
|
35715
|
-
"sort:*",
|
|
35716
|
-
"uniq",
|
|
35717
|
-
"uniq:*",
|
|
35718
|
-
"tr",
|
|
35719
|
-
"tr:*",
|
|
35720
|
-
"column",
|
|
35721
|
-
"column:*",
|
|
35722
|
-
"paste",
|
|
35723
|
-
"paste:*",
|
|
35724
|
-
"join",
|
|
35725
|
-
"join:*",
|
|
35726
|
-
"comm",
|
|
35727
|
-
"comm:*",
|
|
35728
|
-
"diff",
|
|
35729
|
-
"diff:*",
|
|
35730
|
-
"cmp",
|
|
35731
|
-
"cmp:*",
|
|
35732
|
-
"patch:--dry-run:*",
|
|
35733
|
-
// Hashing and encoding (read-only)
|
|
35734
|
-
"md5sum",
|
|
35735
|
-
"md5sum:*",
|
|
35736
|
-
"sha1sum",
|
|
35737
|
-
"sha1sum:*",
|
|
35738
|
-
"sha256sum",
|
|
35739
|
-
"sha256sum:*",
|
|
35740
|
-
"base64",
|
|
35741
|
-
"base64:-d",
|
|
35742
|
-
"od",
|
|
35743
|
-
"od:*",
|
|
35744
|
-
"hexdump",
|
|
35745
|
-
"hexdump:*",
|
|
35746
|
-
// Archive and compression (list/view only)
|
|
35747
|
-
"tar:-tf:*",
|
|
35748
|
-
"tar:-tzf:*",
|
|
35749
|
-
"unzip:-l:*",
|
|
35750
|
-
"zip:-l:*",
|
|
35751
|
-
"gzip:-l:*",
|
|
35752
|
-
"gunzip:-l:*",
|
|
35753
|
-
// Help and documentation
|
|
35754
|
-
"man",
|
|
35755
|
-
"man:*",
|
|
35756
|
-
"--help",
|
|
35757
|
-
"help",
|
|
35758
|
-
"info",
|
|
35759
|
-
"info:*",
|
|
35760
|
-
"whatis",
|
|
35761
|
-
"whatis:*",
|
|
35762
|
-
"apropos",
|
|
35763
|
-
"apropos:*",
|
|
35764
|
-
// Make (dry run and info)
|
|
35765
|
-
"make:-n",
|
|
35766
|
-
"make:--dry-run",
|
|
35767
|
-
"make:-p",
|
|
35768
|
-
"make:--print-data-base",
|
|
35769
|
-
// Docker (read-only operations)
|
|
35770
|
-
"docker:ps",
|
|
35771
|
-
"docker:images",
|
|
35772
|
-
"docker:version",
|
|
35773
|
-
"docker:info",
|
|
35774
|
-
"docker:logs:*",
|
|
35775
|
-
"docker:inspect:*",
|
|
35776
|
-
// Test runners (list/info only)
|
|
35777
|
-
"jest:--listTests",
|
|
35778
|
-
"mocha:--help",
|
|
35779
|
-
"pytest:--collect-only"
|
|
35780
|
-
];
|
|
35781
|
-
DEFAULT_DENY_PATTERNS = [
|
|
35782
|
-
// Dangerous file operations
|
|
35783
|
-
"rm:-rf",
|
|
35784
|
-
"rm:-f:/",
|
|
35785
|
-
"rm:/",
|
|
35786
|
-
"rm:-rf:*",
|
|
35787
|
-
"rmdir",
|
|
35788
|
-
"chmod:777",
|
|
35789
|
-
"chmod:-R:777",
|
|
35790
|
-
"chown",
|
|
35791
|
-
"chgrp",
|
|
35792
|
-
"dd",
|
|
35793
|
-
"dd:*",
|
|
35794
|
-
"shred",
|
|
35795
|
-
"shred:*",
|
|
35796
|
-
// Dangerous find operations that can execute arbitrary commands
|
|
35797
|
-
"find:-exec:*",
|
|
35798
|
-
"find:*:-exec:*",
|
|
35799
|
-
"find:-execdir:*",
|
|
35800
|
-
"find:*:-execdir:*",
|
|
35801
|
-
"find:-ok:*",
|
|
35802
|
-
"find:*:-ok:*",
|
|
35803
|
-
"find:-okdir:*",
|
|
35804
|
-
"find:*:-okdir:*",
|
|
35805
|
-
// Powerful scripting tools that can execute arbitrary commands
|
|
35806
|
-
"awk",
|
|
35807
|
-
"awk:*",
|
|
35808
|
-
"perl",
|
|
35809
|
-
"perl:*",
|
|
35810
|
-
"python:-c:*",
|
|
35811
|
-
"node:-e:*",
|
|
35812
|
-
// System administration and modification
|
|
35813
|
-
"sudo:*",
|
|
35814
|
-
"su",
|
|
35815
|
-
"su:*",
|
|
35816
|
-
"passwd",
|
|
35817
|
-
"adduser",
|
|
35818
|
-
"useradd",
|
|
35819
|
-
"userdel",
|
|
35820
|
-
"usermod",
|
|
35821
|
-
"groupadd",
|
|
35822
|
-
"groupdel",
|
|
35823
|
-
"visudo",
|
|
35824
|
-
// Package installation and removal
|
|
35825
|
-
"npm:install",
|
|
35826
|
-
"npm:i",
|
|
35827
|
-
"npm:uninstall",
|
|
35828
|
-
"npm:publish",
|
|
35829
|
-
"npm:unpublish",
|
|
35830
|
-
"npm:link",
|
|
35831
|
-
"npm:update",
|
|
35832
|
-
"yarn:install",
|
|
35833
|
-
"yarn:add",
|
|
35834
|
-
"yarn:remove",
|
|
35835
|
-
"yarn:upgrade",
|
|
35836
|
-
"pnpm:install",
|
|
35837
|
-
"pnpm:add",
|
|
35838
|
-
"pnpm:remove",
|
|
35839
|
-
"pip:install",
|
|
35840
|
-
"pip:uninstall",
|
|
35841
|
-
"pip:upgrade",
|
|
35842
|
-
"pip3:install",
|
|
35843
|
-
"pip3:uninstall",
|
|
35844
|
-
"pip3:upgrade",
|
|
35845
|
-
"gem:install",
|
|
35846
|
-
"gem:uninstall",
|
|
35847
|
-
"gem:update",
|
|
35848
|
-
"bundle:install",
|
|
35849
|
-
"bundle:update",
|
|
35850
|
-
"composer:install",
|
|
35851
|
-
"composer:update",
|
|
35852
|
-
"composer:remove",
|
|
35853
|
-
"apt:*",
|
|
35854
|
-
"apt-get:*",
|
|
35855
|
-
"yum:*",
|
|
35856
|
-
"dnf:*",
|
|
35857
|
-
"zypper:*",
|
|
35858
|
-
"brew:install",
|
|
35859
|
-
"brew:uninstall",
|
|
35860
|
-
"brew:upgrade",
|
|
35861
|
-
"conda:install",
|
|
35862
|
-
"conda:remove",
|
|
35863
|
-
"conda:update",
|
|
35864
|
-
// Service and system control
|
|
35865
|
-
"systemctl:*",
|
|
35866
|
-
"service:*",
|
|
35867
|
-
"chkconfig:*",
|
|
35868
|
-
"initctl:*",
|
|
35869
|
-
"upstart:*",
|
|
35870
|
-
// Network operations that could be dangerous
|
|
35871
|
-
"curl:-d:*",
|
|
35872
|
-
"curl:--data:*",
|
|
35873
|
-
"curl:-X:POST:*",
|
|
35874
|
-
"curl:-X:PUT:*",
|
|
35875
|
-
"wget:-O:/",
|
|
35876
|
-
"wget:--post-data:*",
|
|
35877
|
-
"ssh",
|
|
35878
|
-
"ssh:*",
|
|
35879
|
-
"scp",
|
|
35880
|
-
"scp:*",
|
|
35881
|
-
"sftp",
|
|
35882
|
-
"sftp:*",
|
|
35883
|
-
"rsync:*",
|
|
35884
|
-
"nc",
|
|
35885
|
-
"nc:*",
|
|
35886
|
-
"netcat",
|
|
35887
|
-
"netcat:*",
|
|
35888
|
-
"telnet",
|
|
35889
|
-
"telnet:*",
|
|
35890
|
-
"ftp",
|
|
35891
|
-
"ftp:*",
|
|
35892
|
-
// Process control and termination
|
|
35893
|
-
"kill",
|
|
35894
|
-
"kill:*",
|
|
35895
|
-
"killall",
|
|
35896
|
-
"killall:*",
|
|
35897
|
-
"pkill",
|
|
35898
|
-
"pkill:*",
|
|
35899
|
-
"nohup:*",
|
|
35900
|
-
"disown:*",
|
|
35901
|
-
// System control and shutdown
|
|
35902
|
-
"shutdown",
|
|
35903
|
-
"shutdown:*",
|
|
35904
|
-
"reboot",
|
|
35905
|
-
"halt",
|
|
35906
|
-
"poweroff",
|
|
35907
|
-
"init",
|
|
35908
|
-
"telinit",
|
|
35909
|
-
// Kernel and module operations
|
|
35910
|
-
"insmod",
|
|
35911
|
-
"insmod:*",
|
|
35912
|
-
"rmmod",
|
|
35913
|
-
"rmmod:*",
|
|
35914
|
-
"modprobe",
|
|
35915
|
-
"modprobe:*",
|
|
35916
|
-
"sysctl:-w:*",
|
|
35917
|
-
// Dangerous git operations
|
|
35918
|
-
"git:push",
|
|
35919
|
-
"git:push:*",
|
|
35920
|
-
"git:force",
|
|
35921
|
-
"git:reset:--hard:*",
|
|
35922
|
-
"git:clean:-fd",
|
|
35923
|
-
"git:rm:*",
|
|
35924
|
-
"git:commit",
|
|
35925
|
-
"git:merge",
|
|
35926
|
-
"git:rebase",
|
|
35927
|
-
"git:cherry-pick",
|
|
35928
|
-
"git:stash:drop",
|
|
35929
|
-
// File system mounting and partitioning
|
|
35930
|
-
"mount",
|
|
35931
|
-
"mount:*",
|
|
35932
|
-
"umount",
|
|
35933
|
-
"umount:*",
|
|
35934
|
-
"fdisk",
|
|
35935
|
-
"fdisk:*",
|
|
35936
|
-
"parted",
|
|
35937
|
-
"parted:*",
|
|
35938
|
-
"mkfs",
|
|
35939
|
-
"mkfs:*",
|
|
35940
|
-
"fsck",
|
|
35941
|
-
"fsck:*",
|
|
35942
|
-
// Cron and scheduling
|
|
35943
|
-
"crontab",
|
|
35944
|
-
"crontab:*",
|
|
35945
|
-
"at",
|
|
35946
|
-
"at:*",
|
|
35947
|
-
"batch",
|
|
35948
|
-
"batch:*",
|
|
35949
|
-
// Compression with potential overwrite
|
|
35950
|
-
"tar:-xf:*",
|
|
35951
|
-
"unzip",
|
|
35952
|
-
"unzip:*",
|
|
35953
|
-
"gzip:*",
|
|
35954
|
-
"gunzip:*",
|
|
35955
|
-
// Build and compilation that might modify files
|
|
35956
|
-
"make",
|
|
35957
|
-
"make:install",
|
|
35958
|
-
"make:clean",
|
|
35959
|
-
"cargo:build",
|
|
35960
|
-
"cargo:install",
|
|
35961
|
-
"npm:run:build",
|
|
35962
|
-
"yarn:build",
|
|
35963
|
-
"mvn:install",
|
|
35964
|
-
"gradle:build",
|
|
35965
|
-
// Docker operations that could modify state
|
|
35966
|
-
"docker:run",
|
|
35967
|
-
"docker:run:*",
|
|
35968
|
-
"docker:exec",
|
|
35969
|
-
"docker:exec:*",
|
|
35970
|
-
"docker:build",
|
|
35971
|
-
"docker:build:*",
|
|
35972
|
-
"docker:pull",
|
|
35973
|
-
"docker:push",
|
|
35974
|
-
"docker:rm",
|
|
35975
|
-
"docker:rmi",
|
|
35976
|
-
"docker:stop",
|
|
35977
|
-
"docker:start",
|
|
35978
|
-
// Database operations
|
|
35979
|
-
"mysql:-e:DROP",
|
|
35980
|
-
"psql:-c:DROP",
|
|
35981
|
-
"redis-cli:FLUSHALL",
|
|
35982
|
-
"mongo:--eval:*",
|
|
35983
|
-
// Text editors that could modify files
|
|
35984
|
-
"vi",
|
|
35985
|
-
"vi:*",
|
|
35986
|
-
"vim",
|
|
35987
|
-
"vim:*",
|
|
35988
|
-
"nano",
|
|
35989
|
-
"nano:*",
|
|
35990
|
-
"emacs",
|
|
35991
|
-
"emacs:*",
|
|
35992
|
-
"sed:-i:*",
|
|
35993
|
-
"perl:-i:*",
|
|
35994
|
-
// Potentially dangerous utilities
|
|
35995
|
-
"eval",
|
|
35996
|
-
"eval:*",
|
|
35997
|
-
"exec",
|
|
35998
|
-
"exec:*",
|
|
35999
|
-
"source",
|
|
36000
|
-
"source:*",
|
|
36001
|
-
"bash:-c:*",
|
|
36002
|
-
"sh:-c:*",
|
|
36003
|
-
"zsh:-c:*"
|
|
36004
|
-
];
|
|
36005
|
-
}
|
|
36006
|
-
});
|
|
36007
|
-
|
|
36008
|
-
// src/agent/bashCommandUtils.js
|
|
36009
|
-
function parseSimpleCommand(command) {
|
|
36010
|
-
if (!command || typeof command !== "string") {
|
|
36011
|
-
return {
|
|
36012
|
-
success: false,
|
|
36013
|
-
error: "Command must be a non-empty string",
|
|
36014
|
-
command: null,
|
|
36015
|
-
args: [],
|
|
36016
|
-
isComplex: false
|
|
36017
|
-
};
|
|
36018
|
-
}
|
|
36019
|
-
const trimmed = command.trim();
|
|
36020
|
-
if (!trimmed) {
|
|
36021
|
-
return {
|
|
36022
|
-
success: false,
|
|
36023
|
-
error: "Command cannot be empty",
|
|
36024
|
-
command: null,
|
|
36025
|
-
args: [],
|
|
36026
|
-
isComplex: false
|
|
36027
|
-
};
|
|
36028
|
-
}
|
|
36029
|
-
const complexPatterns = [
|
|
36030
|
-
/\|/,
|
|
36031
|
-
// Pipes
|
|
36032
|
-
/&&/,
|
|
36033
|
-
// Logical AND
|
|
36034
|
-
/\|\|/,
|
|
36035
|
-
// Logical OR
|
|
36036
|
-
/(?<!\\);/,
|
|
36037
|
-
// Command separator (but not escaped \;)
|
|
36038
|
-
/&$/,
|
|
36039
|
-
// Background execution
|
|
36040
|
-
/\$\(/,
|
|
36041
|
-
// Command substitution $()
|
|
36042
|
-
/`/,
|
|
36043
|
-
// Command substitution ``
|
|
36044
|
-
/>/,
|
|
36045
|
-
// Redirection >
|
|
36046
|
-
/</,
|
|
36047
|
-
// Redirection <
|
|
36048
|
-
/\*\*/,
|
|
36049
|
-
// Glob patterns (potentially dangerous)
|
|
36050
|
-
/^\s*\{.*,.*\}|\{.*\.\.\.*\}/
|
|
36051
|
-
// Brace expansion like {a,b} or {1..10} (but not find {} placeholders)
|
|
36052
|
-
];
|
|
36053
|
-
for (const pattern of complexPatterns) {
|
|
36054
|
-
if (pattern.test(trimmed)) {
|
|
36055
|
-
return {
|
|
36056
|
-
success: false,
|
|
36057
|
-
error: "Complex shell commands with pipes, operators, or redirections are not supported for security reasons",
|
|
36058
|
-
command: null,
|
|
36059
|
-
args: [],
|
|
36060
|
-
isComplex: true,
|
|
36061
|
-
detected: pattern.toString()
|
|
36062
|
-
};
|
|
36063
|
-
}
|
|
36064
|
-
}
|
|
36065
|
-
const args = [];
|
|
36066
|
-
let current = "";
|
|
36067
|
-
let inQuotes = false;
|
|
36068
|
-
let quoteChar = "";
|
|
36069
|
-
let escaped = false;
|
|
36070
|
-
for (let i4 = 0; i4 < trimmed.length; i4++) {
|
|
36071
|
-
const char = trimmed[i4];
|
|
36072
|
-
const nextChar = i4 + 1 < trimmed.length ? trimmed[i4 + 1] : "";
|
|
36073
|
-
if (escaped) {
|
|
36074
|
-
current += char;
|
|
36075
|
-
escaped = false;
|
|
36076
|
-
continue;
|
|
36077
|
-
}
|
|
36078
|
-
if (char === "\\" && !inQuotes) {
|
|
36079
|
-
escaped = true;
|
|
36080
|
-
continue;
|
|
36081
|
-
}
|
|
36082
|
-
if (!inQuotes && (char === '"' || char === "'")) {
|
|
36083
|
-
inQuotes = true;
|
|
36084
|
-
quoteChar = char;
|
|
36085
|
-
} else if (inQuotes && char === quoteChar) {
|
|
36086
|
-
inQuotes = false;
|
|
36087
|
-
quoteChar = "";
|
|
36088
|
-
} else if (!inQuotes && char === " ") {
|
|
36089
|
-
if (current.trim()) {
|
|
36090
|
-
args.push(current.trim());
|
|
36091
|
-
current = "";
|
|
36092
|
-
}
|
|
36093
|
-
} else {
|
|
36094
|
-
current += char;
|
|
36095
|
-
}
|
|
36096
|
-
}
|
|
36097
|
-
if (current.trim()) {
|
|
36098
|
-
args.push(current.trim());
|
|
35248
|
+
return null;
|
|
35249
|
+
}
|
|
35250
|
+
function createMessagePreview(message, charsPerSide = 200) {
|
|
35251
|
+
if (message === null || message === void 0) {
|
|
35252
|
+
return "null/undefined";
|
|
36099
35253
|
}
|
|
36100
|
-
if (
|
|
36101
|
-
return
|
|
36102
|
-
success: false,
|
|
36103
|
-
error: `Unclosed quote in command: ${quoteChar}`,
|
|
36104
|
-
command: null,
|
|
36105
|
-
args: [],
|
|
36106
|
-
isComplex: false
|
|
36107
|
-
};
|
|
35254
|
+
if (typeof message !== "string") {
|
|
35255
|
+
return "null/undefined";
|
|
36108
35256
|
}
|
|
36109
|
-
|
|
36110
|
-
|
|
36111
|
-
|
|
36112
|
-
error: "No command found after parsing",
|
|
36113
|
-
command: null,
|
|
36114
|
-
args: [],
|
|
36115
|
-
isComplex: false
|
|
36116
|
-
};
|
|
35257
|
+
const totalChars = charsPerSide * 2;
|
|
35258
|
+
if (message.length <= totalChars) {
|
|
35259
|
+
return message;
|
|
36117
35260
|
}
|
|
36118
|
-
const
|
|
36119
|
-
|
|
36120
|
-
|
|
36121
|
-
error: null,
|
|
36122
|
-
command: baseCommand,
|
|
36123
|
-
args: commandArgs,
|
|
36124
|
-
fullArgs: args,
|
|
36125
|
-
isComplex: false,
|
|
36126
|
-
original: command
|
|
36127
|
-
};
|
|
36128
|
-
}
|
|
36129
|
-
function isComplexCommand(command) {
|
|
36130
|
-
const result = parseSimpleCommand(command);
|
|
36131
|
-
return result.isComplex;
|
|
35261
|
+
const start = message.substring(0, charsPerSide);
|
|
35262
|
+
const end = message.substring(message.length - charsPerSide);
|
|
35263
|
+
return `${start}...${end}`;
|
|
36132
35264
|
}
|
|
36133
|
-
function
|
|
36134
|
-
if (!
|
|
36135
|
-
|
|
36136
|
-
|
|
36137
|
-
|
|
36138
|
-
/&&/,
|
|
36139
|
-
// Logical AND
|
|
36140
|
-
/\|\|/,
|
|
36141
|
-
// Logical OR
|
|
36142
|
-
/;/,
|
|
36143
|
-
// Command separator
|
|
36144
|
-
/&$/,
|
|
36145
|
-
// Background execution
|
|
36146
|
-
/\$\(/,
|
|
36147
|
-
// Command substitution $()
|
|
36148
|
-
/`/,
|
|
36149
|
-
// Command substitution ``
|
|
36150
|
-
/>/,
|
|
36151
|
-
// Redirection >
|
|
36152
|
-
/</
|
|
36153
|
-
// Redirection <
|
|
36154
|
-
];
|
|
36155
|
-
return operatorPatterns.some((p4) => p4.test(pattern));
|
|
35265
|
+
function parseTargets(targets) {
|
|
35266
|
+
if (!targets || typeof targets !== "string") {
|
|
35267
|
+
return [];
|
|
35268
|
+
}
|
|
35269
|
+
return targets.split(/[\s,]+/).filter((f4) => f4.length > 0);
|
|
36156
35270
|
}
|
|
36157
|
-
function
|
|
36158
|
-
|
|
36159
|
-
|
|
36160
|
-
return
|
|
35271
|
+
function parseAndResolvePaths(pathStr, cwd) {
|
|
35272
|
+
if (!pathStr) return [];
|
|
35273
|
+
const paths = pathStr.split(",").map((p4) => p4.trim()).filter((p4) => p4.length > 0);
|
|
35274
|
+
return paths.map((p4) => {
|
|
35275
|
+
if ((0, import_path6.isAbsolute)(p4)) {
|
|
35276
|
+
return p4;
|
|
35277
|
+
}
|
|
35278
|
+
return cwd ? (0, import_path6.resolve)(cwd, p4) : p4;
|
|
35279
|
+
});
|
|
36161
35280
|
}
|
|
36162
|
-
function
|
|
36163
|
-
|
|
36164
|
-
const
|
|
36165
|
-
const
|
|
36166
|
-
|
|
36167
|
-
|
|
36168
|
-
|
|
36169
|
-
|
|
36170
|
-
|
|
35281
|
+
function resolveTargetPath(target, cwd) {
|
|
35282
|
+
const searchStart = target.length > 2 && target[1] === ":" && /[a-zA-Z]/.test(target[0]) ? 2 : 0;
|
|
35283
|
+
const colonIdx = target.indexOf(":", searchStart);
|
|
35284
|
+
const hashIdx = target.indexOf("#");
|
|
35285
|
+
let filePart, suffix;
|
|
35286
|
+
if (colonIdx !== -1 && (hashIdx === -1 || colonIdx < hashIdx)) {
|
|
35287
|
+
filePart = target.substring(0, colonIdx);
|
|
35288
|
+
suffix = target.substring(colonIdx);
|
|
35289
|
+
} else if (hashIdx !== -1) {
|
|
35290
|
+
filePart = target.substring(0, hashIdx);
|
|
35291
|
+
suffix = target.substring(hashIdx);
|
|
35292
|
+
} else {
|
|
35293
|
+
filePart = target;
|
|
35294
|
+
suffix = "";
|
|
35295
|
+
}
|
|
35296
|
+
if (!(0, import_path6.isAbsolute)(filePart) && cwd) {
|
|
35297
|
+
filePart = (0, import_path6.resolve)(cwd, filePart);
|
|
36171
35298
|
}
|
|
35299
|
+
return filePart + suffix;
|
|
36172
35300
|
}
|
|
36173
|
-
|
|
36174
|
-
|
|
36175
|
-
|
|
36176
|
-
|
|
36177
|
-
|
|
36178
|
-
|
|
36179
|
-
|
|
36180
|
-
|
|
35301
|
+
var import_path6, searchSchema, querySchema, extractSchema, delegateSchema, bashSchema, attemptCompletionSchema, searchToolDefinition, queryToolDefinition, extractToolDefinition, delegateToolDefinition, attemptCompletionToolDefinition, bashToolDefinition, searchDescription, queryDescription, extractDescription, delegateDescription, DEFAULT_VALID_TOOLS;
|
|
35302
|
+
var init_common2 = __esm({
|
|
35303
|
+
"src/tools/common.js"() {
|
|
35304
|
+
"use strict";
|
|
35305
|
+
init_zod();
|
|
35306
|
+
import_path6 = require("path");
|
|
35307
|
+
init_edit();
|
|
35308
|
+
searchSchema = external_exports.object({
|
|
35309
|
+
query: external_exports.string().describe("Search query with Elasticsearch syntax. Use quotes for exact matches, AND/OR for boolean logic, - for negation."),
|
|
35310
|
+
path: external_exports.string().optional().default(".").describe('Path to search in. For dependencies use "go:github.com/owner/repo", "js:package_name", or "rust:cargo_name" etc.')
|
|
35311
|
+
});
|
|
35312
|
+
querySchema = external_exports.object({
|
|
35313
|
+
pattern: external_exports.string().describe("AST pattern to search for. Use $NAME for variable names, $$$PARAMS for parameter lists, etc."),
|
|
35314
|
+
path: external_exports.string().optional().default(".").describe("Path to search in"),
|
|
35315
|
+
language: external_exports.string().optional().default("rust").describe("Programming language to use for parsing"),
|
|
35316
|
+
allow_tests: external_exports.boolean().optional().default(true).describe("Allow test files in search results")
|
|
35317
|
+
});
|
|
35318
|
+
extractSchema = external_exports.object({
|
|
35319
|
+
targets: external_exports.string().optional().describe('File paths or symbols to extract from. Formats: "file.js" (whole file), "file.js:42" (line 42), "file.js:10-20" (lines 10-20), "file.js#funcName" (symbol). Multiple targets separated by spaces.'),
|
|
35320
|
+
input_content: external_exports.string().optional().describe("Text content to extract file paths from (alternative to targets)"),
|
|
35321
|
+
allow_tests: external_exports.boolean().optional().default(true).describe("Include test files in extraction results")
|
|
35322
|
+
});
|
|
35323
|
+
delegateSchema = external_exports.object({
|
|
35324
|
+
task: external_exports.string().describe("The task to delegate to a subagent. Be specific about what needs to be accomplished.")
|
|
35325
|
+
});
|
|
35326
|
+
bashSchema = external_exports.object({
|
|
35327
|
+
command: external_exports.string().describe("The bash command to execute"),
|
|
35328
|
+
workingDirectory: external_exports.string().optional().describe("Directory to execute the command in (optional)"),
|
|
35329
|
+
timeout: external_exports.number().optional().describe("Command timeout in milliseconds (optional)"),
|
|
35330
|
+
env: external_exports.record(external_exports.string()).optional().describe("Additional environment variables (optional)")
|
|
35331
|
+
});
|
|
35332
|
+
attemptCompletionSchema = {
|
|
35333
|
+
// Custom validation that requires result parameter but allows direct XML response
|
|
35334
|
+
safeParse: (params) => {
|
|
35335
|
+
if (!params || typeof params !== "object") {
|
|
35336
|
+
return {
|
|
35337
|
+
success: false,
|
|
35338
|
+
error: {
|
|
35339
|
+
issues: [{
|
|
35340
|
+
code: "invalid_type",
|
|
35341
|
+
expected: "object",
|
|
35342
|
+
received: typeof params,
|
|
35343
|
+
path: [],
|
|
35344
|
+
message: "Expected object"
|
|
35345
|
+
}]
|
|
35346
|
+
}
|
|
35347
|
+
};
|
|
35348
|
+
}
|
|
35349
|
+
if (!("result" in params)) {
|
|
35350
|
+
return {
|
|
35351
|
+
success: false,
|
|
35352
|
+
error: {
|
|
35353
|
+
issues: [{
|
|
35354
|
+
code: "invalid_type",
|
|
35355
|
+
expected: "string",
|
|
35356
|
+
received: "undefined",
|
|
35357
|
+
path: ["result"],
|
|
35358
|
+
message: "Required"
|
|
35359
|
+
}]
|
|
35360
|
+
}
|
|
35361
|
+
};
|
|
35362
|
+
}
|
|
35363
|
+
if (typeof params.result !== "string") {
|
|
35364
|
+
return {
|
|
35365
|
+
success: false,
|
|
35366
|
+
error: {
|
|
35367
|
+
issues: [{
|
|
35368
|
+
code: "invalid_type",
|
|
35369
|
+
expected: "string",
|
|
35370
|
+
received: typeof params.result,
|
|
35371
|
+
path: ["result"],
|
|
35372
|
+
message: "Expected string"
|
|
35373
|
+
}]
|
|
35374
|
+
}
|
|
35375
|
+
};
|
|
35376
|
+
}
|
|
35377
|
+
const filteredData = { result: params.result };
|
|
35378
|
+
return {
|
|
35379
|
+
success: true,
|
|
35380
|
+
data: filteredData
|
|
35381
|
+
};
|
|
35382
|
+
}
|
|
36181
35383
|
};
|
|
36182
|
-
|
|
36183
|
-
|
|
36184
|
-
|
|
36185
|
-
|
|
36186
|
-
|
|
36187
|
-
|
|
36188
|
-
|
|
36189
|
-
|
|
36190
|
-
|
|
36191
|
-
|
|
36192
|
-
|
|
36193
|
-
|
|
36194
|
-
|
|
36195
|
-
|
|
36196
|
-
|
|
36197
|
-
|
|
36198
|
-
|
|
36199
|
-
|
|
35384
|
+
searchToolDefinition = `
|
|
35385
|
+
## search
|
|
35386
|
+
Description: Search code in the repository using Elasticsearch query syntax (except field based queries, e.g. "filename:..." NOT supported).
|
|
35387
|
+
|
|
35388
|
+
You need to focus on main keywords when constructing the query, and always use elastic search syntax like OR AND and brackets to group keywords.
|
|
35389
|
+
|
|
35390
|
+
**Session Management & Caching:**
|
|
35391
|
+
- Ensure not to re-read the same symbols twice - reuse context from previous tool calls
|
|
35392
|
+
- Probe returns a session ID on first run - reuse it for subsequent calls to avoid redundant searches
|
|
35393
|
+
- Once data is returned, it's cached and won't return on next runs (this is expected behavior)
|
|
35394
|
+
|
|
35395
|
+
Parameters:
|
|
35396
|
+
- query: (required) Search query with Elasticsearch syntax. Use quotes for exact matches ("functionName"), AND/OR for boolean logic, - for negation, + for important terms.
|
|
35397
|
+
- path: (optional, default: '.') Path to search in. All dependencies located in /dep folder, under language sub folders, like this: "/dep/go/github.com/owner/repo", "/dep/js/package_name", or "/dep/rust/cargo_name" etc.
|
|
35398
|
+
|
|
35399
|
+
**Workflow:** Always start with search, then use extract for detailed context when needed.
|
|
35400
|
+
|
|
35401
|
+
Usage Example:
|
|
35402
|
+
|
|
35403
|
+
<examples>
|
|
35404
|
+
|
|
35405
|
+
User: Where is the login logic?
|
|
35406
|
+
Assistant workflow:
|
|
35407
|
+
1. <search>
|
|
35408
|
+
<query>login AND auth AND token</query>
|
|
35409
|
+
<path>.</path>
|
|
35410
|
+
</search>
|
|
35411
|
+
2. Now lets look closer: <extract>
|
|
35412
|
+
<targets>session.rs#AuthService.login auth.rs:2-100</targets>
|
|
35413
|
+
</extract>
|
|
35414
|
+
|
|
35415
|
+
User: How to calculate the total amount in the payments module?
|
|
35416
|
+
<search>
|
|
35417
|
+
<query>calculate AND payment</query>
|
|
35418
|
+
<path>src/utils</path>
|
|
35419
|
+
</search>
|
|
35420
|
+
|
|
35421
|
+
User: How do the user authentication and authorization work?
|
|
35422
|
+
<search>
|
|
35423
|
+
<query>+user AND (authentication OR authorization OR authz)</query>
|
|
35424
|
+
<path>.</path>
|
|
35425
|
+
</search>
|
|
35426
|
+
|
|
35427
|
+
User: Find all react imports in the project.
|
|
35428
|
+
<search>
|
|
35429
|
+
<query>"import" AND "react"</query>
|
|
35430
|
+
<path>.</path>
|
|
35431
|
+
</search>
|
|
35432
|
+
|
|
35433
|
+
User: Find how decompound library works?
|
|
35434
|
+
<search>
|
|
35435
|
+
<query>decompound</query>
|
|
35436
|
+
<path>/dep/rust/decompound</path>
|
|
35437
|
+
</search>
|
|
35438
|
+
|
|
35439
|
+
</examples>
|
|
35440
|
+
`;
|
|
35441
|
+
queryToolDefinition = `
|
|
35442
|
+
## query
|
|
35443
|
+
Description: Search code using ast-grep structural pattern matching. Use this tool to find specific code structures like functions, classes, or methods.
|
|
35444
|
+
Parameters:
|
|
35445
|
+
- pattern: (required) AST pattern to search for. Use $NAME for variable names, $$$PARAMS for parameter lists, etc.
|
|
35446
|
+
- path: (optional, default: '.') Path to search in.
|
|
35447
|
+
- language: (optional, default: 'rust') Programming language to use for parsing.
|
|
35448
|
+
- allow_tests: (optional, default: true) Allow test files in search results (true/false).
|
|
35449
|
+
Usage Example:
|
|
35450
|
+
|
|
35451
|
+
<examples>
|
|
35452
|
+
|
|
35453
|
+
<query>
|
|
35454
|
+
<pattern>function $FUNC($$$PARAMS) { $$$BODY }</pattern>
|
|
35455
|
+
<path>src/parser</path>
|
|
35456
|
+
<language>js</language>
|
|
35457
|
+
</query>
|
|
35458
|
+
|
|
35459
|
+
</examples>
|
|
35460
|
+
`;
|
|
35461
|
+
extractToolDefinition = `
|
|
35462
|
+
## extract
|
|
35463
|
+
Description: Extract code blocks from files based on file paths and optional line numbers. Use this tool to see complete context after finding relevant files. It can be used to read full files as well.
|
|
35464
|
+
Full file extraction should be the LAST RESORT! Always prefer search.
|
|
35465
|
+
|
|
35466
|
+
**Multiple Extraction:** You can extract multiple symbols/files in one call by providing multiple file paths separated by spaces.
|
|
35467
|
+
|
|
35468
|
+
**Session Awareness:** Reuse context from previous tool calls. Don't re-extract the same symbols you already have.
|
|
35469
|
+
|
|
35470
|
+
Parameters:
|
|
35471
|
+
- targets: (required) File paths or symbols to extract from. Formats: "file.js" (whole file), "file.js:42" (code block at line 42), "file.js:10-20" (lines 10-20), "file.js#funcName" (specific symbol). Multiple targets separated by spaces.
|
|
35472
|
+
- input_content: (optional) Text content to extract file paths from (alternative to targets for processing diffs/logs).
|
|
35473
|
+
- allow_tests: (optional, default: true) Include test files in extraction results.
|
|
35474
|
+
|
|
35475
|
+
Usage Example:
|
|
35476
|
+
|
|
35477
|
+
<examples>
|
|
35478
|
+
|
|
35479
|
+
User: Where is the login logic? (After search found relevant files)
|
|
35480
|
+
<extract>
|
|
35481
|
+
<targets>session.rs#AuthService.login auth.rs:2-100 config.rs#DatabaseConfig</targets>
|
|
35482
|
+
</extract>
|
|
35483
|
+
|
|
35484
|
+
User: How does error handling work? (After search identified files)
|
|
35485
|
+
<extract>
|
|
35486
|
+
<targets>error.rs#ErrorType utils.rs#handle_error src/main.rs:50-80</targets>
|
|
35487
|
+
</extract>
|
|
35488
|
+
|
|
35489
|
+
User: How RankManager works
|
|
35490
|
+
<extract>
|
|
35491
|
+
<targets>src/search/ranking.rs#RankManager</targets>
|
|
35492
|
+
</extract>
|
|
35493
|
+
|
|
35494
|
+
User: Lets read the whole file
|
|
35495
|
+
<extract>
|
|
35496
|
+
<targets>src/search/ranking.rs</targets>
|
|
35497
|
+
</extract>
|
|
35498
|
+
|
|
35499
|
+
User: Read the first 10 lines of the file
|
|
35500
|
+
<extract>
|
|
35501
|
+
<targets>src/search/ranking.rs:1-10</targets>
|
|
35502
|
+
</extract>
|
|
35503
|
+
|
|
35504
|
+
User: Read file inside the dependency
|
|
35505
|
+
<extract>
|
|
35506
|
+
<targets>/dep/go/github.com/gorilla/mux/router.go</targets>
|
|
35507
|
+
</extract>
|
|
35508
|
+
|
|
35509
|
+
</examples>
|
|
35510
|
+
`;
|
|
35511
|
+
delegateToolDefinition = `
|
|
35512
|
+
## delegate
|
|
35513
|
+
Description: Automatically delegate big distinct tasks to specialized probe subagents within the agentic loop. Use this when you recognize that a user's request involves multiple large, distinct components that would benefit from parallel processing or specialized focus. The AI agent should automatically identify opportunities for task separation and use delegation without explicit user instruction.
|
|
35514
|
+
|
|
35515
|
+
Parameters:
|
|
35516
|
+
- task: (required) A complete, self-contained task that can be executed independently by a subagent. Should be specific and focused on one area of expertise.
|
|
35517
|
+
|
|
35518
|
+
Usage Pattern:
|
|
35519
|
+
When the AI agent encounters complex multi-part requests, it should automatically break them down and delegate:
|
|
35520
|
+
|
|
35521
|
+
<delegate>
|
|
35522
|
+
<task>Analyze all authentication and authorization code in the codebase for security vulnerabilities and provide specific remediation recommendations</task>
|
|
35523
|
+
</delegate>
|
|
35524
|
+
|
|
35525
|
+
<delegate>
|
|
35526
|
+
<task>Review database queries and API endpoints for performance bottlenecks and suggest optimization strategies</task>
|
|
35527
|
+
</delegate>
|
|
35528
|
+
|
|
35529
|
+
The agent uses this tool automatically when it identifies that work can be separated into distinct, parallel tasks for more efficient processing.
|
|
35530
|
+
`;
|
|
35531
|
+
attemptCompletionToolDefinition = `
|
|
35532
|
+
## attempt_completion
|
|
35533
|
+
Description: Use this tool ONLY when the task is fully complete and you have received confirmation of success for all previous tool uses. Presents the final result to the user. You can provide your response directly inside the XML tags without any parameter wrapper.
|
|
35534
|
+
Parameters:
|
|
35535
|
+
- No validation required - provide your complete answer directly inside the XML tags.
|
|
35536
|
+
Usage Example:
|
|
35537
|
+
<attempt_completion>
|
|
35538
|
+
I have refactored the search module according to the requirements and verified the tests pass. The module now uses the new BM25 ranking algorithm and has improved error handling.
|
|
35539
|
+
</attempt_completion>
|
|
35540
|
+
`;
|
|
35541
|
+
bashToolDefinition = `
|
|
35542
|
+
## bash
|
|
35543
|
+
Description: Execute bash commands for system exploration and development tasks. This tool has built-in security with allow/deny lists. By default, only safe read-only commands are allowed for code exploration.
|
|
35544
|
+
|
|
35545
|
+
Parameters:
|
|
35546
|
+
- command: (required) The bash command to execute
|
|
35547
|
+
- workingDirectory: (optional) Directory to execute the command in
|
|
35548
|
+
- timeout: (optional) Command timeout in milliseconds
|
|
35549
|
+
- env: (optional) Additional environment variables as an object
|
|
35550
|
+
|
|
35551
|
+
Security: Commands are filtered through allow/deny lists for safety:
|
|
35552
|
+
- Allowed by default: ls, cat, git status, npm list, find, grep, etc.
|
|
35553
|
+
- Denied by default: rm -rf, sudo, npm install, dangerous system commands
|
|
35554
|
+
|
|
35555
|
+
Usage Examples:
|
|
35556
|
+
|
|
35557
|
+
<examples>
|
|
35558
|
+
|
|
35559
|
+
User: What files are in the src directory?
|
|
35560
|
+
<bash>
|
|
35561
|
+
<command>ls -la src/</command>
|
|
35562
|
+
</bash>
|
|
35563
|
+
|
|
35564
|
+
User: Show me the git status
|
|
35565
|
+
<bash>
|
|
35566
|
+
<command>git status</command>
|
|
35567
|
+
</bash>
|
|
35568
|
+
|
|
35569
|
+
User: Find all TypeScript files
|
|
35570
|
+
<bash>
|
|
35571
|
+
<command>find . -name "*.ts" -type f</command>
|
|
35572
|
+
</bash>
|
|
35573
|
+
|
|
35574
|
+
User: Check installed npm packages
|
|
35575
|
+
<bash>
|
|
35576
|
+
<command>npm list --depth=0</command>
|
|
35577
|
+
</bash>
|
|
35578
|
+
|
|
35579
|
+
User: Search for TODO comments in code
|
|
35580
|
+
<bash>
|
|
35581
|
+
<command>grep -r "TODO" src/</command>
|
|
35582
|
+
</bash>
|
|
35583
|
+
|
|
35584
|
+
User: Show recent git commits
|
|
35585
|
+
<bash>
|
|
35586
|
+
<command>git log --oneline -10</command>
|
|
35587
|
+
</bash>
|
|
35588
|
+
|
|
35589
|
+
User: Check system info
|
|
35590
|
+
<bash>
|
|
35591
|
+
<command>uname -a</command>
|
|
35592
|
+
</bash>
|
|
35593
|
+
|
|
35594
|
+
</examples>
|
|
35595
|
+
`;
|
|
35596
|
+
searchDescription = "Search code in the repository using Elasticsearch-like query syntax. Use this tool first for any code-related questions.";
|
|
35597
|
+
queryDescription = "Search code using ast-grep structural pattern matching. Use this tool to find specific code structures like functions, classes, or methods.";
|
|
35598
|
+
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.";
|
|
35599
|
+
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.";
|
|
35600
|
+
DEFAULT_VALID_TOOLS = [
|
|
35601
|
+
"search",
|
|
35602
|
+
"query",
|
|
35603
|
+
"extract",
|
|
35604
|
+
"delegate",
|
|
35605
|
+
"listFiles",
|
|
35606
|
+
"searchFiles",
|
|
35607
|
+
"implement",
|
|
35608
|
+
"bash",
|
|
35609
|
+
"attempt_completion"
|
|
35610
|
+
];
|
|
36200
35611
|
}
|
|
36201
35612
|
});
|
|
36202
35613
|
|
|
36203
|
-
// src/
|
|
36204
|
-
|
|
36205
|
-
|
|
36206
|
-
|
|
36207
|
-
if (!command) return false;
|
|
36208
|
-
const patternParts = pattern.split(":");
|
|
36209
|
-
const commandName = patternParts[0];
|
|
36210
|
-
if (commandName === "*") {
|
|
36211
|
-
return true;
|
|
36212
|
-
} else if (commandName !== command) {
|
|
36213
|
-
return false;
|
|
36214
|
-
}
|
|
36215
|
-
if (patternParts.length === 1) {
|
|
36216
|
-
return true;
|
|
36217
|
-
}
|
|
36218
|
-
for (let i4 = 1; i4 < patternParts.length; i4++) {
|
|
36219
|
-
const patternArg = patternParts[i4];
|
|
36220
|
-
const argIndex = i4 - 1;
|
|
36221
|
-
if (patternArg === "*") {
|
|
36222
|
-
continue;
|
|
36223
|
-
}
|
|
36224
|
-
if (argIndex >= args.length) {
|
|
36225
|
-
return false;
|
|
36226
|
-
}
|
|
36227
|
-
const actualArg = args[argIndex];
|
|
36228
|
-
if (patternArg !== actualArg) {
|
|
36229
|
-
return false;
|
|
36230
|
-
}
|
|
36231
|
-
}
|
|
36232
|
-
return true;
|
|
36233
|
-
}
|
|
36234
|
-
function matchesAnyPattern(parsedCommand, patterns) {
|
|
36235
|
-
if (!patterns || patterns.length === 0) return false;
|
|
36236
|
-
return patterns.some((pattern) => matchesPattern(parsedCommand, pattern));
|
|
36237
|
-
}
|
|
36238
|
-
var BashPermissionChecker;
|
|
36239
|
-
var init_bashPermissions = __esm({
|
|
36240
|
-
"src/agent/bashPermissions.js"() {
|
|
35614
|
+
// src/tools/vercel.js
|
|
35615
|
+
var import_ai2, searchTool, queryTool, extractTool, delegateTool;
|
|
35616
|
+
var init_vercel = __esm({
|
|
35617
|
+
"src/tools/vercel.js"() {
|
|
36241
35618
|
"use strict";
|
|
36242
|
-
|
|
36243
|
-
|
|
36244
|
-
|
|
36245
|
-
|
|
36246
|
-
|
|
36247
|
-
|
|
36248
|
-
|
|
36249
|
-
|
|
36250
|
-
|
|
36251
|
-
|
|
36252
|
-
|
|
36253
|
-
|
|
36254
|
-
|
|
36255
|
-
|
|
36256
|
-
|
|
36257
|
-
|
|
36258
|
-
|
|
36259
|
-
|
|
36260
|
-
|
|
36261
|
-
|
|
36262
|
-
|
|
36263
|
-
|
|
36264
|
-
|
|
36265
|
-
|
|
36266
|
-
|
|
36267
|
-
|
|
36268
|
-
|
|
36269
|
-
|
|
36270
|
-
|
|
36271
|
-
|
|
36272
|
-
|
|
36273
|
-
|
|
36274
|
-
|
|
36275
|
-
|
|
36276
|
-
|
|
36277
|
-
|
|
36278
|
-
|
|
36279
|
-
|
|
36280
|
-
|
|
36281
|
-
}
|
|
36282
|
-
if (this.debug) {
|
|
36283
|
-
console.log(`[BashPermissions] Total patterns - Allow: ${this.allowPatterns.length}, Deny: ${this.denyPatterns.length}`);
|
|
36284
|
-
}
|
|
36285
|
-
}
|
|
36286
|
-
/**
|
|
36287
|
-
* Check if a simple command is allowed (complex commands allowed if they match patterns)
|
|
36288
|
-
* @param {string} command - Command to check
|
|
36289
|
-
* @returns {Object} Permission result
|
|
36290
|
-
*/
|
|
36291
|
-
check(command) {
|
|
36292
|
-
if (!command || typeof command !== "string") {
|
|
36293
|
-
return {
|
|
36294
|
-
allowed: false,
|
|
36295
|
-
reason: "Invalid or empty command",
|
|
36296
|
-
command
|
|
36297
|
-
};
|
|
36298
|
-
}
|
|
36299
|
-
const commandIsComplex = isComplexCommand(command);
|
|
36300
|
-
if (commandIsComplex) {
|
|
36301
|
-
return this._checkComplexCommand(command);
|
|
36302
|
-
}
|
|
36303
|
-
const parsed = parseCommand(command);
|
|
36304
|
-
if (parsed.error) {
|
|
36305
|
-
return {
|
|
36306
|
-
allowed: false,
|
|
36307
|
-
reason: parsed.error,
|
|
36308
|
-
command
|
|
36309
|
-
};
|
|
36310
|
-
}
|
|
36311
|
-
if (!parsed.command) {
|
|
36312
|
-
return {
|
|
36313
|
-
allowed: false,
|
|
36314
|
-
reason: "No valid command found",
|
|
36315
|
-
command
|
|
36316
|
-
};
|
|
36317
|
-
}
|
|
36318
|
-
if (this.debug) {
|
|
36319
|
-
console.log(`[BashPermissions] Checking simple command: "${command}"`);
|
|
36320
|
-
console.log(`[BashPermissions] Parsed: ${parsed.command} with args: [${parsed.args.join(", ")}]`);
|
|
36321
|
-
}
|
|
36322
|
-
if (matchesAnyPattern(parsed, this.denyPatterns)) {
|
|
36323
|
-
const matchedPatterns = this.denyPatterns.filter((pattern) => matchesPattern(parsed, pattern));
|
|
36324
|
-
return {
|
|
36325
|
-
allowed: false,
|
|
36326
|
-
reason: `Command matches deny pattern: ${matchedPatterns[0]}`,
|
|
36327
|
-
command,
|
|
36328
|
-
parsed,
|
|
36329
|
-
matchedPatterns
|
|
36330
|
-
};
|
|
36331
|
-
}
|
|
36332
|
-
if (this.allowPatterns.length > 0) {
|
|
36333
|
-
if (!matchesAnyPattern(parsed, this.allowPatterns)) {
|
|
36334
|
-
return {
|
|
36335
|
-
allowed: false,
|
|
36336
|
-
reason: "Command not in allow list",
|
|
36337
|
-
command,
|
|
36338
|
-
parsed
|
|
35619
|
+
import_ai2 = require("ai");
|
|
35620
|
+
init_search();
|
|
35621
|
+
init_query();
|
|
35622
|
+
init_extract();
|
|
35623
|
+
init_delegate();
|
|
35624
|
+
init_common2();
|
|
35625
|
+
searchTool = (options = {}) => {
|
|
35626
|
+
const { sessionId, maxTokens = 1e4, debug = false, outline = false } = options;
|
|
35627
|
+
return (0, import_ai2.tool)({
|
|
35628
|
+
name: "search",
|
|
35629
|
+
description: searchDescription,
|
|
35630
|
+
inputSchema: searchSchema,
|
|
35631
|
+
execute: async ({ query: searchQuery, path: path9, allow_tests, exact, maxTokens: paramMaxTokens, language }) => {
|
|
35632
|
+
try {
|
|
35633
|
+
const effectiveMaxTokens = paramMaxTokens || maxTokens;
|
|
35634
|
+
let searchPaths;
|
|
35635
|
+
if (path9) {
|
|
35636
|
+
searchPaths = parseAndResolvePaths(path9, options.cwd);
|
|
35637
|
+
}
|
|
35638
|
+
if (!searchPaths || searchPaths.length === 0) {
|
|
35639
|
+
searchPaths = [options.cwd || "."];
|
|
35640
|
+
}
|
|
35641
|
+
const searchPath = searchPaths.join(" ");
|
|
35642
|
+
if (debug) {
|
|
35643
|
+
console.error(`Executing search with query: "${searchQuery}", path: "${searchPath}", exact: ${exact ? "true" : "false"}, language: ${language || "all"}, session: ${sessionId || "none"}`);
|
|
35644
|
+
}
|
|
35645
|
+
const searchOptions = {
|
|
35646
|
+
query: searchQuery,
|
|
35647
|
+
path: searchPath,
|
|
35648
|
+
cwd: options.cwd,
|
|
35649
|
+
// Working directory for resolving relative paths
|
|
35650
|
+
allowTests: allow_tests ?? true,
|
|
35651
|
+
exact,
|
|
35652
|
+
json: false,
|
|
35653
|
+
maxTokens: effectiveMaxTokens,
|
|
35654
|
+
session: sessionId,
|
|
35655
|
+
// Pass session ID if provided
|
|
35656
|
+
language
|
|
35657
|
+
// Pass language parameter if provided
|
|
36339
35658
|
};
|
|
35659
|
+
if (outline) {
|
|
35660
|
+
searchOptions.format = "outline-xml";
|
|
35661
|
+
}
|
|
35662
|
+
const results = await search(searchOptions);
|
|
35663
|
+
return results;
|
|
35664
|
+
} catch (error2) {
|
|
35665
|
+
console.error("Error executing search command:", error2);
|
|
35666
|
+
return `Error executing search command: ${error2.message}`;
|
|
36340
35667
|
}
|
|
36341
35668
|
}
|
|
36342
|
-
|
|
36343
|
-
|
|
36344
|
-
|
|
36345
|
-
|
|
36346
|
-
|
|
36347
|
-
|
|
36348
|
-
|
|
36349
|
-
|
|
36350
|
-
}
|
|
36351
|
-
|
|
36352
|
-
|
|
36353
|
-
|
|
36354
|
-
|
|
36355
|
-
* @private
|
|
36356
|
-
* @param {string} command - Complex command to check
|
|
36357
|
-
* @returns {Object} Permission result
|
|
36358
|
-
*/
|
|
36359
|
-
_checkComplexCommand(command) {
|
|
36360
|
-
if (this.debug) {
|
|
36361
|
-
console.log(`[BashPermissions] Checking complex command: "${command}"`);
|
|
36362
|
-
}
|
|
36363
|
-
const complexAllowPatterns = this.allowPatterns.filter((p4) => isComplexPattern(p4));
|
|
36364
|
-
const complexDenyPatterns = this.denyPatterns.filter((p4) => isComplexPattern(p4));
|
|
36365
|
-
if (this.debug) {
|
|
36366
|
-
console.log(`[BashPermissions] Complex allow patterns: ${complexAllowPatterns.length}`);
|
|
36367
|
-
console.log(`[BashPermissions] Complex deny patterns: ${complexDenyPatterns.length}`);
|
|
36368
|
-
}
|
|
36369
|
-
for (const pattern of complexDenyPatterns) {
|
|
36370
|
-
if (matchesComplexPattern(command, pattern)) {
|
|
36371
|
-
if (this.debug) {
|
|
36372
|
-
console.log(`[BashPermissions] DENIED - matches complex deny pattern: ${pattern}`);
|
|
35669
|
+
});
|
|
35670
|
+
};
|
|
35671
|
+
queryTool = (options = {}) => {
|
|
35672
|
+
const { debug = false } = options;
|
|
35673
|
+
return (0, import_ai2.tool)({
|
|
35674
|
+
name: "query",
|
|
35675
|
+
description: queryDescription,
|
|
35676
|
+
inputSchema: querySchema,
|
|
35677
|
+
execute: async ({ pattern, path: path9, language, allow_tests }) => {
|
|
35678
|
+
try {
|
|
35679
|
+
let queryPaths;
|
|
35680
|
+
if (path9) {
|
|
35681
|
+
queryPaths = parseAndResolvePaths(path9, options.cwd);
|
|
36373
35682
|
}
|
|
36374
|
-
|
|
36375
|
-
|
|
36376
|
-
|
|
36377
|
-
|
|
36378
|
-
|
|
36379
|
-
|
|
36380
|
-
}
|
|
35683
|
+
if (!queryPaths || queryPaths.length === 0) {
|
|
35684
|
+
queryPaths = [options.cwd || "."];
|
|
35685
|
+
}
|
|
35686
|
+
const queryPath = queryPaths.join(" ");
|
|
35687
|
+
if (debug) {
|
|
35688
|
+
console.error(`Executing query with pattern: "${pattern}", path: "${queryPath}", language: ${language || "auto"}`);
|
|
35689
|
+
}
|
|
35690
|
+
const results = await query({
|
|
35691
|
+
pattern,
|
|
35692
|
+
path: queryPath,
|
|
35693
|
+
cwd: options.cwd,
|
|
35694
|
+
// Working directory for resolving relative paths
|
|
35695
|
+
language,
|
|
35696
|
+
allowTests: allow_tests ?? true,
|
|
35697
|
+
json: false
|
|
35698
|
+
});
|
|
35699
|
+
return results;
|
|
35700
|
+
} catch (error2) {
|
|
35701
|
+
console.error("Error executing query command:", error2);
|
|
35702
|
+
return `Error executing query command: ${error2.message}`;
|
|
36381
35703
|
}
|
|
36382
35704
|
}
|
|
36383
|
-
|
|
36384
|
-
|
|
36385
|
-
|
|
36386
|
-
|
|
35705
|
+
});
|
|
35706
|
+
};
|
|
35707
|
+
extractTool = (options = {}) => {
|
|
35708
|
+
const { debug = false, outline = false } = options;
|
|
35709
|
+
return (0, import_ai2.tool)({
|
|
35710
|
+
name: "extract",
|
|
35711
|
+
description: extractDescription,
|
|
35712
|
+
inputSchema: extractSchema,
|
|
35713
|
+
execute: async ({ targets, input_content, line, end_line, allow_tests, context_lines, format: format2 }) => {
|
|
35714
|
+
try {
|
|
35715
|
+
const effectiveCwd = options.cwd || ".";
|
|
35716
|
+
if (debug) {
|
|
35717
|
+
if (targets) {
|
|
35718
|
+
console.error(`Executing extract with targets: "${targets}", cwd: "${effectiveCwd}", context lines: ${context_lines || 10}`);
|
|
35719
|
+
} else if (input_content) {
|
|
35720
|
+
console.error(`Executing extract with input content, cwd: "${effectiveCwd}", context lines: ${context_lines || 10}`);
|
|
35721
|
+
}
|
|
36387
35722
|
}
|
|
36388
|
-
|
|
36389
|
-
|
|
36390
|
-
|
|
36391
|
-
|
|
36392
|
-
|
|
36393
|
-
|
|
35723
|
+
let tempFilePath = null;
|
|
35724
|
+
let extractOptions = { cwd: effectiveCwd };
|
|
35725
|
+
if (input_content) {
|
|
35726
|
+
const { writeFileSync: writeFileSync2, unlinkSync } = await import("fs");
|
|
35727
|
+
const { join: join3 } = await import("path");
|
|
35728
|
+
const { tmpdir } = await import("os");
|
|
35729
|
+
const { randomUUID: randomUUID6 } = await import("crypto");
|
|
35730
|
+
tempFilePath = join3(tmpdir(), `probe-extract-${randomUUID6()}.txt`);
|
|
35731
|
+
writeFileSync2(tempFilePath, input_content);
|
|
35732
|
+
if (debug) {
|
|
35733
|
+
console.error(`Created temporary file for input content: ${tempFilePath}`);
|
|
35734
|
+
}
|
|
35735
|
+
let effectiveFormat = format2;
|
|
35736
|
+
if (outline && format2 === "outline-xml") {
|
|
35737
|
+
effectiveFormat = "xml";
|
|
35738
|
+
}
|
|
35739
|
+
extractOptions = {
|
|
35740
|
+
inputFile: tempFilePath,
|
|
35741
|
+
cwd: effectiveCwd,
|
|
35742
|
+
allowTests: allow_tests ?? true,
|
|
35743
|
+
contextLines: context_lines,
|
|
35744
|
+
format: effectiveFormat
|
|
35745
|
+
};
|
|
35746
|
+
} else if (targets) {
|
|
35747
|
+
const parsedTargets = parseTargets(targets);
|
|
35748
|
+
const files = parsedTargets.map((target) => resolveTargetPath(target, effectiveCwd));
|
|
35749
|
+
let effectiveFormat = format2;
|
|
35750
|
+
if (outline && format2 === "outline-xml") {
|
|
35751
|
+
effectiveFormat = "xml";
|
|
35752
|
+
}
|
|
35753
|
+
extractOptions = {
|
|
35754
|
+
files,
|
|
35755
|
+
cwd: effectiveCwd,
|
|
35756
|
+
allowTests: allow_tests ?? true,
|
|
35757
|
+
contextLines: context_lines,
|
|
35758
|
+
format: effectiveFormat
|
|
35759
|
+
};
|
|
35760
|
+
} else {
|
|
35761
|
+
throw new Error("Either targets or input_content must be provided");
|
|
35762
|
+
}
|
|
35763
|
+
const results = await extract(extractOptions);
|
|
35764
|
+
if (tempFilePath) {
|
|
35765
|
+
const { unlinkSync } = await import("fs");
|
|
35766
|
+
try {
|
|
35767
|
+
unlinkSync(tempFilePath);
|
|
35768
|
+
if (debug) {
|
|
35769
|
+
console.error(`Removed temporary file: ${tempFilePath}`);
|
|
35770
|
+
}
|
|
35771
|
+
} catch (cleanupError) {
|
|
35772
|
+
console.error(`Warning: Failed to remove temporary file: ${cleanupError.message}`);
|
|
35773
|
+
}
|
|
35774
|
+
}
|
|
35775
|
+
return results;
|
|
35776
|
+
} catch (error2) {
|
|
35777
|
+
console.error("Error executing extract command:", error2);
|
|
35778
|
+
return `Error executing extract command: ${error2.message}`;
|
|
36394
35779
|
}
|
|
36395
35780
|
}
|
|
36396
|
-
|
|
36397
|
-
console.log(`[BashPermissions] DENIED - no matching complex pattern found`);
|
|
36398
|
-
}
|
|
36399
|
-
return {
|
|
36400
|
-
allowed: false,
|
|
36401
|
-
reason: 'Complex shell commands require explicit allow patterns (e.g., "cd * && git *")',
|
|
36402
|
-
command,
|
|
36403
|
-
isComplex: true
|
|
36404
|
-
};
|
|
36405
|
-
}
|
|
36406
|
-
/**
|
|
36407
|
-
* Get configuration summary
|
|
36408
|
-
* @returns {Object} Configuration info
|
|
36409
|
-
*/
|
|
36410
|
-
getConfig() {
|
|
36411
|
-
return {
|
|
36412
|
-
allowPatterns: this.allowPatterns.length,
|
|
36413
|
-
denyPatterns: this.denyPatterns.length,
|
|
36414
|
-
totalPatterns: this.allowPatterns.length + this.denyPatterns.length
|
|
36415
|
-
};
|
|
36416
|
-
}
|
|
36417
|
-
};
|
|
36418
|
-
}
|
|
36419
|
-
});
|
|
36420
|
-
|
|
36421
|
-
// src/agent/bashExecutor.js
|
|
36422
|
-
async function executeBashCommand(command, options = {}) {
|
|
36423
|
-
const {
|
|
36424
|
-
workingDirectory = process.cwd(),
|
|
36425
|
-
timeout = 12e4,
|
|
36426
|
-
// 2 minutes default
|
|
36427
|
-
env = {},
|
|
36428
|
-
maxBuffer = 10 * 1024 * 1024,
|
|
36429
|
-
// 10MB
|
|
36430
|
-
debug = false
|
|
36431
|
-
} = options;
|
|
36432
|
-
let cwd = workingDirectory;
|
|
36433
|
-
try {
|
|
36434
|
-
cwd = (0, import_path6.resolve)(cwd);
|
|
36435
|
-
if (!(0, import_fs4.existsSync)(cwd)) {
|
|
36436
|
-
throw new Error(`Working directory does not exist: ${cwd}`);
|
|
36437
|
-
}
|
|
36438
|
-
} catch (error2) {
|
|
36439
|
-
return {
|
|
36440
|
-
success: false,
|
|
36441
|
-
error: `Invalid working directory: ${error2.message}`,
|
|
36442
|
-
stdout: "",
|
|
36443
|
-
stderr: "",
|
|
36444
|
-
exitCode: 1,
|
|
36445
|
-
command,
|
|
36446
|
-
workingDirectory: cwd,
|
|
36447
|
-
duration: 0
|
|
36448
|
-
};
|
|
36449
|
-
}
|
|
36450
|
-
const startTime = Date.now();
|
|
36451
|
-
if (debug) {
|
|
36452
|
-
console.log(`[BashExecutor] Executing command: "${command}"`);
|
|
36453
|
-
console.log(`[BashExecutor] Working directory: "${cwd}"`);
|
|
36454
|
-
console.log(`[BashExecutor] Timeout: ${timeout}ms`);
|
|
36455
|
-
}
|
|
36456
|
-
return new Promise((resolve6, reject2) => {
|
|
36457
|
-
const processEnv = {
|
|
36458
|
-
...process.env,
|
|
36459
|
-
...env
|
|
35781
|
+
});
|
|
36460
35782
|
};
|
|
36461
|
-
|
|
36462
|
-
|
|
36463
|
-
|
|
36464
|
-
|
|
36465
|
-
|
|
36466
|
-
|
|
36467
|
-
|
|
36468
|
-
|
|
36469
|
-
|
|
36470
|
-
|
|
36471
|
-
|
|
36472
|
-
|
|
36473
|
-
|
|
36474
|
-
|
|
36475
|
-
|
|
36476
|
-
|
|
36477
|
-
|
|
36478
|
-
|
|
36479
|
-
|
|
36480
|
-
|
|
36481
|
-
|
|
36482
|
-
|
|
36483
|
-
|
|
36484
|
-
|
|
36485
|
-
|
|
36486
|
-
|
|
36487
|
-
|
|
36488
|
-
|
|
36489
|
-
|
|
36490
|
-
|
|
36491
|
-
|
|
36492
|
-
|
|
36493
|
-
|
|
36494
|
-
|
|
36495
|
-
|
|
36496
|
-
|
|
36497
|
-
|
|
36498
|
-
|
|
36499
|
-
|
|
36500
|
-
|
|
36501
|
-
|
|
36502
|
-
|
|
36503
|
-
|
|
36504
|
-
|
|
36505
|
-
|
|
36506
|
-
|
|
36507
|
-
|
|
36508
|
-
|
|
36509
|
-
|
|
36510
|
-
|
|
36511
|
-
|
|
36512
|
-
|
|
36513
|
-
|
|
36514
|
-
|
|
36515
|
-
|
|
36516
|
-
|
|
36517
|
-
|
|
36518
|
-
} else {
|
|
36519
|
-
if (!killed) {
|
|
36520
|
-
killed = true;
|
|
36521
|
-
child.kill("SIGTERM");
|
|
36522
|
-
}
|
|
36523
|
-
}
|
|
36524
|
-
});
|
|
36525
|
-
child.stderr.on("data", (data2) => {
|
|
36526
|
-
const chunk = data2.toString();
|
|
36527
|
-
if (stderr.length + chunk.length <= maxBuffer) {
|
|
36528
|
-
stderr += chunk;
|
|
36529
|
-
} else {
|
|
36530
|
-
if (!killed) {
|
|
36531
|
-
killed = true;
|
|
36532
|
-
child.kill("SIGTERM");
|
|
36533
|
-
}
|
|
36534
|
-
}
|
|
36535
|
-
});
|
|
36536
|
-
child.on("close", (code, signal) => {
|
|
36537
|
-
if (timeoutHandle) {
|
|
36538
|
-
clearTimeout(timeoutHandle);
|
|
36539
|
-
}
|
|
36540
|
-
const duration = Date.now() - startTime;
|
|
36541
|
-
if (debug) {
|
|
36542
|
-
console.log(`[BashExecutor] Command completed - Code: ${code}, Signal: ${signal}, Duration: ${duration}ms`);
|
|
36543
|
-
console.log(`[BashExecutor] Stdout length: ${stdout.length}, Stderr length: ${stderr.length}`);
|
|
36544
|
-
}
|
|
36545
|
-
let success = true;
|
|
36546
|
-
let error2 = "";
|
|
36547
|
-
if (killed) {
|
|
36548
|
-
success = false;
|
|
36549
|
-
if (stdout.length + stderr.length > maxBuffer) {
|
|
36550
|
-
error2 = `Command output exceeded maximum buffer size (${maxBuffer} bytes)`;
|
|
36551
|
-
} else {
|
|
36552
|
-
error2 = `Command timed out after ${timeout}ms`;
|
|
35783
|
+
delegateTool = (options = {}) => {
|
|
35784
|
+
const { debug = false, timeout = 300, cwd, allowedFolders, enableBash = false, bashConfig } = options;
|
|
35785
|
+
return (0, import_ai2.tool)({
|
|
35786
|
+
name: "delegate",
|
|
35787
|
+
description: delegateDescription,
|
|
35788
|
+
inputSchema: delegateSchema,
|
|
35789
|
+
execute: async ({ task, currentIteration, maxIterations, parentSessionId, path: path9, provider, model, tracer }) => {
|
|
35790
|
+
if (!task || typeof task !== "string") {
|
|
35791
|
+
throw new Error("Task parameter is required and must be a non-empty string");
|
|
35792
|
+
}
|
|
35793
|
+
if (task.trim().length === 0) {
|
|
35794
|
+
throw new Error("Task parameter cannot be empty or whitespace only");
|
|
35795
|
+
}
|
|
35796
|
+
if (currentIteration !== void 0 && (typeof currentIteration !== "number" || currentIteration < 0)) {
|
|
35797
|
+
throw new Error("currentIteration must be a non-negative number");
|
|
35798
|
+
}
|
|
35799
|
+
if (maxIterations !== void 0 && (typeof maxIterations !== "number" || maxIterations < 1)) {
|
|
35800
|
+
throw new Error("maxIterations must be a positive number");
|
|
35801
|
+
}
|
|
35802
|
+
if (parentSessionId !== void 0 && parentSessionId !== null && typeof parentSessionId !== "string") {
|
|
35803
|
+
throw new TypeError("parentSessionId must be a string, null, or undefined");
|
|
35804
|
+
}
|
|
35805
|
+
if (path9 !== void 0 && path9 !== null && typeof path9 !== "string") {
|
|
35806
|
+
throw new TypeError("path must be a string, null, or undefined");
|
|
35807
|
+
}
|
|
35808
|
+
if (provider !== void 0 && provider !== null && typeof provider !== "string") {
|
|
35809
|
+
throw new TypeError("provider must be a string, null, or undefined");
|
|
35810
|
+
}
|
|
35811
|
+
if (model !== void 0 && model !== null && typeof model !== "string") {
|
|
35812
|
+
throw new TypeError("model must be a string, null, or undefined");
|
|
35813
|
+
}
|
|
35814
|
+
const workspaceRoot = allowedFolders && allowedFolders[0];
|
|
35815
|
+
const effectivePath = path9 || workspaceRoot || cwd;
|
|
35816
|
+
if (debug) {
|
|
35817
|
+
console.error(`Executing delegate with task: "${task.substring(0, 100)}${task.length > 100 ? "..." : ""}"`);
|
|
35818
|
+
if (parentSessionId) {
|
|
35819
|
+
console.error(`Parent session: ${parentSessionId}`);
|
|
35820
|
+
}
|
|
35821
|
+
if (effectivePath && effectivePath !== path9) {
|
|
35822
|
+
console.error(`Using workspace root: ${effectivePath} (cwd was: ${cwd || "not set"})`);
|
|
35823
|
+
}
|
|
35824
|
+
}
|
|
35825
|
+
const result = await delegate({
|
|
35826
|
+
task,
|
|
35827
|
+
timeout,
|
|
35828
|
+
debug,
|
|
35829
|
+
currentIteration: currentIteration || 0,
|
|
35830
|
+
maxIterations: maxIterations || 30,
|
|
35831
|
+
parentSessionId,
|
|
35832
|
+
path: effectivePath,
|
|
35833
|
+
provider,
|
|
35834
|
+
model,
|
|
35835
|
+
tracer,
|
|
35836
|
+
enableBash,
|
|
35837
|
+
bashConfig
|
|
35838
|
+
});
|
|
35839
|
+
return result;
|
|
36553
35840
|
}
|
|
36554
|
-
} else if (code !== 0) {
|
|
36555
|
-
success = false;
|
|
36556
|
-
error2 = `Command exited with code ${code}`;
|
|
36557
|
-
}
|
|
36558
|
-
resolve6({
|
|
36559
|
-
success,
|
|
36560
|
-
error: error2,
|
|
36561
|
-
stdout: stdout.trim(),
|
|
36562
|
-
stderr: stderr.trim(),
|
|
36563
|
-
exitCode: code,
|
|
36564
|
-
signal,
|
|
36565
|
-
command,
|
|
36566
|
-
workingDirectory: cwd,
|
|
36567
|
-
duration,
|
|
36568
|
-
killed
|
|
36569
|
-
});
|
|
36570
|
-
});
|
|
36571
|
-
child.on("error", (error2) => {
|
|
36572
|
-
if (timeoutHandle) {
|
|
36573
|
-
clearTimeout(timeoutHandle);
|
|
36574
|
-
}
|
|
36575
|
-
if (debug) {
|
|
36576
|
-
console.log(`[BashExecutor] Spawn error:`, error2);
|
|
36577
|
-
}
|
|
36578
|
-
resolve6({
|
|
36579
|
-
success: false,
|
|
36580
|
-
error: `Failed to execute command: ${error2.message}`,
|
|
36581
|
-
stdout: "",
|
|
36582
|
-
stderr: "",
|
|
36583
|
-
exitCode: 1,
|
|
36584
|
-
command,
|
|
36585
|
-
workingDirectory: cwd,
|
|
36586
|
-
duration: Date.now() - startTime
|
|
36587
35841
|
});
|
|
36588
|
-
}
|
|
36589
|
-
}
|
|
36590
|
-
}
|
|
36591
|
-
|
|
36592
|
-
|
|
36593
|
-
|
|
35842
|
+
};
|
|
35843
|
+
}
|
|
35844
|
+
});
|
|
35845
|
+
|
|
35846
|
+
// src/agent/bashDefaults.js
|
|
35847
|
+
var DEFAULT_ALLOW_PATTERNS, DEFAULT_DENY_PATTERNS;
|
|
35848
|
+
var init_bashDefaults = __esm({
|
|
35849
|
+
"src/agent/bashDefaults.js"() {
|
|
35850
|
+
"use strict";
|
|
35851
|
+
DEFAULT_ALLOW_PATTERNS = [
|
|
35852
|
+
// Basic navigation and listing
|
|
35853
|
+
"ls",
|
|
35854
|
+
"dir",
|
|
35855
|
+
"pwd",
|
|
35856
|
+
"cd",
|
|
35857
|
+
"cd:*",
|
|
35858
|
+
// File reading commands
|
|
35859
|
+
"cat",
|
|
35860
|
+
"cat:*",
|
|
35861
|
+
"head",
|
|
35862
|
+
"head:*",
|
|
35863
|
+
"tail",
|
|
35864
|
+
"tail:*",
|
|
35865
|
+
"less",
|
|
35866
|
+
"more",
|
|
35867
|
+
"view",
|
|
35868
|
+
// File information and metadata
|
|
35869
|
+
"file",
|
|
35870
|
+
"file:*",
|
|
35871
|
+
"stat",
|
|
35872
|
+
"stat:*",
|
|
35873
|
+
"wc",
|
|
35874
|
+
"wc:*",
|
|
35875
|
+
"du",
|
|
35876
|
+
"du:*",
|
|
35877
|
+
"df",
|
|
35878
|
+
"df:*",
|
|
35879
|
+
"realpath",
|
|
35880
|
+
"realpath:*",
|
|
35881
|
+
// Search and find commands (read-only) - find restricted to safe operations
|
|
35882
|
+
"find",
|
|
35883
|
+
"find:-name:*",
|
|
35884
|
+
"find:-type:*",
|
|
35885
|
+
"find:-size:*",
|
|
35886
|
+
"find:-mtime:*",
|
|
35887
|
+
"find:-newer:*",
|
|
35888
|
+
"find:-path:*",
|
|
35889
|
+
"find:-iname:*",
|
|
35890
|
+
"find:-maxdepth:*",
|
|
35891
|
+
"find:-mindepth:*",
|
|
35892
|
+
"find:-print",
|
|
35893
|
+
"grep",
|
|
35894
|
+
"grep:*",
|
|
35895
|
+
"egrep",
|
|
35896
|
+
"egrep:*",
|
|
35897
|
+
"fgrep",
|
|
35898
|
+
"fgrep:*",
|
|
35899
|
+
"rg",
|
|
35900
|
+
"rg:*",
|
|
35901
|
+
"ag",
|
|
35902
|
+
"ag:*",
|
|
35903
|
+
"ack",
|
|
35904
|
+
"ack:*",
|
|
35905
|
+
"which",
|
|
35906
|
+
"which:*",
|
|
35907
|
+
"whereis",
|
|
35908
|
+
"whereis:*",
|
|
35909
|
+
"locate",
|
|
35910
|
+
"locate:*",
|
|
35911
|
+
"type",
|
|
35912
|
+
"type:*",
|
|
35913
|
+
"command",
|
|
35914
|
+
"command:*",
|
|
35915
|
+
// Tree and structure visualization
|
|
35916
|
+
"tree",
|
|
35917
|
+
"tree:*",
|
|
35918
|
+
// Git read-only operations
|
|
35919
|
+
"git:status",
|
|
35920
|
+
"git:log",
|
|
35921
|
+
"git:log:*",
|
|
35922
|
+
"git:diff",
|
|
35923
|
+
"git:diff:*",
|
|
35924
|
+
"git:show",
|
|
35925
|
+
"git:show:*",
|
|
35926
|
+
"git:branch",
|
|
35927
|
+
"git:branch:*",
|
|
35928
|
+
"git:tag",
|
|
35929
|
+
"git:tag:*",
|
|
35930
|
+
"git:describe",
|
|
35931
|
+
"git:describe:*",
|
|
35932
|
+
"git:remote",
|
|
35933
|
+
"git:remote:*",
|
|
35934
|
+
"git:config:*",
|
|
35935
|
+
"git:blame",
|
|
35936
|
+
"git:blame:*",
|
|
35937
|
+
"git:shortlog",
|
|
35938
|
+
"git:reflog",
|
|
35939
|
+
"git:ls-files",
|
|
35940
|
+
"git:ls-tree",
|
|
35941
|
+
"git:rev-parse",
|
|
35942
|
+
"git:rev-list",
|
|
35943
|
+
"git:--version",
|
|
35944
|
+
"git:help",
|
|
35945
|
+
"git:help:*",
|
|
35946
|
+
// Package managers (information only)
|
|
35947
|
+
"npm:list",
|
|
35948
|
+
"npm:ls",
|
|
35949
|
+
"npm:view",
|
|
35950
|
+
"npm:info",
|
|
35951
|
+
"npm:show",
|
|
35952
|
+
"npm:outdated",
|
|
35953
|
+
"npm:audit",
|
|
35954
|
+
"npm:--version",
|
|
35955
|
+
"yarn:list",
|
|
35956
|
+
"yarn:info",
|
|
35957
|
+
"yarn:--version",
|
|
35958
|
+
"pnpm:list",
|
|
35959
|
+
"pnpm:--version",
|
|
35960
|
+
"pip:list",
|
|
35961
|
+
"pip:show",
|
|
35962
|
+
"pip:--version",
|
|
35963
|
+
"pip3:list",
|
|
35964
|
+
"pip3:show",
|
|
35965
|
+
"pip3:--version",
|
|
35966
|
+
"gem:list",
|
|
35967
|
+
"gem:--version",
|
|
35968
|
+
"bundle:list",
|
|
35969
|
+
"bundle:show",
|
|
35970
|
+
"bundle:--version",
|
|
35971
|
+
"composer:show",
|
|
35972
|
+
"composer:--version",
|
|
35973
|
+
// Language and runtime versions
|
|
35974
|
+
"node:--version",
|
|
35975
|
+
"node:-v",
|
|
35976
|
+
"python:--version",
|
|
35977
|
+
"python:-V",
|
|
35978
|
+
"python3:--version",
|
|
35979
|
+
"python3:-V",
|
|
35980
|
+
"ruby:--version",
|
|
35981
|
+
"ruby:-v",
|
|
35982
|
+
"go:version",
|
|
35983
|
+
"go:env",
|
|
35984
|
+
"go:list",
|
|
35985
|
+
"go:mod:graph",
|
|
35986
|
+
"rustc:--version",
|
|
35987
|
+
"cargo:--version",
|
|
35988
|
+
"cargo:tree",
|
|
35989
|
+
"cargo:metadata",
|
|
35990
|
+
"java:--version",
|
|
35991
|
+
"java:-version",
|
|
35992
|
+
"javac:--version",
|
|
35993
|
+
"mvn:--version",
|
|
35994
|
+
"gradle:--version",
|
|
35995
|
+
"php:--version",
|
|
35996
|
+
"dotnet:--version",
|
|
35997
|
+
"dotnet:list",
|
|
35998
|
+
// Database client versions (connection info only)
|
|
35999
|
+
"psql:--version",
|
|
36000
|
+
"mysql:--version",
|
|
36001
|
+
"redis-cli:--version",
|
|
36002
|
+
"mongo:--version",
|
|
36003
|
+
"sqlite3:--version",
|
|
36004
|
+
// System information
|
|
36005
|
+
"uname",
|
|
36006
|
+
"uname:*",
|
|
36007
|
+
"hostname",
|
|
36008
|
+
"whoami",
|
|
36009
|
+
"id",
|
|
36010
|
+
"groups",
|
|
36011
|
+
"date",
|
|
36012
|
+
"cal",
|
|
36013
|
+
"uptime",
|
|
36014
|
+
"w",
|
|
36015
|
+
"users",
|
|
36016
|
+
"sleep",
|
|
36017
|
+
"sleep:*",
|
|
36018
|
+
// Environment and shell
|
|
36019
|
+
"env",
|
|
36020
|
+
"printenv",
|
|
36021
|
+
"echo",
|
|
36022
|
+
"echo:*",
|
|
36023
|
+
"printf",
|
|
36024
|
+
"printf:*",
|
|
36025
|
+
"export",
|
|
36026
|
+
"export:*",
|
|
36027
|
+
"set",
|
|
36028
|
+
"unset",
|
|
36029
|
+
// Process information (read-only)
|
|
36030
|
+
"ps",
|
|
36031
|
+
"ps:*",
|
|
36032
|
+
"pgrep",
|
|
36033
|
+
"pgrep:*",
|
|
36034
|
+
"jobs",
|
|
36035
|
+
"top:-n:1",
|
|
36036
|
+
// Network information (read-only)
|
|
36037
|
+
"ifconfig",
|
|
36038
|
+
"ip:addr",
|
|
36039
|
+
"ip:link",
|
|
36040
|
+
"hostname:-I",
|
|
36041
|
+
"ping:-c:*",
|
|
36042
|
+
"traceroute",
|
|
36043
|
+
"nslookup",
|
|
36044
|
+
"dig",
|
|
36045
|
+
// Text processing and utilities (awk removed - too powerful)
|
|
36046
|
+
"sed:-n:*",
|
|
36047
|
+
"cut",
|
|
36048
|
+
"cut:*",
|
|
36049
|
+
"sort",
|
|
36050
|
+
"sort:*",
|
|
36051
|
+
"uniq",
|
|
36052
|
+
"uniq:*",
|
|
36053
|
+
"tr",
|
|
36054
|
+
"tr:*",
|
|
36055
|
+
"column",
|
|
36056
|
+
"column:*",
|
|
36057
|
+
"paste",
|
|
36058
|
+
"paste:*",
|
|
36059
|
+
"join",
|
|
36060
|
+
"join:*",
|
|
36061
|
+
"comm",
|
|
36062
|
+
"comm:*",
|
|
36063
|
+
"diff",
|
|
36064
|
+
"diff:*",
|
|
36065
|
+
"cmp",
|
|
36066
|
+
"cmp:*",
|
|
36067
|
+
"patch:--dry-run:*",
|
|
36068
|
+
// Hashing and encoding (read-only)
|
|
36069
|
+
"md5sum",
|
|
36070
|
+
"md5sum:*",
|
|
36071
|
+
"sha1sum",
|
|
36072
|
+
"sha1sum:*",
|
|
36073
|
+
"sha256sum",
|
|
36074
|
+
"sha256sum:*",
|
|
36075
|
+
"base64",
|
|
36076
|
+
"base64:-d",
|
|
36077
|
+
"od",
|
|
36078
|
+
"od:*",
|
|
36079
|
+
"hexdump",
|
|
36080
|
+
"hexdump:*",
|
|
36081
|
+
// Archive and compression (list/view only)
|
|
36082
|
+
"tar:-tf:*",
|
|
36083
|
+
"tar:-tzf:*",
|
|
36084
|
+
"unzip:-l:*",
|
|
36085
|
+
"zip:-l:*",
|
|
36086
|
+
"gzip:-l:*",
|
|
36087
|
+
"gunzip:-l:*",
|
|
36088
|
+
// Help and documentation
|
|
36089
|
+
"man",
|
|
36090
|
+
"man:*",
|
|
36091
|
+
"--help",
|
|
36092
|
+
"help",
|
|
36093
|
+
"info",
|
|
36094
|
+
"info:*",
|
|
36095
|
+
"whatis",
|
|
36096
|
+
"whatis:*",
|
|
36097
|
+
"apropos",
|
|
36098
|
+
"apropos:*",
|
|
36099
|
+
// Make (dry run and info)
|
|
36100
|
+
"make:-n",
|
|
36101
|
+
"make:--dry-run",
|
|
36102
|
+
"make:-p",
|
|
36103
|
+
"make:--print-data-base",
|
|
36104
|
+
// Docker (read-only operations)
|
|
36105
|
+
"docker:ps",
|
|
36106
|
+
"docker:images",
|
|
36107
|
+
"docker:version",
|
|
36108
|
+
"docker:info",
|
|
36109
|
+
"docker:logs:*",
|
|
36110
|
+
"docker:inspect:*",
|
|
36111
|
+
// Test runners (list/info only)
|
|
36112
|
+
"jest:--listTests",
|
|
36113
|
+
"mocha:--help",
|
|
36114
|
+
"pytest:--collect-only"
|
|
36115
|
+
];
|
|
36116
|
+
DEFAULT_DENY_PATTERNS = [
|
|
36117
|
+
// Dangerous file operations
|
|
36118
|
+
"rm:-rf",
|
|
36119
|
+
"rm:-f:/",
|
|
36120
|
+
"rm:/",
|
|
36121
|
+
"rm:-rf:*",
|
|
36122
|
+
"rmdir",
|
|
36123
|
+
"chmod:777",
|
|
36124
|
+
"chmod:-R:777",
|
|
36125
|
+
"chown",
|
|
36126
|
+
"chgrp",
|
|
36127
|
+
"dd",
|
|
36128
|
+
"dd:*",
|
|
36129
|
+
"shred",
|
|
36130
|
+
"shred:*",
|
|
36131
|
+
// Dangerous find operations that can execute arbitrary commands
|
|
36132
|
+
"find:-exec:*",
|
|
36133
|
+
"find:*:-exec:*",
|
|
36134
|
+
"find:-execdir:*",
|
|
36135
|
+
"find:*:-execdir:*",
|
|
36136
|
+
"find:-ok:*",
|
|
36137
|
+
"find:*:-ok:*",
|
|
36138
|
+
"find:-okdir:*",
|
|
36139
|
+
"find:*:-okdir:*",
|
|
36140
|
+
// Powerful scripting tools that can execute arbitrary commands
|
|
36141
|
+
"awk",
|
|
36142
|
+
"awk:*",
|
|
36143
|
+
"perl",
|
|
36144
|
+
"perl:*",
|
|
36145
|
+
"python:-c:*",
|
|
36146
|
+
"node:-e:*",
|
|
36147
|
+
// System administration and modification
|
|
36148
|
+
"sudo:*",
|
|
36149
|
+
"su",
|
|
36150
|
+
"su:*",
|
|
36151
|
+
"passwd",
|
|
36152
|
+
"adduser",
|
|
36153
|
+
"useradd",
|
|
36154
|
+
"userdel",
|
|
36155
|
+
"usermod",
|
|
36156
|
+
"groupadd",
|
|
36157
|
+
"groupdel",
|
|
36158
|
+
"visudo",
|
|
36159
|
+
// Package installation and removal
|
|
36160
|
+
"npm:install",
|
|
36161
|
+
"npm:i",
|
|
36162
|
+
"npm:uninstall",
|
|
36163
|
+
"npm:publish",
|
|
36164
|
+
"npm:unpublish",
|
|
36165
|
+
"npm:link",
|
|
36166
|
+
"npm:update",
|
|
36167
|
+
"yarn:install",
|
|
36168
|
+
"yarn:add",
|
|
36169
|
+
"yarn:remove",
|
|
36170
|
+
"yarn:upgrade",
|
|
36171
|
+
"pnpm:install",
|
|
36172
|
+
"pnpm:add",
|
|
36173
|
+
"pnpm:remove",
|
|
36174
|
+
"pip:install",
|
|
36175
|
+
"pip:uninstall",
|
|
36176
|
+
"pip:upgrade",
|
|
36177
|
+
"pip3:install",
|
|
36178
|
+
"pip3:uninstall",
|
|
36179
|
+
"pip3:upgrade",
|
|
36180
|
+
"gem:install",
|
|
36181
|
+
"gem:uninstall",
|
|
36182
|
+
"gem:update",
|
|
36183
|
+
"bundle:install",
|
|
36184
|
+
"bundle:update",
|
|
36185
|
+
"composer:install",
|
|
36186
|
+
"composer:update",
|
|
36187
|
+
"composer:remove",
|
|
36188
|
+
"apt:*",
|
|
36189
|
+
"apt-get:*",
|
|
36190
|
+
"yum:*",
|
|
36191
|
+
"dnf:*",
|
|
36192
|
+
"zypper:*",
|
|
36193
|
+
"brew:install",
|
|
36194
|
+
"brew:uninstall",
|
|
36195
|
+
"brew:upgrade",
|
|
36196
|
+
"conda:install",
|
|
36197
|
+
"conda:remove",
|
|
36198
|
+
"conda:update",
|
|
36199
|
+
// Service and system control
|
|
36200
|
+
"systemctl:*",
|
|
36201
|
+
"service:*",
|
|
36202
|
+
"chkconfig:*",
|
|
36203
|
+
"initctl:*",
|
|
36204
|
+
"upstart:*",
|
|
36205
|
+
// Network operations that could be dangerous
|
|
36206
|
+
"curl:-d:*",
|
|
36207
|
+
"curl:--data:*",
|
|
36208
|
+
"curl:-X:POST:*",
|
|
36209
|
+
"curl:-X:PUT:*",
|
|
36210
|
+
"wget:-O:/",
|
|
36211
|
+
"wget:--post-data:*",
|
|
36212
|
+
"ssh",
|
|
36213
|
+
"ssh:*",
|
|
36214
|
+
"scp",
|
|
36215
|
+
"scp:*",
|
|
36216
|
+
"sftp",
|
|
36217
|
+
"sftp:*",
|
|
36218
|
+
"rsync:*",
|
|
36219
|
+
"nc",
|
|
36220
|
+
"nc:*",
|
|
36221
|
+
"netcat",
|
|
36222
|
+
"netcat:*",
|
|
36223
|
+
"telnet",
|
|
36224
|
+
"telnet:*",
|
|
36225
|
+
"ftp",
|
|
36226
|
+
"ftp:*",
|
|
36227
|
+
// Process control and termination
|
|
36228
|
+
"kill",
|
|
36229
|
+
"kill:*",
|
|
36230
|
+
"killall",
|
|
36231
|
+
"killall:*",
|
|
36232
|
+
"pkill",
|
|
36233
|
+
"pkill:*",
|
|
36234
|
+
"nohup:*",
|
|
36235
|
+
"disown:*",
|
|
36236
|
+
// System control and shutdown
|
|
36237
|
+
"shutdown",
|
|
36238
|
+
"shutdown:*",
|
|
36239
|
+
"reboot",
|
|
36240
|
+
"halt",
|
|
36241
|
+
"poweroff",
|
|
36242
|
+
"init",
|
|
36243
|
+
"telinit",
|
|
36244
|
+
// Kernel and module operations
|
|
36245
|
+
"insmod",
|
|
36246
|
+
"insmod:*",
|
|
36247
|
+
"rmmod",
|
|
36248
|
+
"rmmod:*",
|
|
36249
|
+
"modprobe",
|
|
36250
|
+
"modprobe:*",
|
|
36251
|
+
"sysctl:-w:*",
|
|
36252
|
+
// Dangerous git operations
|
|
36253
|
+
"git:push",
|
|
36254
|
+
"git:push:*",
|
|
36255
|
+
"git:force",
|
|
36256
|
+
"git:reset:--hard:*",
|
|
36257
|
+
"git:clean:-fd",
|
|
36258
|
+
"git:rm:*",
|
|
36259
|
+
"git:commit",
|
|
36260
|
+
"git:merge",
|
|
36261
|
+
"git:rebase",
|
|
36262
|
+
"git:cherry-pick",
|
|
36263
|
+
"git:stash:drop",
|
|
36264
|
+
// File system mounting and partitioning
|
|
36265
|
+
"mount",
|
|
36266
|
+
"mount:*",
|
|
36267
|
+
"umount",
|
|
36268
|
+
"umount:*",
|
|
36269
|
+
"fdisk",
|
|
36270
|
+
"fdisk:*",
|
|
36271
|
+
"parted",
|
|
36272
|
+
"parted:*",
|
|
36273
|
+
"mkfs",
|
|
36274
|
+
"mkfs:*",
|
|
36275
|
+
"fsck",
|
|
36276
|
+
"fsck:*",
|
|
36277
|
+
// Cron and scheduling
|
|
36278
|
+
"crontab",
|
|
36279
|
+
"crontab:*",
|
|
36280
|
+
"at",
|
|
36281
|
+
"at:*",
|
|
36282
|
+
"batch",
|
|
36283
|
+
"batch:*",
|
|
36284
|
+
// Compression with potential overwrite
|
|
36285
|
+
"tar:-xf:*",
|
|
36286
|
+
"unzip",
|
|
36287
|
+
"unzip:*",
|
|
36288
|
+
"gzip:*",
|
|
36289
|
+
"gunzip:*",
|
|
36290
|
+
// Build and compilation that might modify files
|
|
36291
|
+
"make",
|
|
36292
|
+
"make:install",
|
|
36293
|
+
"make:clean",
|
|
36294
|
+
"cargo:build",
|
|
36295
|
+
"cargo:install",
|
|
36296
|
+
"npm:run:build",
|
|
36297
|
+
"yarn:build",
|
|
36298
|
+
"mvn:install",
|
|
36299
|
+
"gradle:build",
|
|
36300
|
+
// Docker operations that could modify state
|
|
36301
|
+
"docker:run",
|
|
36302
|
+
"docker:run:*",
|
|
36303
|
+
"docker:exec",
|
|
36304
|
+
"docker:exec:*",
|
|
36305
|
+
"docker:build",
|
|
36306
|
+
"docker:build:*",
|
|
36307
|
+
"docker:pull",
|
|
36308
|
+
"docker:push",
|
|
36309
|
+
"docker:rm",
|
|
36310
|
+
"docker:rmi",
|
|
36311
|
+
"docker:stop",
|
|
36312
|
+
"docker:start",
|
|
36313
|
+
// Database operations
|
|
36314
|
+
"mysql:-e:DROP",
|
|
36315
|
+
"psql:-c:DROP",
|
|
36316
|
+
"redis-cli:FLUSHALL",
|
|
36317
|
+
"mongo:--eval:*",
|
|
36318
|
+
// Text editors that could modify files
|
|
36319
|
+
"vi",
|
|
36320
|
+
"vi:*",
|
|
36321
|
+
"vim",
|
|
36322
|
+
"vim:*",
|
|
36323
|
+
"nano",
|
|
36324
|
+
"nano:*",
|
|
36325
|
+
"emacs",
|
|
36326
|
+
"emacs:*",
|
|
36327
|
+
"sed:-i:*",
|
|
36328
|
+
"perl:-i:*",
|
|
36329
|
+
// Potentially dangerous utilities
|
|
36330
|
+
"eval",
|
|
36331
|
+
"eval:*",
|
|
36332
|
+
"exec",
|
|
36333
|
+
"exec:*",
|
|
36334
|
+
"source",
|
|
36335
|
+
"source:*",
|
|
36336
|
+
"bash:-c:*",
|
|
36337
|
+
"sh:-c:*",
|
|
36338
|
+
"zsh:-c:*"
|
|
36339
|
+
];
|
|
36594
36340
|
}
|
|
36595
|
-
|
|
36596
|
-
|
|
36597
|
-
|
|
36598
|
-
|
|
36599
|
-
|
|
36600
|
-
|
|
36601
|
-
|
|
36602
|
-
|
|
36603
|
-
|
|
36604
|
-
|
|
36605
|
-
|
|
36606
|
-
|
|
36607
|
-
|
|
36341
|
+
});
|
|
36342
|
+
|
|
36343
|
+
// src/agent/bashCommandUtils.js
|
|
36344
|
+
function parseSimpleCommand(command) {
|
|
36345
|
+
if (!command || typeof command !== "string") {
|
|
36346
|
+
return {
|
|
36347
|
+
success: false,
|
|
36348
|
+
error: "Command must be a non-empty string",
|
|
36349
|
+
command: null,
|
|
36350
|
+
args: [],
|
|
36351
|
+
isComplex: false
|
|
36352
|
+
};
|
|
36353
|
+
}
|
|
36354
|
+
const trimmed = command.trim();
|
|
36355
|
+
if (!trimmed) {
|
|
36356
|
+
return {
|
|
36357
|
+
success: false,
|
|
36358
|
+
error: "Command cannot be empty",
|
|
36359
|
+
command: null,
|
|
36360
|
+
args: [],
|
|
36361
|
+
isComplex: false
|
|
36362
|
+
};
|
|
36363
|
+
}
|
|
36364
|
+
const complexPatterns = [
|
|
36365
|
+
/\|/,
|
|
36366
|
+
// Pipes
|
|
36367
|
+
/&&/,
|
|
36368
|
+
// Logical AND
|
|
36369
|
+
/\|\|/,
|
|
36370
|
+
// Logical OR
|
|
36371
|
+
/(?<!\\);/,
|
|
36372
|
+
// Command separator (but not escaped \;)
|
|
36373
|
+
/&$/,
|
|
36374
|
+
// Background execution
|
|
36375
|
+
/\$\(/,
|
|
36376
|
+
// Command substitution $()
|
|
36377
|
+
/`/,
|
|
36378
|
+
// Command substitution ``
|
|
36379
|
+
/>/,
|
|
36380
|
+
// Redirection >
|
|
36381
|
+
/</,
|
|
36382
|
+
// Redirection <
|
|
36383
|
+
/\*\*/,
|
|
36384
|
+
// Glob patterns (potentially dangerous)
|
|
36385
|
+
/^\s*\{.*,.*\}|\{.*\.\.\.*\}/
|
|
36386
|
+
// Brace expansion like {a,b} or {1..10} (but not find {} placeholders)
|
|
36387
|
+
];
|
|
36388
|
+
for (const pattern of complexPatterns) {
|
|
36389
|
+
if (pattern.test(trimmed)) {
|
|
36390
|
+
return {
|
|
36391
|
+
success: false,
|
|
36392
|
+
error: "Complex shell commands with pipes, operators, or redirections are not supported for security reasons",
|
|
36393
|
+
command: null,
|
|
36394
|
+
args: [],
|
|
36395
|
+
isComplex: true,
|
|
36396
|
+
detected: pattern.toString()
|
|
36397
|
+
};
|
|
36608
36398
|
}
|
|
36609
|
-
output += "\n";
|
|
36610
36399
|
}
|
|
36611
|
-
|
|
36612
|
-
|
|
36613
|
-
|
|
36400
|
+
const args = [];
|
|
36401
|
+
let current = "";
|
|
36402
|
+
let inQuotes = false;
|
|
36403
|
+
let quoteChar = "";
|
|
36404
|
+
let escaped = false;
|
|
36405
|
+
for (let i4 = 0; i4 < trimmed.length; i4++) {
|
|
36406
|
+
const char = trimmed[i4];
|
|
36407
|
+
const nextChar = i4 + 1 < trimmed.length ? trimmed[i4 + 1] : "";
|
|
36408
|
+
if (escaped) {
|
|
36409
|
+
current += char;
|
|
36410
|
+
escaped = false;
|
|
36411
|
+
continue;
|
|
36614
36412
|
}
|
|
36615
|
-
|
|
36616
|
-
|
|
36617
|
-
|
|
36413
|
+
if (char === "\\" && !inQuotes) {
|
|
36414
|
+
escaped = true;
|
|
36415
|
+
continue;
|
|
36618
36416
|
}
|
|
36619
|
-
|
|
36620
|
-
|
|
36621
|
-
|
|
36622
|
-
|
|
36623
|
-
|
|
36624
|
-
|
|
36625
|
-
|
|
36417
|
+
if (!inQuotes && (char === '"' || char === "'")) {
|
|
36418
|
+
inQuotes = true;
|
|
36419
|
+
quoteChar = char;
|
|
36420
|
+
} else if (inQuotes && char === quoteChar) {
|
|
36421
|
+
inQuotes = false;
|
|
36422
|
+
quoteChar = "";
|
|
36423
|
+
} else if (!inQuotes && char === " ") {
|
|
36424
|
+
if (current.trim()) {
|
|
36425
|
+
args.push(current.trim());
|
|
36426
|
+
current = "";
|
|
36427
|
+
}
|
|
36428
|
+
} else {
|
|
36429
|
+
current += char;
|
|
36626
36430
|
}
|
|
36627
|
-
output += result.stderr;
|
|
36628
36431
|
}
|
|
36629
|
-
if (
|
|
36630
|
-
|
|
36631
|
-
output += `Error: ${result.error}`;
|
|
36432
|
+
if (current.trim()) {
|
|
36433
|
+
args.push(current.trim());
|
|
36632
36434
|
}
|
|
36633
|
-
if (
|
|
36634
|
-
|
|
36635
|
-
|
|
36435
|
+
if (inQuotes) {
|
|
36436
|
+
return {
|
|
36437
|
+
success: false,
|
|
36438
|
+
error: `Unclosed quote in command: ${quoteChar}`,
|
|
36439
|
+
command: null,
|
|
36440
|
+
args: [],
|
|
36441
|
+
isComplex: false
|
|
36442
|
+
};
|
|
36443
|
+
}
|
|
36444
|
+
if (args.length === 0) {
|
|
36445
|
+
return {
|
|
36446
|
+
success: false,
|
|
36447
|
+
error: "No command found after parsing",
|
|
36448
|
+
command: null,
|
|
36449
|
+
args: [],
|
|
36450
|
+
isComplex: false
|
|
36451
|
+
};
|
|
36452
|
+
}
|
|
36453
|
+
const [baseCommand, ...commandArgs] = args;
|
|
36454
|
+
return {
|
|
36455
|
+
success: true,
|
|
36456
|
+
error: null,
|
|
36457
|
+
command: baseCommand,
|
|
36458
|
+
args: commandArgs,
|
|
36459
|
+
fullArgs: args,
|
|
36460
|
+
isComplex: false,
|
|
36461
|
+
original: command
|
|
36462
|
+
};
|
|
36463
|
+
}
|
|
36464
|
+
function isComplexCommand(command) {
|
|
36465
|
+
const result = parseSimpleCommand(command);
|
|
36466
|
+
return result.isComplex;
|
|
36467
|
+
}
|
|
36468
|
+
function isComplexPattern(pattern) {
|
|
36469
|
+
if (!pattern || typeof pattern !== "string") return false;
|
|
36470
|
+
const operatorPatterns = [
|
|
36471
|
+
/\|/,
|
|
36472
|
+
// Pipes
|
|
36473
|
+
/&&/,
|
|
36474
|
+
// Logical AND
|
|
36475
|
+
/\|\|/,
|
|
36476
|
+
// Logical OR
|
|
36477
|
+
/;/,
|
|
36478
|
+
// Command separator
|
|
36479
|
+
/&$/,
|
|
36480
|
+
// Background execution
|
|
36481
|
+
/\$\(/,
|
|
36482
|
+
// Command substitution $()
|
|
36483
|
+
/`/,
|
|
36484
|
+
// Command substitution ``
|
|
36485
|
+
/>/,
|
|
36486
|
+
// Redirection >
|
|
36487
|
+
/</
|
|
36488
|
+
// Redirection <
|
|
36489
|
+
];
|
|
36490
|
+
return operatorPatterns.some((p4) => p4.test(pattern));
|
|
36491
|
+
}
|
|
36492
|
+
function globToRegex(pattern) {
|
|
36493
|
+
let escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
|
|
36494
|
+
escaped = escaped.replace(/\*/g, ".*?");
|
|
36495
|
+
return new RegExp("^" + escaped + "$", "i");
|
|
36496
|
+
}
|
|
36497
|
+
function matchesComplexPattern(command, pattern) {
|
|
36498
|
+
if (!command || !pattern) return false;
|
|
36499
|
+
const normalizedCommand = command.trim().replace(/\s+/g, " ");
|
|
36500
|
+
const normalizedPattern = pattern.trim().replace(/\s+/g, " ");
|
|
36501
|
+
try {
|
|
36502
|
+
const regex = globToRegex(normalizedPattern);
|
|
36503
|
+
return regex.test(normalizedCommand);
|
|
36504
|
+
} catch (e4) {
|
|
36505
|
+
return normalizedCommand === normalizedPattern;
|
|
36636
36506
|
}
|
|
36637
|
-
return output || (result.success ? "Command completed successfully (no output)" : "Command failed (no output)");
|
|
36638
36507
|
}
|
|
36639
|
-
function
|
|
36640
|
-
const
|
|
36641
|
-
|
|
36642
|
-
|
|
36643
|
-
|
|
36644
|
-
|
|
36645
|
-
|
|
36646
|
-
|
|
36647
|
-
}
|
|
36648
|
-
}
|
|
36649
|
-
if (options.maxBuffer !== void 0) {
|
|
36650
|
-
if (typeof options.maxBuffer !== "number" || options.maxBuffer < 1024) {
|
|
36651
|
-
errors.push("maxBuffer must be at least 1024 bytes");
|
|
36652
|
-
} else if (options.maxBuffer > 100 * 1024 * 1024) {
|
|
36653
|
-
warnings.push("maxBuffer is very high (>100MB)");
|
|
36654
|
-
}
|
|
36655
|
-
}
|
|
36656
|
-
if (options.workingDirectory) {
|
|
36657
|
-
if (typeof options.workingDirectory !== "string") {
|
|
36658
|
-
errors.push("workingDirectory must be a string");
|
|
36659
|
-
} else if (!(0, import_fs4.existsSync)(options.workingDirectory)) {
|
|
36660
|
-
errors.push(`workingDirectory does not exist: ${options.workingDirectory}`);
|
|
36661
|
-
}
|
|
36662
|
-
}
|
|
36663
|
-
if (options.env && typeof options.env !== "object") {
|
|
36664
|
-
errors.push("env must be an object");
|
|
36508
|
+
function parseCommand(command) {
|
|
36509
|
+
const result = parseSimpleCommand(command);
|
|
36510
|
+
if (!result.success) {
|
|
36511
|
+
return {
|
|
36512
|
+
command: "",
|
|
36513
|
+
args: [],
|
|
36514
|
+
error: result.error,
|
|
36515
|
+
isComplex: result.isComplex
|
|
36516
|
+
};
|
|
36665
36517
|
}
|
|
36666
36518
|
return {
|
|
36667
|
-
|
|
36668
|
-
|
|
36669
|
-
|
|
36519
|
+
command: result.command,
|
|
36520
|
+
args: result.args,
|
|
36521
|
+
error: null,
|
|
36522
|
+
isComplex: result.isComplex
|
|
36670
36523
|
};
|
|
36671
36524
|
}
|
|
36672
|
-
|
|
36673
|
-
|
|
36674
|
-
|
|
36525
|
+
function parseCommandForExecution(command) {
|
|
36526
|
+
const result = parseSimpleCommand(command);
|
|
36527
|
+
if (!result.success) {
|
|
36528
|
+
return null;
|
|
36529
|
+
}
|
|
36530
|
+
return result.fullArgs;
|
|
36531
|
+
}
|
|
36532
|
+
var init_bashCommandUtils = __esm({
|
|
36533
|
+
"src/agent/bashCommandUtils.js"() {
|
|
36675
36534
|
"use strict";
|
|
36676
|
-
import_child_process6 = require("child_process");
|
|
36677
|
-
import_path6 = require("path");
|
|
36678
|
-
import_fs4 = require("fs");
|
|
36679
|
-
init_bashCommandUtils();
|
|
36680
36535
|
}
|
|
36681
36536
|
});
|
|
36682
36537
|
|
|
36683
|
-
// src/
|
|
36684
|
-
|
|
36685
|
-
|
|
36686
|
-
|
|
36538
|
+
// src/agent/bashPermissions.js
|
|
36539
|
+
function matchesPattern(parsedCommand, pattern) {
|
|
36540
|
+
if (!parsedCommand || !pattern) return false;
|
|
36541
|
+
const { command, args } = parsedCommand;
|
|
36542
|
+
if (!command) return false;
|
|
36543
|
+
const patternParts = pattern.split(":");
|
|
36544
|
+
const commandName = patternParts[0];
|
|
36545
|
+
if (commandName === "*") {
|
|
36546
|
+
return true;
|
|
36547
|
+
} else if (commandName !== command) {
|
|
36548
|
+
return false;
|
|
36549
|
+
}
|
|
36550
|
+
if (patternParts.length === 1) {
|
|
36551
|
+
return true;
|
|
36552
|
+
}
|
|
36553
|
+
for (let i4 = 1; i4 < patternParts.length; i4++) {
|
|
36554
|
+
const patternArg = patternParts[i4];
|
|
36555
|
+
const argIndex = i4 - 1;
|
|
36556
|
+
if (patternArg === "*") {
|
|
36557
|
+
continue;
|
|
36558
|
+
}
|
|
36559
|
+
if (argIndex >= args.length) {
|
|
36560
|
+
return false;
|
|
36561
|
+
}
|
|
36562
|
+
const actualArg = args[argIndex];
|
|
36563
|
+
if (patternArg !== actualArg) {
|
|
36564
|
+
return false;
|
|
36565
|
+
}
|
|
36566
|
+
}
|
|
36567
|
+
return true;
|
|
36568
|
+
}
|
|
36569
|
+
function matchesAnyPattern(parsedCommand, patterns) {
|
|
36570
|
+
if (!patterns || patterns.length === 0) return false;
|
|
36571
|
+
return patterns.some((pattern) => matchesPattern(parsedCommand, pattern));
|
|
36572
|
+
}
|
|
36573
|
+
var BashPermissionChecker;
|
|
36574
|
+
var init_bashPermissions = __esm({
|
|
36575
|
+
"src/agent/bashPermissions.js"() {
|
|
36687
36576
|
"use strict";
|
|
36688
|
-
|
|
36689
|
-
|
|
36690
|
-
|
|
36691
|
-
|
|
36692
|
-
|
|
36693
|
-
|
|
36694
|
-
|
|
36695
|
-
|
|
36696
|
-
|
|
36697
|
-
|
|
36698
|
-
|
|
36699
|
-
|
|
36700
|
-
|
|
36701
|
-
|
|
36702
|
-
|
|
36703
|
-
|
|
36704
|
-
|
|
36705
|
-
|
|
36706
|
-
|
|
36707
|
-
|
|
36708
|
-
return bashConfig.workingDirectory;
|
|
36577
|
+
init_bashDefaults();
|
|
36578
|
+
init_bashCommandUtils();
|
|
36579
|
+
BashPermissionChecker = class {
|
|
36580
|
+
/**
|
|
36581
|
+
* Create a permission checker
|
|
36582
|
+
* @param {Object} config - Configuration options
|
|
36583
|
+
* @param {string[]} [config.allow] - Additional allow patterns
|
|
36584
|
+
* @param {string[]} [config.deny] - Additional deny patterns
|
|
36585
|
+
* @param {boolean} [config.disableDefaultAllow] - Disable default allow list
|
|
36586
|
+
* @param {boolean} [config.disableDefaultDeny] - Disable default deny list
|
|
36587
|
+
* @param {boolean} [config.debug] - Enable debug logging
|
|
36588
|
+
*/
|
|
36589
|
+
constructor(config = {}) {
|
|
36590
|
+
this.debug = config.debug || false;
|
|
36591
|
+
this.allowPatterns = [];
|
|
36592
|
+
if (!config.disableDefaultAllow) {
|
|
36593
|
+
this.allowPatterns.push(...DEFAULT_ALLOW_PATTERNS);
|
|
36594
|
+
if (this.debug) {
|
|
36595
|
+
console.log(`[BashPermissions] Added ${DEFAULT_ALLOW_PATTERNS.length} default allow patterns`);
|
|
36596
|
+
}
|
|
36709
36597
|
}
|
|
36710
|
-
if (
|
|
36711
|
-
|
|
36598
|
+
if (config.allow && Array.isArray(config.allow)) {
|
|
36599
|
+
this.allowPatterns.push(...config.allow);
|
|
36600
|
+
if (this.debug) {
|
|
36601
|
+
console.log(`[BashPermissions] Added ${config.allow.length} custom allow patterns:`, config.allow);
|
|
36602
|
+
}
|
|
36712
36603
|
}
|
|
36713
|
-
|
|
36714
|
-
|
|
36604
|
+
this.denyPatterns = [];
|
|
36605
|
+
if (!config.disableDefaultDeny) {
|
|
36606
|
+
this.denyPatterns.push(...DEFAULT_DENY_PATTERNS);
|
|
36607
|
+
if (this.debug) {
|
|
36608
|
+
console.log(`[BashPermissions] Added ${DEFAULT_DENY_PATTERNS.length} default deny patterns`);
|
|
36609
|
+
}
|
|
36715
36610
|
}
|
|
36716
|
-
|
|
36717
|
-
|
|
36718
|
-
|
|
36719
|
-
|
|
36720
|
-
|
|
36721
|
-
|
|
36722
|
-
|
|
36723
|
-
|
|
36724
|
-
|
|
36725
|
-
|
|
36726
|
-
|
|
36727
|
-
|
|
36728
|
-
|
|
36729
|
-
|
|
36730
|
-
|
|
36731
|
-
|
|
36732
|
-
|
|
36733
|
-
|
|
36734
|
-
|
|
36735
|
-
|
|
36736
|
-
|
|
36737
|
-
|
|
36738
|
-
|
|
36739
|
-
|
|
36740
|
-
|
|
36741
|
-
|
|
36742
|
-
|
|
36743
|
-
|
|
36744
|
-
|
|
36745
|
-
|
|
36746
|
-
|
|
36747
|
-
|
|
36748
|
-
|
|
36749
|
-
|
|
36750
|
-
|
|
36751
|
-
|
|
36752
|
-
|
|
36753
|
-
|
|
36754
|
-
|
|
36755
|
-
|
|
36756
|
-
|
|
36757
|
-
|
|
36758
|
-
|
|
36759
|
-
|
|
36760
|
-
|
|
36761
|
-
|
|
36762
|
-
|
|
36763
|
-
|
|
36764
|
-
|
|
36765
|
-
|
|
36766
|
-
|
|
36767
|
-
|
|
36768
|
-
|
|
36769
|
-
|
|
36770
|
-
|
|
36771
|
-
|
|
36772
|
-
|
|
36773
|
-
|
|
36774
|
-
|
|
36775
|
-
|
|
36776
|
-
|
|
36777
|
-
|
|
36778
|
-
|
|
36779
|
-
return `Permission denied: ${permissionResult.reason}
|
|
36780
|
-
|
|
36781
|
-
This command is not allowed by the current security policy.
|
|
36782
|
-
|
|
36783
|
-
Common reasons:
|
|
36784
|
-
1. The command is in the deny list (potentially dangerous)
|
|
36785
|
-
2. The command is not in the allow list (not a recognized safe command)
|
|
36786
|
-
|
|
36787
|
-
If you believe this command should be allowed, you can:
|
|
36788
|
-
- Use the --bash-allow option to add specific patterns
|
|
36789
|
-
- Use the --no-default-bash-deny flag to remove default restrictions (not recommended)
|
|
36790
|
-
|
|
36791
|
-
For code exploration, try these safe alternatives:
|
|
36792
|
-
- ls, cat, head, tail for file operations
|
|
36793
|
-
- find, grep, rg for searching
|
|
36794
|
-
- git status, git log, git show for git operations
|
|
36795
|
-
- npm list, pip list for package information`;
|
|
36796
|
-
}
|
|
36797
|
-
const defaultDir = getDefaultWorkingDirectory();
|
|
36798
|
-
const workingDir = workingDirectory ? (0, import_path7.isAbsolute)(workingDirectory) ? (0, import_path7.resolve)(workingDirectory) : (0, import_path7.resolve)(defaultDir, workingDirectory) : defaultDir;
|
|
36799
|
-
if (allowedFolders && allowedFolders.length > 0) {
|
|
36800
|
-
const resolvedWorkingDir = (0, import_path7.resolve)(workingDir);
|
|
36801
|
-
const isAllowed = allowedFolders.some((folder) => {
|
|
36802
|
-
const resolvedFolder = (0, import_path7.resolve)(folder);
|
|
36803
|
-
return resolvedWorkingDir === resolvedFolder || resolvedWorkingDir.startsWith(resolvedFolder + import_path7.sep);
|
|
36804
|
-
});
|
|
36805
|
-
if (!isAllowed) {
|
|
36806
|
-
return `Error: Working directory "${workingDir}" is not within allowed folders: ${allowedFolders.join(", ")}`;
|
|
36807
|
-
}
|
|
36808
|
-
}
|
|
36809
|
-
const executionOptions = {
|
|
36810
|
-
workingDirectory: workingDir,
|
|
36811
|
-
timeout: timeout || bashConfig.timeout || 12e4,
|
|
36812
|
-
env: { ...bashConfig.env, ...env },
|
|
36813
|
-
maxBuffer: bashConfig.maxBuffer,
|
|
36814
|
-
debug
|
|
36611
|
+
if (config.deny && Array.isArray(config.deny)) {
|
|
36612
|
+
this.denyPatterns.push(...config.deny);
|
|
36613
|
+
if (this.debug) {
|
|
36614
|
+
console.log(`[BashPermissions] Added ${config.deny.length} custom deny patterns:`, config.deny);
|
|
36615
|
+
}
|
|
36616
|
+
}
|
|
36617
|
+
if (this.debug) {
|
|
36618
|
+
console.log(`[BashPermissions] Total patterns - Allow: ${this.allowPatterns.length}, Deny: ${this.denyPatterns.length}`);
|
|
36619
|
+
}
|
|
36620
|
+
}
|
|
36621
|
+
/**
|
|
36622
|
+
* Check if a simple command is allowed (complex commands allowed if they match patterns)
|
|
36623
|
+
* @param {string} command - Command to check
|
|
36624
|
+
* @returns {Object} Permission result
|
|
36625
|
+
*/
|
|
36626
|
+
check(command) {
|
|
36627
|
+
if (!command || typeof command !== "string") {
|
|
36628
|
+
return {
|
|
36629
|
+
allowed: false,
|
|
36630
|
+
reason: "Invalid or empty command",
|
|
36631
|
+
command
|
|
36632
|
+
};
|
|
36633
|
+
}
|
|
36634
|
+
const commandIsComplex = isComplexCommand(command);
|
|
36635
|
+
if (commandIsComplex) {
|
|
36636
|
+
return this._checkComplexCommand(command);
|
|
36637
|
+
}
|
|
36638
|
+
const parsed = parseCommand(command);
|
|
36639
|
+
if (parsed.error) {
|
|
36640
|
+
return {
|
|
36641
|
+
allowed: false,
|
|
36642
|
+
reason: parsed.error,
|
|
36643
|
+
command
|
|
36644
|
+
};
|
|
36645
|
+
}
|
|
36646
|
+
if (!parsed.command) {
|
|
36647
|
+
return {
|
|
36648
|
+
allowed: false,
|
|
36649
|
+
reason: "No valid command found",
|
|
36650
|
+
command
|
|
36651
|
+
};
|
|
36652
|
+
}
|
|
36653
|
+
if (this.debug) {
|
|
36654
|
+
console.log(`[BashPermissions] Checking simple command: "${command}"`);
|
|
36655
|
+
console.log(`[BashPermissions] Parsed: ${parsed.command} with args: [${parsed.args.join(", ")}]`);
|
|
36656
|
+
}
|
|
36657
|
+
if (matchesAnyPattern(parsed, this.denyPatterns)) {
|
|
36658
|
+
const matchedPatterns = this.denyPatterns.filter((pattern) => matchesPattern(parsed, pattern));
|
|
36659
|
+
return {
|
|
36660
|
+
allowed: false,
|
|
36661
|
+
reason: `Command matches deny pattern: ${matchedPatterns[0]}`,
|
|
36662
|
+
command,
|
|
36663
|
+
parsed,
|
|
36664
|
+
matchedPatterns
|
|
36665
|
+
};
|
|
36666
|
+
}
|
|
36667
|
+
if (this.allowPatterns.length > 0) {
|
|
36668
|
+
if (!matchesAnyPattern(parsed, this.allowPatterns)) {
|
|
36669
|
+
return {
|
|
36670
|
+
allowed: false,
|
|
36671
|
+
reason: "Command not in allow list",
|
|
36672
|
+
command,
|
|
36673
|
+
parsed
|
|
36815
36674
|
};
|
|
36816
|
-
|
|
36817
|
-
|
|
36818
|
-
|
|
36819
|
-
|
|
36820
|
-
|
|
36821
|
-
|
|
36822
|
-
|
|
36823
|
-
|
|
36824
|
-
|
|
36825
|
-
|
|
36826
|
-
|
|
36675
|
+
}
|
|
36676
|
+
}
|
|
36677
|
+
const result = {
|
|
36678
|
+
allowed: true,
|
|
36679
|
+
command,
|
|
36680
|
+
parsed,
|
|
36681
|
+
isComplex: false
|
|
36682
|
+
};
|
|
36683
|
+
if (this.debug) {
|
|
36684
|
+
console.log(`[BashPermissions] ALLOWED - command passed all checks`);
|
|
36685
|
+
}
|
|
36686
|
+
return result;
|
|
36687
|
+
}
|
|
36688
|
+
/**
|
|
36689
|
+
* Check a complex command against complex patterns in allow/deny lists
|
|
36690
|
+
* @private
|
|
36691
|
+
* @param {string} command - Complex command to check
|
|
36692
|
+
* @returns {Object} Permission result
|
|
36693
|
+
*/
|
|
36694
|
+
_checkComplexCommand(command) {
|
|
36695
|
+
if (this.debug) {
|
|
36696
|
+
console.log(`[BashPermissions] Checking complex command: "${command}"`);
|
|
36697
|
+
}
|
|
36698
|
+
const complexAllowPatterns = this.allowPatterns.filter((p4) => isComplexPattern(p4));
|
|
36699
|
+
const complexDenyPatterns = this.denyPatterns.filter((p4) => isComplexPattern(p4));
|
|
36700
|
+
if (this.debug) {
|
|
36701
|
+
console.log(`[BashPermissions] Complex allow patterns: ${complexAllowPatterns.length}`);
|
|
36702
|
+
console.log(`[BashPermissions] Complex deny patterns: ${complexDenyPatterns.length}`);
|
|
36703
|
+
}
|
|
36704
|
+
for (const pattern of complexDenyPatterns) {
|
|
36705
|
+
if (matchesComplexPattern(command, pattern)) {
|
|
36706
|
+
if (this.debug) {
|
|
36707
|
+
console.log(`[BashPermissions] DENIED - matches complex deny pattern: ${pattern}`);
|
|
36827
36708
|
}
|
|
36828
|
-
|
|
36829
|
-
|
|
36830
|
-
|
|
36709
|
+
return {
|
|
36710
|
+
allowed: false,
|
|
36711
|
+
reason: `Command matches deny pattern: ${pattern}`,
|
|
36712
|
+
command,
|
|
36713
|
+
isComplex: true,
|
|
36714
|
+
matchedPatterns: [pattern]
|
|
36715
|
+
};
|
|
36716
|
+
}
|
|
36717
|
+
}
|
|
36718
|
+
for (const pattern of complexAllowPatterns) {
|
|
36719
|
+
if (matchesComplexPattern(command, pattern)) {
|
|
36720
|
+
if (this.debug) {
|
|
36721
|
+
console.log(`[BashPermissions] ALLOWED - matches complex allow pattern: ${pattern}`);
|
|
36831
36722
|
}
|
|
36832
|
-
|
|
36833
|
-
|
|
36834
|
-
|
|
36723
|
+
return {
|
|
36724
|
+
allowed: true,
|
|
36725
|
+
command,
|
|
36726
|
+
isComplex: true,
|
|
36727
|
+
matchedPattern: pattern
|
|
36728
|
+
};
|
|
36729
|
+
}
|
|
36730
|
+
}
|
|
36731
|
+
if (this.debug) {
|
|
36732
|
+
console.log(`[BashPermissions] DENIED - no matching complex pattern found`);
|
|
36733
|
+
}
|
|
36734
|
+
return {
|
|
36735
|
+
allowed: false,
|
|
36736
|
+
reason: 'Complex shell commands require explicit allow patterns (e.g., "cd * && git *")',
|
|
36737
|
+
command,
|
|
36738
|
+
isComplex: true
|
|
36739
|
+
};
|
|
36740
|
+
}
|
|
36741
|
+
/**
|
|
36742
|
+
* Get configuration summary
|
|
36743
|
+
* @returns {Object} Configuration info
|
|
36744
|
+
*/
|
|
36745
|
+
getConfig() {
|
|
36746
|
+
return {
|
|
36747
|
+
allowPatterns: this.allowPatterns.length,
|
|
36748
|
+
denyPatterns: this.denyPatterns.length,
|
|
36749
|
+
totalPatterns: this.allowPatterns.length + this.denyPatterns.length
|
|
36750
|
+
};
|
|
36751
|
+
}
|
|
36752
|
+
};
|
|
36753
|
+
}
|
|
36754
|
+
});
|
|
36835
36755
|
|
|
36836
|
-
|
|
36837
|
-
|
|
36838
|
-
|
|
36839
|
-
|
|
36840
|
-
|
|
36841
|
-
|
|
36842
|
-
|
|
36843
|
-
|
|
36844
|
-
|
|
36845
|
-
|
|
36756
|
+
// src/agent/bashExecutor.js
|
|
36757
|
+
async function executeBashCommand(command, options = {}) {
|
|
36758
|
+
const {
|
|
36759
|
+
workingDirectory = process.cwd(),
|
|
36760
|
+
timeout = 12e4,
|
|
36761
|
+
// 2 minutes default
|
|
36762
|
+
env = {},
|
|
36763
|
+
maxBuffer = 10 * 1024 * 1024,
|
|
36764
|
+
// 10MB
|
|
36765
|
+
debug = false
|
|
36766
|
+
} = options;
|
|
36767
|
+
let cwd = workingDirectory;
|
|
36768
|
+
try {
|
|
36769
|
+
cwd = (0, import_path7.resolve)(cwd);
|
|
36770
|
+
if (!(0, import_fs6.existsSync)(cwd)) {
|
|
36771
|
+
throw new Error(`Working directory does not exist: ${cwd}`);
|
|
36772
|
+
}
|
|
36773
|
+
} catch (error2) {
|
|
36774
|
+
return {
|
|
36775
|
+
success: false,
|
|
36776
|
+
error: `Invalid working directory: ${error2.message}`,
|
|
36777
|
+
stdout: "",
|
|
36778
|
+
stderr: "",
|
|
36779
|
+
exitCode: 1,
|
|
36780
|
+
command,
|
|
36781
|
+
workingDirectory: cwd,
|
|
36782
|
+
duration: 0
|
|
36783
|
+
};
|
|
36784
|
+
}
|
|
36785
|
+
const startTime = Date.now();
|
|
36786
|
+
if (debug) {
|
|
36787
|
+
console.log(`[BashExecutor] Executing command: "${command}"`);
|
|
36788
|
+
console.log(`[BashExecutor] Working directory: "${cwd}"`);
|
|
36789
|
+
console.log(`[BashExecutor] Timeout: ${timeout}ms`);
|
|
36790
|
+
}
|
|
36791
|
+
return new Promise((resolve6, reject2) => {
|
|
36792
|
+
const processEnv = {
|
|
36793
|
+
...process.env,
|
|
36794
|
+
...env
|
|
36795
|
+
};
|
|
36796
|
+
const isComplex = isComplexCommand(command);
|
|
36797
|
+
let cmd, cmdArgs, useShell;
|
|
36798
|
+
if (isComplex) {
|
|
36799
|
+
cmd = "sh";
|
|
36800
|
+
cmdArgs = ["-c", command];
|
|
36801
|
+
useShell = false;
|
|
36802
|
+
if (debug) {
|
|
36803
|
+
console.log(`[BashExecutor] Complex command - using sh -c`);
|
|
36804
|
+
}
|
|
36805
|
+
} else {
|
|
36806
|
+
const args = parseCommandForExecution(command);
|
|
36807
|
+
if (!args || args.length === 0) {
|
|
36808
|
+
resolve6({
|
|
36809
|
+
success: false,
|
|
36810
|
+
error: "Failed to parse command",
|
|
36811
|
+
stdout: "",
|
|
36812
|
+
stderr: "",
|
|
36813
|
+
exitCode: 1,
|
|
36814
|
+
command,
|
|
36815
|
+
workingDirectory: cwd,
|
|
36816
|
+
duration: Date.now() - startTime
|
|
36817
|
+
});
|
|
36818
|
+
return;
|
|
36819
|
+
}
|
|
36820
|
+
[cmd, ...cmdArgs] = args;
|
|
36821
|
+
useShell = false;
|
|
36822
|
+
}
|
|
36823
|
+
const child = (0, import_child_process6.spawn)(cmd, cmdArgs, {
|
|
36824
|
+
cwd,
|
|
36825
|
+
env: processEnv,
|
|
36826
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
36827
|
+
// stdin ignored, capture stdout/stderr
|
|
36828
|
+
shell: useShell,
|
|
36829
|
+
// false for security
|
|
36830
|
+
windowsHide: true
|
|
36831
|
+
});
|
|
36832
|
+
let stdout = "";
|
|
36833
|
+
let stderr = "";
|
|
36834
|
+
let killed = false;
|
|
36835
|
+
let timeoutHandle;
|
|
36836
|
+
if (timeout > 0) {
|
|
36837
|
+
timeoutHandle = setTimeout(() => {
|
|
36838
|
+
if (!killed) {
|
|
36839
|
+
killed = true;
|
|
36840
|
+
child.kill("SIGTERM");
|
|
36841
|
+
setTimeout(() => {
|
|
36842
|
+
if (child.exitCode === null) {
|
|
36843
|
+
child.kill("SIGKILL");
|
|
36846
36844
|
}
|
|
36847
|
-
|
|
36848
|
-
|
|
36845
|
+
}, 5e3);
|
|
36846
|
+
}
|
|
36847
|
+
}, timeout);
|
|
36848
|
+
}
|
|
36849
|
+
child.stdout.on("data", (data2) => {
|
|
36850
|
+
const chunk = data2.toString();
|
|
36851
|
+
if (stdout.length + chunk.length <= maxBuffer) {
|
|
36852
|
+
stdout += chunk;
|
|
36853
|
+
} else {
|
|
36854
|
+
if (!killed) {
|
|
36855
|
+
killed = true;
|
|
36856
|
+
child.kill("SIGTERM");
|
|
36857
|
+
}
|
|
36858
|
+
}
|
|
36859
|
+
});
|
|
36860
|
+
child.stderr.on("data", (data2) => {
|
|
36861
|
+
const chunk = data2.toString();
|
|
36862
|
+
if (stderr.length + chunk.length <= maxBuffer) {
|
|
36863
|
+
stderr += chunk;
|
|
36864
|
+
} else {
|
|
36865
|
+
if (!killed) {
|
|
36866
|
+
killed = true;
|
|
36867
|
+
child.kill("SIGTERM");
|
|
36868
|
+
}
|
|
36869
|
+
}
|
|
36870
|
+
});
|
|
36871
|
+
child.on("close", (code, signal) => {
|
|
36872
|
+
if (timeoutHandle) {
|
|
36873
|
+
clearTimeout(timeoutHandle);
|
|
36874
|
+
}
|
|
36875
|
+
const duration = Date.now() - startTime;
|
|
36876
|
+
if (debug) {
|
|
36877
|
+
console.log(`[BashExecutor] Command completed - Code: ${code}, Signal: ${signal}, Duration: ${duration}ms`);
|
|
36878
|
+
console.log(`[BashExecutor] Stdout length: ${stdout.length}, Stderr length: ${stderr.length}`);
|
|
36879
|
+
}
|
|
36880
|
+
let success = true;
|
|
36881
|
+
let error2 = "";
|
|
36882
|
+
if (killed) {
|
|
36883
|
+
success = false;
|
|
36884
|
+
if (stdout.length + stderr.length > maxBuffer) {
|
|
36885
|
+
error2 = `Command output exceeded maximum buffer size (${maxBuffer} bytes)`;
|
|
36886
|
+
} else {
|
|
36887
|
+
error2 = `Command timed out after ${timeout}ms`;
|
|
36849
36888
|
}
|
|
36889
|
+
} else if (code !== 0) {
|
|
36890
|
+
success = false;
|
|
36891
|
+
error2 = `Command exited with code ${code}`;
|
|
36892
|
+
}
|
|
36893
|
+
resolve6({
|
|
36894
|
+
success,
|
|
36895
|
+
error: error2,
|
|
36896
|
+
stdout: stdout.trim(),
|
|
36897
|
+
stderr: stderr.trim(),
|
|
36898
|
+
exitCode: code,
|
|
36899
|
+
signal,
|
|
36900
|
+
command,
|
|
36901
|
+
workingDirectory: cwd,
|
|
36902
|
+
duration,
|
|
36903
|
+
killed
|
|
36850
36904
|
});
|
|
36851
|
-
};
|
|
36905
|
+
});
|
|
36906
|
+
child.on("error", (error2) => {
|
|
36907
|
+
if (timeoutHandle) {
|
|
36908
|
+
clearTimeout(timeoutHandle);
|
|
36909
|
+
}
|
|
36910
|
+
if (debug) {
|
|
36911
|
+
console.log(`[BashExecutor] Spawn error:`, error2);
|
|
36912
|
+
}
|
|
36913
|
+
resolve6({
|
|
36914
|
+
success: false,
|
|
36915
|
+
error: `Failed to execute command: ${error2.message}`,
|
|
36916
|
+
stdout: "",
|
|
36917
|
+
stderr: "",
|
|
36918
|
+
exitCode: 1,
|
|
36919
|
+
command,
|
|
36920
|
+
workingDirectory: cwd,
|
|
36921
|
+
duration: Date.now() - startTime
|
|
36922
|
+
});
|
|
36923
|
+
});
|
|
36924
|
+
});
|
|
36925
|
+
}
|
|
36926
|
+
function formatExecutionResult(result, includeMetadata = false) {
|
|
36927
|
+
if (!result) {
|
|
36928
|
+
return "No result available";
|
|
36852
36929
|
}
|
|
36853
|
-
|
|
36854
|
-
|
|
36855
|
-
|
|
36856
|
-
|
|
36857
|
-
|
|
36858
|
-
|
|
36859
|
-
|
|
36860
|
-
|
|
36930
|
+
let output = "";
|
|
36931
|
+
if (includeMetadata) {
|
|
36932
|
+
output += `Command: ${result.command}
|
|
36933
|
+
`;
|
|
36934
|
+
output += `Working directory: ${result.workingDirectory}
|
|
36935
|
+
`;
|
|
36936
|
+
output += `Duration: ${result.duration}ms
|
|
36937
|
+
`;
|
|
36938
|
+
output += `Exit Code: ${result.exitCode}
|
|
36939
|
+
`;
|
|
36940
|
+
if (result.signal) {
|
|
36941
|
+
output += `Signal: ${result.signal}
|
|
36942
|
+
`;
|
|
36943
|
+
}
|
|
36944
|
+
output += "\n";
|
|
36861
36945
|
}
|
|
36862
|
-
|
|
36863
|
-
|
|
36864
|
-
|
|
36865
|
-
|
|
36866
|
-
|
|
36946
|
+
if (result.stdout) {
|
|
36947
|
+
if (includeMetadata) {
|
|
36948
|
+
output += "--- STDOUT ---\n";
|
|
36949
|
+
}
|
|
36950
|
+
output += result.stdout;
|
|
36951
|
+
if (includeMetadata && result.stderr) {
|
|
36952
|
+
output += "\n";
|
|
36953
|
+
}
|
|
36954
|
+
}
|
|
36955
|
+
if (result.stderr) {
|
|
36956
|
+
if (includeMetadata) {
|
|
36957
|
+
if (result.stdout) output += "\n";
|
|
36958
|
+
output += "--- STDERR ---\n";
|
|
36959
|
+
} else if (result.stdout) {
|
|
36960
|
+
output += "\n--- STDERR ---\n";
|
|
36961
|
+
}
|
|
36962
|
+
output += result.stderr;
|
|
36963
|
+
}
|
|
36964
|
+
if (!result.success && result.error && !result.stderr) {
|
|
36965
|
+
if (output) output += "\n";
|
|
36966
|
+
output += `Error: ${result.error}`;
|
|
36967
|
+
}
|
|
36968
|
+
if (!result.success && result.exitCode !== void 0 && result.exitCode !== 0) {
|
|
36969
|
+
if (output) output += "\n";
|
|
36970
|
+
output += `Exit code: ${result.exitCode}`;
|
|
36971
|
+
}
|
|
36972
|
+
return output || (result.success ? "Command completed successfully (no output)" : "Command failed (no output)");
|
|
36867
36973
|
}
|
|
36868
|
-
function
|
|
36974
|
+
function validateExecutionOptions(options = {}) {
|
|
36975
|
+
const errors = [];
|
|
36976
|
+
const warnings = [];
|
|
36977
|
+
if (options.timeout !== void 0) {
|
|
36978
|
+
if (typeof options.timeout !== "number" || options.timeout < 0) {
|
|
36979
|
+
errors.push("timeout must be a non-negative number");
|
|
36980
|
+
} else if (options.timeout > 6e5) {
|
|
36981
|
+
warnings.push("timeout is very high (>10 minutes)");
|
|
36982
|
+
}
|
|
36983
|
+
}
|
|
36984
|
+
if (options.maxBuffer !== void 0) {
|
|
36985
|
+
if (typeof options.maxBuffer !== "number" || options.maxBuffer < 1024) {
|
|
36986
|
+
errors.push("maxBuffer must be at least 1024 bytes");
|
|
36987
|
+
} else if (options.maxBuffer > 100 * 1024 * 1024) {
|
|
36988
|
+
warnings.push("maxBuffer is very high (>100MB)");
|
|
36989
|
+
}
|
|
36990
|
+
}
|
|
36991
|
+
if (options.workingDirectory) {
|
|
36992
|
+
if (typeof options.workingDirectory !== "string") {
|
|
36993
|
+
errors.push("workingDirectory must be a string");
|
|
36994
|
+
} else if (!(0, import_fs6.existsSync)(options.workingDirectory)) {
|
|
36995
|
+
errors.push(`workingDirectory does not exist: ${options.workingDirectory}`);
|
|
36996
|
+
}
|
|
36997
|
+
}
|
|
36998
|
+
if (options.env && typeof options.env !== "object") {
|
|
36999
|
+
errors.push("env must be an object");
|
|
37000
|
+
}
|
|
36869
37001
|
return {
|
|
36870
|
-
|
|
36871
|
-
|
|
36872
|
-
|
|
37002
|
+
valid: errors.length === 0,
|
|
37003
|
+
errors,
|
|
37004
|
+
warnings
|
|
36873
37005
|
};
|
|
36874
37006
|
}
|
|
36875
|
-
var
|
|
36876
|
-
var
|
|
36877
|
-
"src/
|
|
37007
|
+
var import_child_process6, import_path7, import_fs6;
|
|
37008
|
+
var init_bashExecutor = __esm({
|
|
37009
|
+
"src/agent/bashExecutor.js"() {
|
|
36878
37010
|
"use strict";
|
|
36879
|
-
|
|
36880
|
-
|
|
36881
|
-
import_path8 = require("path");
|
|
37011
|
+
import_child_process6 = require("child_process");
|
|
37012
|
+
import_path7 = require("path");
|
|
36882
37013
|
import_fs6 = require("fs");
|
|
36883
|
-
|
|
36884
|
-
|
|
36885
|
-
|
|
36886
|
-
name: "edit",
|
|
36887
|
-
description: `Edit files using exact string replacement (Claude Code style).
|
|
36888
|
-
|
|
36889
|
-
This tool performs exact string replacements in files. It requires the old_string to match exactly what's in the file, including all whitespace and indentation.
|
|
36890
|
-
|
|
36891
|
-
Parameters:
|
|
36892
|
-
- file_path: Path to the file to edit (absolute or relative)
|
|
36893
|
-
- old_string: Exact text to find and replace (must be unique in the file unless replace_all is true)
|
|
36894
|
-
- new_string: Text to replace with
|
|
36895
|
-
- replace_all: (optional) Replace all occurrences instead of requiring uniqueness
|
|
37014
|
+
init_bashCommandUtils();
|
|
37015
|
+
}
|
|
37016
|
+
});
|
|
36896
37017
|
|
|
36897
|
-
|
|
36898
|
-
|
|
36899
|
-
|
|
36900
|
-
|
|
36901
|
-
|
|
36902
|
-
|
|
36903
|
-
|
|
36904
|
-
|
|
36905
|
-
|
|
36906
|
-
|
|
36907
|
-
|
|
36908
|
-
|
|
36909
|
-
|
|
36910
|
-
|
|
36911
|
-
|
|
36912
|
-
|
|
36913
|
-
|
|
36914
|
-
|
|
36915
|
-
|
|
36916
|
-
|
|
36917
|
-
|
|
36918
|
-
|
|
36919
|
-
default: false
|
|
36920
|
-
}
|
|
36921
|
-
},
|
|
36922
|
-
required: ["file_path", "old_string", "new_string"]
|
|
36923
|
-
},
|
|
36924
|
-
execute: async ({ file_path, old_string, new_string, replace_all = false }) => {
|
|
36925
|
-
try {
|
|
36926
|
-
if (!file_path || typeof file_path !== "string" || file_path.trim() === "") {
|
|
36927
|
-
return `Error editing file: Invalid file_path - must be a non-empty string`;
|
|
36928
|
-
}
|
|
36929
|
-
if (old_string === void 0 || old_string === null || typeof old_string !== "string") {
|
|
36930
|
-
return `Error editing file: Invalid old_string - must be a string`;
|
|
36931
|
-
}
|
|
36932
|
-
if (new_string === void 0 || new_string === null || typeof new_string !== "string") {
|
|
36933
|
-
return `Error editing file: Invalid new_string - must be a string`;
|
|
36934
|
-
}
|
|
36935
|
-
const resolvedPath2 = (0, import_path8.isAbsolute)(file_path) ? file_path : (0, import_path8.resolve)(cwd || process.cwd(), file_path);
|
|
36936
|
-
if (debug) {
|
|
36937
|
-
console.error(`[Edit] Attempting to edit file: ${resolvedPath2}`);
|
|
36938
|
-
}
|
|
36939
|
-
if (!isPathAllowed(resolvedPath2, allowedFolders)) {
|
|
36940
|
-
return `Error editing file: Permission denied - ${file_path} is outside allowed directories`;
|
|
36941
|
-
}
|
|
36942
|
-
if (!(0, import_fs6.existsSync)(resolvedPath2)) {
|
|
36943
|
-
return `Error editing file: File not found - ${file_path}`;
|
|
36944
|
-
}
|
|
36945
|
-
const content = await import_fs5.promises.readFile(resolvedPath2, "utf-8");
|
|
36946
|
-
if (!content.includes(old_string)) {
|
|
36947
|
-
return `Error editing file: String not found - the specified old_string was not found in ${file_path}`;
|
|
36948
|
-
}
|
|
36949
|
-
const occurrences = content.split(old_string).length - 1;
|
|
36950
|
-
if (!replace_all && occurrences > 1) {
|
|
36951
|
-
return `Error editing file: Multiple occurrences found - the old_string appears ${occurrences} times. Use replace_all: true to replace all occurrences, or provide more context to make the string unique.`;
|
|
36952
|
-
}
|
|
36953
|
-
let newContent;
|
|
36954
|
-
if (replace_all) {
|
|
36955
|
-
newContent = content.replaceAll(old_string, new_string);
|
|
36956
|
-
} else {
|
|
36957
|
-
newContent = content.replace(old_string, new_string);
|
|
36958
|
-
}
|
|
36959
|
-
if (newContent === content) {
|
|
36960
|
-
return `Error editing file: No changes made - old_string and new_string might be the same`;
|
|
36961
|
-
}
|
|
36962
|
-
await import_fs5.promises.writeFile(resolvedPath2, newContent, "utf-8");
|
|
36963
|
-
const replacedCount = replace_all ? occurrences : 1;
|
|
36964
|
-
if (debug) {
|
|
36965
|
-
console.error(`[Edit] Successfully edited ${resolvedPath2}, replaced ${replacedCount} occurrence(s)`);
|
|
36966
|
-
}
|
|
36967
|
-
return `Successfully edited ${file_path} (${replacedCount} replacement${replacedCount !== 1 ? "s" : ""})`;
|
|
36968
|
-
} catch (error2) {
|
|
36969
|
-
console.error("[Edit] Error:", error2);
|
|
36970
|
-
return `Error editing file: ${error2.message}`;
|
|
36971
|
-
}
|
|
36972
|
-
}
|
|
37018
|
+
// src/tools/bash.js
|
|
37019
|
+
var import_ai3, import_path8, bashTool;
|
|
37020
|
+
var init_bash = __esm({
|
|
37021
|
+
"src/tools/bash.js"() {
|
|
37022
|
+
"use strict";
|
|
37023
|
+
import_ai3 = require("ai");
|
|
37024
|
+
import_path8 = require("path");
|
|
37025
|
+
init_bashPermissions();
|
|
37026
|
+
init_bashExecutor();
|
|
37027
|
+
bashTool = (options = {}) => {
|
|
37028
|
+
const {
|
|
37029
|
+
bashConfig = {},
|
|
37030
|
+
debug = false,
|
|
37031
|
+
cwd,
|
|
37032
|
+
allowedFolders = []
|
|
37033
|
+
} = options;
|
|
37034
|
+
const permissionChecker = new BashPermissionChecker({
|
|
37035
|
+
allow: bashConfig.allow,
|
|
37036
|
+
deny: bashConfig.deny,
|
|
37037
|
+
disableDefaultAllow: bashConfig.disableDefaultAllow,
|
|
37038
|
+
disableDefaultDeny: bashConfig.disableDefaultDeny,
|
|
37039
|
+
debug
|
|
36973
37040
|
});
|
|
36974
|
-
|
|
36975
|
-
|
|
36976
|
-
|
|
37041
|
+
const getDefaultWorkingDirectory = () => {
|
|
37042
|
+
if (bashConfig.workingDirectory) {
|
|
37043
|
+
return bashConfig.workingDirectory;
|
|
37044
|
+
}
|
|
37045
|
+
if (cwd) {
|
|
37046
|
+
return cwd;
|
|
37047
|
+
}
|
|
37048
|
+
if (allowedFolders && allowedFolders.length > 0) {
|
|
37049
|
+
return allowedFolders[0];
|
|
37050
|
+
}
|
|
37051
|
+
return process.cwd();
|
|
37052
|
+
};
|
|
36977
37053
|
return (0, import_ai3.tool)({
|
|
36978
|
-
name: "
|
|
36979
|
-
description: `
|
|
37054
|
+
name: "bash",
|
|
37055
|
+
description: `Execute bash commands for system exploration and development tasks.
|
|
36980
37056
|
|
|
36981
|
-
This tool
|
|
37057
|
+
Security: This tool has built-in security with allow/deny lists. By default, only safe read-only commands are allowed for code exploration.
|
|
36982
37058
|
|
|
36983
37059
|
Parameters:
|
|
36984
|
-
-
|
|
36985
|
-
-
|
|
36986
|
-
-
|
|
37060
|
+
- command: (required) The bash command to execute
|
|
37061
|
+
- workingDirectory: (optional) Directory to execute command in
|
|
37062
|
+
- timeout: (optional) Command timeout in milliseconds
|
|
37063
|
+
- env: (optional) Additional environment variables
|
|
36987
37064
|
|
|
36988
|
-
|
|
36989
|
-
-
|
|
36990
|
-
-
|
|
36991
|
-
-
|
|
37065
|
+
Examples of allowed commands by default:
|
|
37066
|
+
- File exploration: ls, cat, head, tail, find, grep
|
|
37067
|
+
- Git operations: git status, git log, git diff, git show
|
|
37068
|
+
- Package info: npm list, pip list, cargo --version
|
|
37069
|
+
- System info: whoami, pwd, uname, date
|
|
37070
|
+
|
|
37071
|
+
Dangerous commands are blocked by default (rm -rf, sudo, npm install, etc.)`,
|
|
36992
37072
|
inputSchema: {
|
|
36993
37073
|
type: "object",
|
|
36994
37074
|
properties: {
|
|
36995
|
-
|
|
37075
|
+
command: {
|
|
36996
37076
|
type: "string",
|
|
36997
|
-
description: "
|
|
37077
|
+
description: "The bash command to execute"
|
|
36998
37078
|
},
|
|
36999
|
-
|
|
37079
|
+
workingDirectory: {
|
|
37000
37080
|
type: "string",
|
|
37001
|
-
description: "
|
|
37081
|
+
description: "Directory to execute the command in (optional)"
|
|
37002
37082
|
},
|
|
37003
|
-
|
|
37004
|
-
type: "
|
|
37005
|
-
description: "
|
|
37006
|
-
|
|
37083
|
+
timeout: {
|
|
37084
|
+
type: "number",
|
|
37085
|
+
description: "Command timeout in milliseconds (optional)",
|
|
37086
|
+
minimum: 1e3,
|
|
37087
|
+
maximum: 6e5
|
|
37088
|
+
},
|
|
37089
|
+
env: {
|
|
37090
|
+
type: "object",
|
|
37091
|
+
description: "Additional environment variables (optional)",
|
|
37092
|
+
additionalProperties: {
|
|
37093
|
+
type: "string"
|
|
37094
|
+
}
|
|
37007
37095
|
}
|
|
37008
37096
|
},
|
|
37009
|
-
required: ["
|
|
37097
|
+
required: ["command"],
|
|
37098
|
+
additionalProperties: false
|
|
37010
37099
|
},
|
|
37011
|
-
execute: async ({
|
|
37100
|
+
execute: async ({ command, workingDirectory, timeout, env }) => {
|
|
37012
37101
|
try {
|
|
37013
|
-
if (
|
|
37014
|
-
return
|
|
37102
|
+
if (command === null || command === void 0 || typeof command !== "string") {
|
|
37103
|
+
return "Error: Command is required and must be a string";
|
|
37015
37104
|
}
|
|
37016
|
-
if (
|
|
37017
|
-
return
|
|
37105
|
+
if (command.trim().length === 0) {
|
|
37106
|
+
return "Error: Command cannot be empty";
|
|
37018
37107
|
}
|
|
37019
|
-
const
|
|
37020
|
-
if (
|
|
37021
|
-
|
|
37108
|
+
const permissionResult = permissionChecker.check(command.trim());
|
|
37109
|
+
if (!permissionResult.allowed) {
|
|
37110
|
+
if (debug) {
|
|
37111
|
+
console.log(`[BashTool] Permission denied for command: "${command}"`);
|
|
37112
|
+
console.log(`[BashTool] Reason: ${permissionResult.reason}`);
|
|
37113
|
+
}
|
|
37114
|
+
return `Permission denied: ${permissionResult.reason}
|
|
37115
|
+
|
|
37116
|
+
This command is not allowed by the current security policy.
|
|
37117
|
+
|
|
37118
|
+
Common reasons:
|
|
37119
|
+
1. The command is in the deny list (potentially dangerous)
|
|
37120
|
+
2. The command is not in the allow list (not a recognized safe command)
|
|
37121
|
+
|
|
37122
|
+
If you believe this command should be allowed, you can:
|
|
37123
|
+
- Use the --bash-allow option to add specific patterns
|
|
37124
|
+
- Use the --no-default-bash-deny flag to remove default restrictions (not recommended)
|
|
37125
|
+
|
|
37126
|
+
For code exploration, try these safe alternatives:
|
|
37127
|
+
- ls, cat, head, tail for file operations
|
|
37128
|
+
- find, grep, rg for searching
|
|
37129
|
+
- git status, git log, git show for git operations
|
|
37130
|
+
- npm list, pip list for package information`;
|
|
37022
37131
|
}
|
|
37023
|
-
|
|
37024
|
-
|
|
37132
|
+
const defaultDir = getDefaultWorkingDirectory();
|
|
37133
|
+
const workingDir = workingDirectory ? (0, import_path8.isAbsolute)(workingDirectory) ? (0, import_path8.resolve)(workingDirectory) : (0, import_path8.resolve)(defaultDir, workingDirectory) : defaultDir;
|
|
37134
|
+
if (allowedFolders && allowedFolders.length > 0) {
|
|
37135
|
+
const resolvedWorkingDir = (0, import_path8.resolve)(workingDir);
|
|
37136
|
+
const isAllowed = allowedFolders.some((folder) => {
|
|
37137
|
+
const resolvedFolder = (0, import_path8.resolve)(folder);
|
|
37138
|
+
return resolvedWorkingDir === resolvedFolder || resolvedWorkingDir.startsWith(resolvedFolder + import_path8.sep);
|
|
37139
|
+
});
|
|
37140
|
+
if (!isAllowed) {
|
|
37141
|
+
return `Error: Working directory "${workingDir}" is not within allowed folders: ${allowedFolders.join(", ")}`;
|
|
37142
|
+
}
|
|
37025
37143
|
}
|
|
37026
|
-
|
|
37027
|
-
|
|
37144
|
+
const executionOptions = {
|
|
37145
|
+
workingDirectory: workingDir,
|
|
37146
|
+
timeout: timeout || bashConfig.timeout || 12e4,
|
|
37147
|
+
env: { ...bashConfig.env, ...env },
|
|
37148
|
+
maxBuffer: bashConfig.maxBuffer,
|
|
37149
|
+
debug
|
|
37150
|
+
};
|
|
37151
|
+
const validation = validateExecutionOptions(executionOptions);
|
|
37152
|
+
if (!validation.valid) {
|
|
37153
|
+
return `Error: Invalid execution options: ${validation.errors.join(", ")}`;
|
|
37154
|
+
}
|
|
37155
|
+
if (validation.warnings.length > 0 && debug) {
|
|
37156
|
+
console.log("[BashTool] Warnings:", validation.warnings);
|
|
37028
37157
|
}
|
|
37029
|
-
const dir = (0, import_path8.dirname)(resolvedPath2);
|
|
37030
|
-
await import_fs5.promises.mkdir(dir, { recursive: true });
|
|
37031
|
-
await import_fs5.promises.writeFile(resolvedPath2, content, "utf-8");
|
|
37032
|
-
const action = (0, import_fs6.existsSync)(resolvedPath2) && overwrite ? "overwrote" : "created";
|
|
37033
|
-
const bytes = Buffer.byteLength(content, "utf-8");
|
|
37034
37158
|
if (debug) {
|
|
37035
|
-
console.
|
|
37159
|
+
console.log(`[BashTool] Executing command: "${command}"`);
|
|
37160
|
+
console.log(`[BashTool] Working directory: "${workingDir}"`);
|
|
37161
|
+
console.log(`[BashTool] Timeout: ${executionOptions.timeout}ms`);
|
|
37036
37162
|
}
|
|
37037
|
-
|
|
37163
|
+
const result = await executeBashCommand(command.trim(), executionOptions);
|
|
37164
|
+
if (debug) {
|
|
37165
|
+
console.log(`[BashTool] Command completed - Success: ${result.success}, Duration: ${result.duration}ms`);
|
|
37166
|
+
}
|
|
37167
|
+
const formattedResult = formatExecutionResult(result, debug);
|
|
37168
|
+
if (!result.success) {
|
|
37169
|
+
let errorInfo = `
|
|
37170
|
+
|
|
37171
|
+
Command failed with exit code ${result.exitCode}`;
|
|
37172
|
+
if (result.killed) {
|
|
37173
|
+
errorInfo += ` (${result.error})`;
|
|
37174
|
+
}
|
|
37175
|
+
return formattedResult + errorInfo;
|
|
37176
|
+
}
|
|
37177
|
+
return formattedResult;
|
|
37038
37178
|
} catch (error2) {
|
|
37039
|
-
|
|
37040
|
-
|
|
37179
|
+
if (debug) {
|
|
37180
|
+
console.error("[BashTool] Execution error:", error2);
|
|
37181
|
+
}
|
|
37182
|
+
return `Error executing bash command: ${error2.message}`;
|
|
37041
37183
|
}
|
|
37042
37184
|
}
|
|
37043
37185
|
});
|
|
37044
37186
|
};
|
|
37045
|
-
editDescription = "Edit files using exact string replacement. Requires exact match including whitespace.";
|
|
37046
|
-
createDescription = "Create new files with specified content. Will create parent directories if needed.";
|
|
37047
|
-
editToolDefinition = `
|
|
37048
|
-
## edit
|
|
37049
|
-
Description: ${editDescription}
|
|
37050
|
-
|
|
37051
|
-
When to use:
|
|
37052
|
-
- For precise, surgical edits to existing files
|
|
37053
|
-
- When you need to change specific lines or blocks of code
|
|
37054
|
-
- For renaming functions, variables, or updating configuration values
|
|
37055
|
-
- When the exact text to replace is known and unique (or use replace_all for multiple occurrences)
|
|
37056
|
-
|
|
37057
|
-
When NOT to use:
|
|
37058
|
-
- For creating new files (use 'create' tool instead)
|
|
37059
|
-
- When you cannot determine the exact text to replace
|
|
37060
|
-
- When changes span multiple locations that would be better handled together
|
|
37061
|
-
|
|
37062
|
-
Parameters:
|
|
37063
|
-
- file_path: (required) Path to the file to edit
|
|
37064
|
-
- old_string: (required) Exact text to find and replace (must match including whitespace, newlines, and indentation)
|
|
37065
|
-
- new_string: (required) Text to replace with
|
|
37066
|
-
- replace_all: (optional, default: false) Replace all occurrences if the string appears multiple times
|
|
37067
|
-
|
|
37068
|
-
Important notes:
|
|
37069
|
-
- The old_string MUST match EXACTLY, including all whitespace, indentation, and line breaks
|
|
37070
|
-
- If old_string appears multiple times and replace_all is false, the tool will fail
|
|
37071
|
-
- Always verify the exact formatting of the text you want to replace
|
|
37072
|
-
|
|
37073
|
-
Examples:
|
|
37074
|
-
<edit>
|
|
37075
|
-
<file_path>src/main.js</file_path>
|
|
37076
|
-
<old_string>function oldName() {
|
|
37077
|
-
return 42;
|
|
37078
|
-
}</old_string>
|
|
37079
|
-
<new_string>function newName() {
|
|
37080
|
-
return 42;
|
|
37081
|
-
}</new_string>
|
|
37082
|
-
</edit>
|
|
37083
|
-
|
|
37084
|
-
<edit>
|
|
37085
|
-
<file_path>config.json</file_path>
|
|
37086
|
-
<old_string>"debug": false</old_string>
|
|
37087
|
-
<new_string>"debug": true</new_string>
|
|
37088
|
-
<replace_all>true</replace_all>
|
|
37089
|
-
</edit>`;
|
|
37090
|
-
createToolDefinition = `
|
|
37091
|
-
## create
|
|
37092
|
-
Description: ${createDescription}
|
|
37093
|
-
|
|
37094
|
-
When to use:
|
|
37095
|
-
- For creating brand new files from scratch
|
|
37096
|
-
- When you need to add configuration files, documentation, or new modules
|
|
37097
|
-
- For generating boilerplate code or templates
|
|
37098
|
-
- When you have the complete content ready to write
|
|
37099
|
-
|
|
37100
|
-
When NOT to use:
|
|
37101
|
-
- For editing existing files (use 'edit' tool instead)
|
|
37102
|
-
- When a file already exists unless you explicitly want to overwrite it
|
|
37103
|
-
|
|
37104
|
-
Parameters:
|
|
37105
|
-
- file_path: (required) Path where the file should be created
|
|
37106
|
-
- content: (required) Complete content to write to the file
|
|
37107
|
-
- overwrite: (optional, default: false) Whether to overwrite if file already exists
|
|
37108
|
-
|
|
37109
|
-
Important notes:
|
|
37110
|
-
- Parent directories will be created automatically if they don't exist
|
|
37111
|
-
- The tool will fail if the file already exists and overwrite is false
|
|
37112
|
-
- Be careful with the overwrite option as it completely replaces existing files
|
|
37113
|
-
|
|
37114
|
-
Examples:
|
|
37115
|
-
<create>
|
|
37116
|
-
<file_path>src/newFile.js</file_path>
|
|
37117
|
-
<content>export function hello() {
|
|
37118
|
-
return "Hello, world!";
|
|
37119
|
-
}</content>
|
|
37120
|
-
</create>
|
|
37121
|
-
|
|
37122
|
-
<create>
|
|
37123
|
-
<file_path>README.md</file_path>
|
|
37124
|
-
<content># My Project
|
|
37125
|
-
|
|
37126
|
-
This is a new project.</content>
|
|
37127
|
-
<overwrite>true</overwrite>
|
|
37128
|
-
</create>`;
|
|
37129
37187
|
}
|
|
37130
37188
|
});
|
|
37131
37189
|
|
|
@@ -44436,7 +44494,7 @@ function removeThinkingTags(xmlString) {
|
|
|
44436
44494
|
const thinkingIndex = result.indexOf("<thinking>");
|
|
44437
44495
|
if (thinkingIndex !== -1) {
|
|
44438
44496
|
const afterThinking = result.substring(thinkingIndex + "<thinking>".length);
|
|
44439
|
-
const toolPattern =
|
|
44497
|
+
const toolPattern = buildToolTagPattern(DEFAULT_VALID_TOOLS);
|
|
44440
44498
|
const toolMatch = afterThinking.match(toolPattern);
|
|
44441
44499
|
if (toolMatch) {
|
|
44442
44500
|
const toolStart = thinkingIndex + "<thinking>".length + toolMatch.index;
|
|
@@ -44511,8 +44569,7 @@ function checkAttemptCompleteRecovery(cleanedXmlString, validTools = []) {
|
|
|
44511
44569
|
return null;
|
|
44512
44570
|
}
|
|
44513
44571
|
function hasOtherToolTags(xmlString, validTools = []) {
|
|
44514
|
-
const
|
|
44515
|
-
const toolsToCheck = validTools.length > 0 ? validTools : defaultTools;
|
|
44572
|
+
const toolsToCheck = validTools.length > 0 ? validTools : DEFAULT_VALID_TOOLS;
|
|
44516
44573
|
for (const tool4 of toolsToCheck) {
|
|
44517
44574
|
if (tool4 !== "attempt_completion" && xmlString.includes(`<${tool4}`)) {
|
|
44518
44575
|
return true;
|
|
@@ -44537,6 +44594,7 @@ ${thinkingContent}`);
|
|
|
44537
44594
|
var init_xmlParsingUtils = __esm({
|
|
44538
44595
|
"src/agent/xmlParsingUtils.js"() {
|
|
44539
44596
|
"use strict";
|
|
44597
|
+
init_common2();
|
|
44540
44598
|
}
|
|
44541
44599
|
});
|
|
44542
44600
|
|