@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/cjs/index.cjs CHANGED
@@ -30515,261 +30515,6 @@ var init_imageConfig = __esm({
30515
30515
  }
30516
30516
  });
30517
30517
 
30518
- // src/agent/xmlParsingUtils.js
30519
- function removeThinkingTags(xmlString) {
30520
- let result = xmlString;
30521
- result = result.replace(/<thinking>[\s\S]*?<\/thinking>/g, "");
30522
- const thinkingIndex = result.indexOf("<thinking>");
30523
- if (thinkingIndex !== -1) {
30524
- const afterThinking = result.substring(thinkingIndex + "<thinking>".length);
30525
- const toolPattern = /<(search|query|extract|listFiles|searchFiles|implement|attempt_completion|attempt_complete)>/;
30526
- const toolMatch = afterThinking.match(toolPattern);
30527
- if (toolMatch) {
30528
- const toolStart = thinkingIndex + "<thinking>".length + toolMatch.index;
30529
- result = result.substring(0, thinkingIndex) + result.substring(toolStart);
30530
- } else {
30531
- result = result.substring(0, thinkingIndex);
30532
- }
30533
- }
30534
- return result.trim();
30535
- }
30536
- function extractThinkingContent(xmlString) {
30537
- const thinkingMatch = xmlString.match(/<thinking>([\s\S]*?)<\/thinking>/);
30538
- return thinkingMatch ? thinkingMatch[1].trim() : null;
30539
- }
30540
- function checkAttemptCompleteRecovery(cleanedXmlString, validTools = []) {
30541
- const openTagIndex = cleanedXmlString.indexOf("<attempt_completion>");
30542
- if (openTagIndex !== -1) {
30543
- const afterOpenTag = cleanedXmlString.substring(openTagIndex + "<attempt_completion>".length);
30544
- const closeTagIndex = cleanedXmlString.lastIndexOf("</attempt_completion>");
30545
- let content;
30546
- let hasClosingTag = false;
30547
- if (closeTagIndex !== -1 && closeTagIndex >= openTagIndex + "<attempt_completion>".length) {
30548
- content = cleanedXmlString.substring(
30549
- openTagIndex + "<attempt_completion>".length,
30550
- closeTagIndex
30551
- ).trim();
30552
- hasClosingTag = true;
30553
- } else {
30554
- content = afterOpenTag.trim();
30555
- hasClosingTag = false;
30556
- }
30557
- if (content) {
30558
- return {
30559
- toolName: "attempt_completion",
30560
- params: { result: content }
30561
- };
30562
- }
30563
- return {
30564
- toolName: "attempt_completion",
30565
- params: { result: hasClosingTag ? "" : "__PREVIOUS_RESPONSE__" }
30566
- };
30567
- }
30568
- const attemptCompletePatterns = [
30569
- // Standard shorthand with optional whitespace
30570
- /^<attempt_complete>\s*$/,
30571
- // Empty with proper closing tag (common case from the logs)
30572
- /^<attempt_complete>\s*<\/attempt_complete>\s*$/,
30573
- // Self-closing variant
30574
- /^<attempt_complete\s*\/>\s*$/,
30575
- // Incomplete opening tag (missing closing bracket)
30576
- /^<attempt_complete\s*$/,
30577
- // With trailing content (extract just the tag part) - must come after empty tag pattern
30578
- /^<attempt_complete>(.*)$/s,
30579
- // Self-closing with trailing content
30580
- /^<attempt_complete\s*\/>(.*)$/s
30581
- ];
30582
- for (const pattern of attemptCompletePatterns) {
30583
- const match2 = cleanedXmlString.match(pattern);
30584
- if (match2) {
30585
- return {
30586
- toolName: "attempt_completion",
30587
- params: { result: "__PREVIOUS_RESPONSE__" }
30588
- };
30589
- }
30590
- }
30591
- if (cleanedXmlString.includes("<attempt_complete") && !hasOtherToolTags(cleanedXmlString, validTools)) {
30592
- return {
30593
- toolName: "attempt_completion",
30594
- params: { result: "__PREVIOUS_RESPONSE__" }
30595
- };
30596
- }
30597
- return null;
30598
- }
30599
- function hasOtherToolTags(xmlString, validTools = []) {
30600
- const defaultTools = ["search", "query", "extract", "listFiles", "searchFiles", "implement", "attempt_completion"];
30601
- const toolsToCheck = validTools.length > 0 ? validTools : defaultTools;
30602
- for (const tool4 of toolsToCheck) {
30603
- if (tool4 !== "attempt_completion" && xmlString.includes(`<${tool4}`)) {
30604
- return true;
30605
- }
30606
- }
30607
- return false;
30608
- }
30609
- function processXmlWithThinkingAndRecovery(xmlString, validTools = []) {
30610
- const thinkingContent = extractThinkingContent(xmlString);
30611
- const cleanedXmlString = removeThinkingTags(xmlString);
30612
- const recoveryResult = checkAttemptCompleteRecovery(cleanedXmlString, validTools);
30613
- if (process.env.DEBUG === "1" && thinkingContent) {
30614
- console.log(`[DEBUG] AI Thinking Process:
30615
- ${thinkingContent}`);
30616
- }
30617
- return {
30618
- cleanedXmlString,
30619
- thinkingContent,
30620
- recoveryResult
30621
- };
30622
- }
30623
- var init_xmlParsingUtils = __esm({
30624
- "src/agent/xmlParsingUtils.js"() {
30625
- "use strict";
30626
- }
30627
- });
30628
-
30629
- // src/agent/tools.js
30630
- function createTools(configOptions) {
30631
- const tools2 = {};
30632
- const isToolAllowed = configOptions.isToolAllowed || ((toolName) => {
30633
- if (!configOptions.allowedTools) return true;
30634
- return configOptions.allowedTools.isEnabled(toolName);
30635
- });
30636
- if (isToolAllowed("search")) {
30637
- tools2.searchTool = searchTool(configOptions);
30638
- }
30639
- if (isToolAllowed("query")) {
30640
- tools2.queryTool = queryTool(configOptions);
30641
- }
30642
- if (isToolAllowed("extract")) {
30643
- tools2.extractTool = extractTool(configOptions);
30644
- }
30645
- if (configOptions.enableDelegate && isToolAllowed("delegate")) {
30646
- tools2.delegateTool = delegateTool(configOptions);
30647
- }
30648
- if (configOptions.enableBash && isToolAllowed("bash")) {
30649
- tools2.bashTool = bashTool(configOptions);
30650
- }
30651
- if (configOptions.allowEdit && isToolAllowed("edit")) {
30652
- tools2.editTool = editTool(configOptions);
30653
- }
30654
- if (configOptions.allowEdit && isToolAllowed("create")) {
30655
- tools2.createTool = createTool(configOptions);
30656
- }
30657
- return tools2;
30658
- }
30659
- function parseXmlToolCallWithThinking(xmlString, validTools) {
30660
- const { cleanedXmlString, recoveryResult } = processXmlWithThinkingAndRecovery(xmlString, validTools);
30661
- if (recoveryResult) {
30662
- return recoveryResult;
30663
- }
30664
- return parseXmlToolCall(cleanedXmlString, validTools);
30665
- }
30666
- var import_crypto2, implementToolDefinition, listFilesToolDefinition, searchFilesToolDefinition, readImageToolDefinition;
30667
- var init_tools = __esm({
30668
- "src/agent/tools.js"() {
30669
- "use strict";
30670
- init_index();
30671
- import_crypto2 = require("crypto");
30672
- init_xmlParsingUtils();
30673
- implementToolDefinition = `
30674
- ## implement
30675
- Description: Implement a given task. Can modify files. Can be used ONLY if task explicitly stated that something requires modification or implementation.
30676
-
30677
- Parameters:
30678
- - task: (required) The task description. Should be as detailed as possible, ideally pointing to exact files which needs be modified or created.
30679
- - autoCommits: (optional) Whether to enable auto-commits in aider. Default is false.
30680
-
30681
- Usage Example:
30682
-
30683
- <examples>
30684
-
30685
- User: Can you implement a function to calculate Fibonacci numbers in main.js?
30686
- <implement>
30687
- <task>Implement a recursive function to calculate the nth Fibonacci number in main.js</task>
30688
- </implement>
30689
-
30690
- User: Can you implement a function to calculate Fibonacci numbers in main.js with auto-commits?
30691
- <implement>
30692
- <task>Implement a recursive function to calculate the nth Fibonacci number in main.js</task>
30693
- <autoCommits>true</autoCommits>
30694
- </implement>
30695
-
30696
- </examples>
30697
- `;
30698
- listFilesToolDefinition = `
30699
- ## listFiles
30700
- Description: List files and directories in a specified location.
30701
-
30702
- Parameters:
30703
- - directory: (optional) The directory path to list files from. Defaults to current directory if not specified.
30704
-
30705
- Usage Example:
30706
-
30707
- <examples>
30708
-
30709
- User: Can you list the files in the src directory?
30710
- <listFiles>
30711
- <directory>src</directory>
30712
- </listFiles>
30713
-
30714
- User: What files are in the current directory?
30715
- <listFiles>
30716
- </listFiles>
30717
-
30718
- </examples>
30719
- `;
30720
- searchFilesToolDefinition = `
30721
- ## searchFiles
30722
- Description: Find files with name matching a glob pattern with recursive search capability.
30723
-
30724
- Parameters:
30725
- - pattern: (required) The glob pattern to search for (e.g., "**/*.js", "*.md").
30726
- - directory: (optional) The directory to search in. Defaults to current directory if not specified.
30727
- - recursive: (optional) Whether to search recursively. Defaults to true.
30728
-
30729
- Usage Example:
30730
-
30731
- <examples>
30732
-
30733
- User: Can you find all JavaScript files in the project?
30734
- <searchFiles>
30735
- <pattern>**/*.js</pattern>
30736
- </searchFiles>
30737
-
30738
- User: Find all markdown files in the docs directory, but only at the top level.
30739
- <searchFiles>
30740
- <pattern>*.md</pattern>
30741
- <directory>docs</directory>
30742
- <recursive>false</recursive>
30743
- </searchFiles>
30744
-
30745
- </examples>
30746
- `;
30747
- readImageToolDefinition = `
30748
- ## readImage
30749
- Description: Read and load an image file so it can be viewed by the AI. Use this when you need to analyze, describe, or work with image content. Images from user messages are automatically loaded, but use this tool to explicitly read images mentioned in tool outputs or when you need to examine specific image files.
30750
-
30751
- Parameters:
30752
- - path: (required) The path to the image file to read. Supports png, jpg, jpeg, webp, bmp, and svg formats.
30753
-
30754
- Usage Example:
30755
-
30756
- <examples>
30757
-
30758
- User: Can you describe what's in screenshot.png?
30759
- <readImage>
30760
- <path>screenshot.png</path>
30761
- </readImage>
30762
-
30763
- User: Analyze the diagram in docs/architecture.svg
30764
- <readImage>
30765
- <path>docs/architecture.svg</path>
30766
- </readImage>
30767
-
30768
- </examples>
30769
- `;
30770
- }
30771
- });
30772
-
30773
30518
  // node_modules/zod/v3/helpers/util.js
30774
30519
  var util, objectUtil, ZodParsedType, getParsedType;
30775
30520
  var init_util2 = __esm({
@@ -34876,7 +34621,332 @@ var init_zod = __esm({
34876
34621
  }
34877
34622
  });
34878
34623
 
34624
+ // src/tools/edit.js
34625
+ function isPathAllowed(filePath, allowedFolders) {
34626
+ if (!allowedFolders || allowedFolders.length === 0) {
34627
+ const resolvedPath3 = (0, import_path5.resolve)(filePath);
34628
+ const cwd = (0, import_path5.resolve)(process.cwd());
34629
+ return resolvedPath3 === cwd || resolvedPath3.startsWith(cwd + import_path5.sep);
34630
+ }
34631
+ const resolvedPath2 = (0, import_path5.resolve)(filePath);
34632
+ return allowedFolders.some((folder) => {
34633
+ const allowedPath = (0, import_path5.resolve)(folder);
34634
+ return resolvedPath2 === allowedPath || resolvedPath2.startsWith(allowedPath + import_path5.sep);
34635
+ });
34636
+ }
34637
+ function parseFileToolOptions(options = {}) {
34638
+ return {
34639
+ debug: options.debug || false,
34640
+ allowedFolders: options.allowedFolders || [],
34641
+ cwd: options.cwd
34642
+ };
34643
+ }
34644
+ var import_ai, import_fs4, import_path5, import_fs5, editTool, createTool, editSchema, createSchema, editDescription, createDescription, editToolDefinition, createToolDefinition;
34645
+ var init_edit = __esm({
34646
+ "src/tools/edit.js"() {
34647
+ "use strict";
34648
+ import_ai = require("ai");
34649
+ import_fs4 = require("fs");
34650
+ import_path5 = require("path");
34651
+ import_fs5 = require("fs");
34652
+ editTool = (options = {}) => {
34653
+ const { debug, allowedFolders, cwd } = parseFileToolOptions(options);
34654
+ return (0, import_ai.tool)({
34655
+ name: "edit",
34656
+ description: `Edit files using exact string replacement (Claude Code style).
34657
+
34658
+ 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.
34659
+
34660
+ Parameters:
34661
+ - file_path: Path to the file to edit (absolute or relative)
34662
+ - old_string: Exact text to find and replace (must be unique in the file unless replace_all is true)
34663
+ - new_string: Text to replace with
34664
+ - replace_all: (optional) Replace all occurrences instead of requiring uniqueness
34665
+
34666
+ Important:
34667
+ - The old_string must match EXACTLY including whitespace
34668
+ - If old_string appears multiple times and replace_all is false, the edit will fail
34669
+ - Use larger context around the string to ensure uniqueness when needed`,
34670
+ inputSchema: {
34671
+ type: "object",
34672
+ properties: {
34673
+ file_path: {
34674
+ type: "string",
34675
+ description: "Path to the file to edit"
34676
+ },
34677
+ old_string: {
34678
+ type: "string",
34679
+ description: "Exact text to find and replace"
34680
+ },
34681
+ new_string: {
34682
+ type: "string",
34683
+ description: "Text to replace with"
34684
+ },
34685
+ replace_all: {
34686
+ type: "boolean",
34687
+ description: "Replace all occurrences (default: false)",
34688
+ default: false
34689
+ }
34690
+ },
34691
+ required: ["file_path", "old_string", "new_string"]
34692
+ },
34693
+ execute: async ({ file_path, old_string, new_string, replace_all = false }) => {
34694
+ try {
34695
+ if (!file_path || typeof file_path !== "string" || file_path.trim() === "") {
34696
+ return `Error editing file: Invalid file_path - must be a non-empty string`;
34697
+ }
34698
+ if (old_string === void 0 || old_string === null || typeof old_string !== "string") {
34699
+ return `Error editing file: Invalid old_string - must be a string`;
34700
+ }
34701
+ if (new_string === void 0 || new_string === null || typeof new_string !== "string") {
34702
+ return `Error editing file: Invalid new_string - must be a string`;
34703
+ }
34704
+ const resolvedPath2 = (0, import_path5.isAbsolute)(file_path) ? file_path : (0, import_path5.resolve)(cwd || process.cwd(), file_path);
34705
+ if (debug) {
34706
+ console.error(`[Edit] Attempting to edit file: ${resolvedPath2}`);
34707
+ }
34708
+ if (!isPathAllowed(resolvedPath2, allowedFolders)) {
34709
+ return `Error editing file: Permission denied - ${file_path} is outside allowed directories`;
34710
+ }
34711
+ if (!(0, import_fs5.existsSync)(resolvedPath2)) {
34712
+ return `Error editing file: File not found - ${file_path}`;
34713
+ }
34714
+ const content = await import_fs4.promises.readFile(resolvedPath2, "utf-8");
34715
+ if (!content.includes(old_string)) {
34716
+ return `Error editing file: String not found - the specified old_string was not found in ${file_path}`;
34717
+ }
34718
+ const occurrences = content.split(old_string).length - 1;
34719
+ if (!replace_all && occurrences > 1) {
34720
+ 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.`;
34721
+ }
34722
+ let newContent;
34723
+ if (replace_all) {
34724
+ newContent = content.replaceAll(old_string, new_string);
34725
+ } else {
34726
+ newContent = content.replace(old_string, new_string);
34727
+ }
34728
+ if (newContent === content) {
34729
+ return `Error editing file: No changes made - old_string and new_string might be the same`;
34730
+ }
34731
+ await import_fs4.promises.writeFile(resolvedPath2, newContent, "utf-8");
34732
+ const replacedCount = replace_all ? occurrences : 1;
34733
+ if (debug) {
34734
+ console.error(`[Edit] Successfully edited ${resolvedPath2}, replaced ${replacedCount} occurrence(s)`);
34735
+ }
34736
+ return `Successfully edited ${file_path} (${replacedCount} replacement${replacedCount !== 1 ? "s" : ""})`;
34737
+ } catch (error2) {
34738
+ console.error("[Edit] Error:", error2);
34739
+ return `Error editing file: ${error2.message}`;
34740
+ }
34741
+ }
34742
+ });
34743
+ };
34744
+ createTool = (options = {}) => {
34745
+ const { debug, allowedFolders, cwd } = parseFileToolOptions(options);
34746
+ return (0, import_ai.tool)({
34747
+ name: "create",
34748
+ description: `Create new files with specified content.
34749
+
34750
+ This tool creates new files in the filesystem. It will create parent directories if they don't exist.
34751
+
34752
+ Parameters:
34753
+ - file_path: Path where the file should be created (absolute or relative)
34754
+ - content: Content to write to the file
34755
+ - overwrite: (optional) Whether to overwrite if file exists (default: false)
34756
+
34757
+ Important:
34758
+ - By default, will fail if the file already exists
34759
+ - Set overwrite: true to replace existing files
34760
+ - Parent directories will be created automatically if needed`,
34761
+ inputSchema: {
34762
+ type: "object",
34763
+ properties: {
34764
+ file_path: {
34765
+ type: "string",
34766
+ description: "Path where the file should be created"
34767
+ },
34768
+ content: {
34769
+ type: "string",
34770
+ description: "Content to write to the file"
34771
+ },
34772
+ overwrite: {
34773
+ type: "boolean",
34774
+ description: "Overwrite if file exists (default: false)",
34775
+ default: false
34776
+ }
34777
+ },
34778
+ required: ["file_path", "content"]
34779
+ },
34780
+ execute: async ({ file_path, content, overwrite = false }) => {
34781
+ try {
34782
+ if (!file_path || typeof file_path !== "string" || file_path.trim() === "") {
34783
+ return `Error creating file: Invalid file_path - must be a non-empty string`;
34784
+ }
34785
+ if (content === void 0 || content === null || typeof content !== "string") {
34786
+ return `Error creating file: Invalid content - must be a string`;
34787
+ }
34788
+ const resolvedPath2 = (0, import_path5.isAbsolute)(file_path) ? file_path : (0, import_path5.resolve)(cwd || process.cwd(), file_path);
34789
+ if (debug) {
34790
+ console.error(`[Create] Attempting to create file: ${resolvedPath2}`);
34791
+ }
34792
+ if (!isPathAllowed(resolvedPath2, allowedFolders)) {
34793
+ return `Error creating file: Permission denied - ${file_path} is outside allowed directories`;
34794
+ }
34795
+ if ((0, import_fs5.existsSync)(resolvedPath2) && !overwrite) {
34796
+ return `Error creating file: File already exists - ${file_path}. Use overwrite: true to replace it.`;
34797
+ }
34798
+ const dir = (0, import_path5.dirname)(resolvedPath2);
34799
+ await import_fs4.promises.mkdir(dir, { recursive: true });
34800
+ await import_fs4.promises.writeFile(resolvedPath2, content, "utf-8");
34801
+ const action = (0, import_fs5.existsSync)(resolvedPath2) && overwrite ? "overwrote" : "created";
34802
+ const bytes = Buffer.byteLength(content, "utf-8");
34803
+ if (debug) {
34804
+ console.error(`[Create] Successfully ${action} ${resolvedPath2}`);
34805
+ }
34806
+ return `Successfully ${action} ${file_path} (${bytes} bytes)`;
34807
+ } catch (error2) {
34808
+ console.error("[Create] Error:", error2);
34809
+ return `Error creating file: ${error2.message}`;
34810
+ }
34811
+ }
34812
+ });
34813
+ };
34814
+ editSchema = {
34815
+ type: "object",
34816
+ properties: {
34817
+ file_path: {
34818
+ type: "string",
34819
+ description: "Path to the file to edit"
34820
+ },
34821
+ old_string: {
34822
+ type: "string",
34823
+ description: "Exact text to find and replace"
34824
+ },
34825
+ new_string: {
34826
+ type: "string",
34827
+ description: "Text to replace with"
34828
+ },
34829
+ replace_all: {
34830
+ type: "boolean",
34831
+ description: "Replace all occurrences (default: false)"
34832
+ }
34833
+ },
34834
+ required: ["file_path", "old_string", "new_string"]
34835
+ };
34836
+ createSchema = {
34837
+ type: "object",
34838
+ properties: {
34839
+ file_path: {
34840
+ type: "string",
34841
+ description: "Path where the file should be created"
34842
+ },
34843
+ content: {
34844
+ type: "string",
34845
+ description: "Content to write to the file"
34846
+ },
34847
+ overwrite: {
34848
+ type: "boolean",
34849
+ description: "Overwrite if file exists (default: false)"
34850
+ }
34851
+ },
34852
+ required: ["file_path", "content"]
34853
+ };
34854
+ editDescription = "Edit files using exact string replacement. Requires exact match including whitespace.";
34855
+ createDescription = "Create new files with specified content. Will create parent directories if needed.";
34856
+ editToolDefinition = `
34857
+ ## edit
34858
+ Description: ${editDescription}
34859
+
34860
+ When to use:
34861
+ - For precise, surgical edits to existing files
34862
+ - When you need to change specific lines or blocks of code
34863
+ - For renaming functions, variables, or updating configuration values
34864
+ - When the exact text to replace is known and unique (or use replace_all for multiple occurrences)
34865
+
34866
+ When NOT to use:
34867
+ - For creating new files (use 'create' tool instead)
34868
+ - When you cannot determine the exact text to replace
34869
+ - When changes span multiple locations that would be better handled together
34870
+
34871
+ Parameters:
34872
+ - file_path: (required) Path to the file to edit
34873
+ - old_string: (required) Exact text to find and replace (must match including whitespace, newlines, and indentation)
34874
+ - new_string: (required) Text to replace with
34875
+ - replace_all: (optional, default: false) Replace all occurrences if the string appears multiple times
34876
+
34877
+ Important notes:
34878
+ - The old_string MUST match EXACTLY, including all whitespace, indentation, and line breaks
34879
+ - If old_string appears multiple times and replace_all is false, the tool will fail
34880
+ - Always verify the exact formatting of the text you want to replace
34881
+
34882
+ Examples:
34883
+ <edit>
34884
+ <file_path>src/main.js</file_path>
34885
+ <old_string>function oldName() {
34886
+ return 42;
34887
+ }</old_string>
34888
+ <new_string>function newName() {
34889
+ return 42;
34890
+ }</new_string>
34891
+ </edit>
34892
+
34893
+ <edit>
34894
+ <file_path>config.json</file_path>
34895
+ <old_string>"debug": false</old_string>
34896
+ <new_string>"debug": true</new_string>
34897
+ <replace_all>true</replace_all>
34898
+ </edit>`;
34899
+ createToolDefinition = `
34900
+ ## create
34901
+ Description: ${createDescription}
34902
+
34903
+ When to use:
34904
+ - For creating brand new files from scratch
34905
+ - When you need to add configuration files, documentation, or new modules
34906
+ - For generating boilerplate code or templates
34907
+ - When you have the complete content ready to write
34908
+
34909
+ When NOT to use:
34910
+ - For editing existing files (use 'edit' tool instead)
34911
+ - When a file already exists unless you explicitly want to overwrite it
34912
+
34913
+ Parameters:
34914
+ - file_path: (required) Path where the file should be created
34915
+ - content: (required) Complete content to write to the file
34916
+ - overwrite: (optional, default: false) Whether to overwrite if file already exists
34917
+
34918
+ Important notes:
34919
+ - Parent directories will be created automatically if they don't exist
34920
+ - The tool will fail if the file already exists and overwrite is false
34921
+ - Be careful with the overwrite option as it completely replaces existing files
34922
+
34923
+ Examples:
34924
+ <create>
34925
+ <file_path>src/newFile.js</file_path>
34926
+ <content>export function hello() {
34927
+ return "Hello, world!";
34928
+ }</content>
34929
+ </create>
34930
+
34931
+ <create>
34932
+ <file_path>README.md</file_path>
34933
+ <content># My Project
34934
+
34935
+ This is a new project.</content>
34936
+ <overwrite>true</overwrite>
34937
+ </create>`;
34938
+ }
34939
+ });
34940
+
34879
34941
  // src/tools/common.js
34942
+ function buildToolTagPattern(tools2 = DEFAULT_VALID_TOOLS) {
34943
+ const allTools = [...tools2];
34944
+ if (allTools.includes("attempt_completion") && !allTools.includes("attempt_complete")) {
34945
+ allTools.push("attempt_complete");
34946
+ }
34947
+ const escaped = allTools.map((t4) => t4.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
34948
+ return new RegExp(`<(${escaped.join("|")})>`);
34949
+ }
34880
34950
  function getValidParamsForTool(toolName) {
34881
34951
  const schemaMap = {
34882
34952
  search: searchSchema,
@@ -34884,7 +34954,9 @@ function getValidParamsForTool(toolName) {
34884
34954
  extract: extractSchema,
34885
34955
  delegate: delegateSchema,
34886
34956
  bash: bashSchema,
34887
- attempt_completion: attemptCompletionSchema
34957
+ attempt_completion: attemptCompletionSchema,
34958
+ edit: editSchema,
34959
+ create: createSchema
34888
34960
  };
34889
34961
  const schema = schemaMap[toolName];
34890
34962
  if (!schema) {
@@ -34893,9 +34965,12 @@ function getValidParamsForTool(toolName) {
34893
34965
  if (toolName === "attempt_completion") {
34894
34966
  return ["result"];
34895
34967
  }
34896
- if (schema && schema._def && schema._def.shape) {
34968
+ if (schema._def && schema._def.shape) {
34897
34969
  return Object.keys(schema._def.shape());
34898
34970
  }
34971
+ if (schema.properties) {
34972
+ return Object.keys(schema.properties);
34973
+ }
34899
34974
  return [];
34900
34975
  }
34901
34976
  function parseXmlToolCall(xmlString, validTools = DEFAULT_VALID_TOOLS) {
@@ -34995,10 +35070,10 @@ function parseAndResolvePaths(pathStr, cwd) {
34995
35070
  if (!pathStr) return [];
34996
35071
  const paths = pathStr.split(",").map((p4) => p4.trim()).filter((p4) => p4.length > 0);
34997
35072
  return paths.map((p4) => {
34998
- if ((0, import_path5.isAbsolute)(p4)) {
35073
+ if ((0, import_path6.isAbsolute)(p4)) {
34999
35074
  return p4;
35000
35075
  }
35001
- return cwd ? (0, import_path5.resolve)(cwd, p4) : p4;
35076
+ return cwd ? (0, import_path6.resolve)(cwd, p4) : p4;
35002
35077
  });
35003
35078
  }
35004
35079
  function resolveTargetPath(target, cwd) {
@@ -35016,17 +35091,18 @@ function resolveTargetPath(target, cwd) {
35016
35091
  filePart = target;
35017
35092
  suffix = "";
35018
35093
  }
35019
- if (!(0, import_path5.isAbsolute)(filePart) && cwd) {
35020
- filePart = (0, import_path5.resolve)(cwd, filePart);
35094
+ if (!(0, import_path6.isAbsolute)(filePart) && cwd) {
35095
+ filePart = (0, import_path6.resolve)(cwd, filePart);
35021
35096
  }
35022
35097
  return filePart + suffix;
35023
35098
  }
35024
- var import_path5, searchSchema, querySchema, extractSchema, delegateSchema, bashSchema, attemptCompletionSchema, searchToolDefinition, queryToolDefinition, extractToolDefinition, delegateToolDefinition, attemptCompletionToolDefinition, bashToolDefinition, searchDescription, queryDescription, extractDescription, delegateDescription, bashDescription, DEFAULT_VALID_TOOLS;
35099
+ var import_path6, searchSchema, querySchema, extractSchema, delegateSchema, bashSchema, attemptCompletionSchema, searchToolDefinition, queryToolDefinition, extractToolDefinition, delegateToolDefinition, attemptCompletionToolDefinition, bashToolDefinition, searchDescription, queryDescription, extractDescription, delegateDescription, bashDescription, DEFAULT_VALID_TOOLS;
35025
35100
  var init_common2 = __esm({
35026
35101
  "src/tools/common.js"() {
35027
35102
  "use strict";
35028
35103
  init_zod();
35029
- import_path5 = require("path");
35104
+ import_path6 = require("path");
35105
+ init_edit();
35030
35106
  searchSchema = external_exports.object({
35031
35107
  query: external_exports.string().describe("Search query with Elasticsearch syntax. Use quotes for exact matches, AND/OR for boolean logic, - for negation."),
35032
35108
  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.')
@@ -35328,11 +35404,267 @@ User: Check system info
35328
35404
  "listFiles",
35329
35405
  "searchFiles",
35330
35406
  "implement",
35407
+ "bash",
35331
35408
  "attempt_completion"
35332
35409
  ];
35333
35410
  }
35334
35411
  });
35335
35412
 
35413
+ // src/agent/xmlParsingUtils.js
35414
+ function removeThinkingTags(xmlString) {
35415
+ let result = xmlString;
35416
+ result = result.replace(/<thinking>[\s\S]*?<\/thinking>/g, "");
35417
+ const thinkingIndex = result.indexOf("<thinking>");
35418
+ if (thinkingIndex !== -1) {
35419
+ const afterThinking = result.substring(thinkingIndex + "<thinking>".length);
35420
+ const toolPattern = buildToolTagPattern(DEFAULT_VALID_TOOLS);
35421
+ const toolMatch = afterThinking.match(toolPattern);
35422
+ if (toolMatch) {
35423
+ const toolStart = thinkingIndex + "<thinking>".length + toolMatch.index;
35424
+ result = result.substring(0, thinkingIndex) + result.substring(toolStart);
35425
+ } else {
35426
+ result = result.substring(0, thinkingIndex);
35427
+ }
35428
+ }
35429
+ return result.trim();
35430
+ }
35431
+ function extractThinkingContent(xmlString) {
35432
+ const thinkingMatch = xmlString.match(/<thinking>([\s\S]*?)<\/thinking>/);
35433
+ return thinkingMatch ? thinkingMatch[1].trim() : null;
35434
+ }
35435
+ function checkAttemptCompleteRecovery(cleanedXmlString, validTools = []) {
35436
+ const openTagIndex = cleanedXmlString.indexOf("<attempt_completion>");
35437
+ if (openTagIndex !== -1) {
35438
+ const afterOpenTag = cleanedXmlString.substring(openTagIndex + "<attempt_completion>".length);
35439
+ const closeTagIndex = cleanedXmlString.lastIndexOf("</attempt_completion>");
35440
+ let content;
35441
+ let hasClosingTag = false;
35442
+ if (closeTagIndex !== -1 && closeTagIndex >= openTagIndex + "<attempt_completion>".length) {
35443
+ content = cleanedXmlString.substring(
35444
+ openTagIndex + "<attempt_completion>".length,
35445
+ closeTagIndex
35446
+ ).trim();
35447
+ hasClosingTag = true;
35448
+ } else {
35449
+ content = afterOpenTag.trim();
35450
+ hasClosingTag = false;
35451
+ }
35452
+ if (content) {
35453
+ return {
35454
+ toolName: "attempt_completion",
35455
+ params: { result: content }
35456
+ };
35457
+ }
35458
+ return {
35459
+ toolName: "attempt_completion",
35460
+ params: { result: hasClosingTag ? "" : "__PREVIOUS_RESPONSE__" }
35461
+ };
35462
+ }
35463
+ const attemptCompletePatterns = [
35464
+ // Standard shorthand with optional whitespace
35465
+ /^<attempt_complete>\s*$/,
35466
+ // Empty with proper closing tag (common case from the logs)
35467
+ /^<attempt_complete>\s*<\/attempt_complete>\s*$/,
35468
+ // Self-closing variant
35469
+ /^<attempt_complete\s*\/>\s*$/,
35470
+ // Incomplete opening tag (missing closing bracket)
35471
+ /^<attempt_complete\s*$/,
35472
+ // With trailing content (extract just the tag part) - must come after empty tag pattern
35473
+ /^<attempt_complete>(.*)$/s,
35474
+ // Self-closing with trailing content
35475
+ /^<attempt_complete\s*\/>(.*)$/s
35476
+ ];
35477
+ for (const pattern of attemptCompletePatterns) {
35478
+ const match2 = cleanedXmlString.match(pattern);
35479
+ if (match2) {
35480
+ return {
35481
+ toolName: "attempt_completion",
35482
+ params: { result: "__PREVIOUS_RESPONSE__" }
35483
+ };
35484
+ }
35485
+ }
35486
+ if (cleanedXmlString.includes("<attempt_complete") && !hasOtherToolTags(cleanedXmlString, validTools)) {
35487
+ return {
35488
+ toolName: "attempt_completion",
35489
+ params: { result: "__PREVIOUS_RESPONSE__" }
35490
+ };
35491
+ }
35492
+ return null;
35493
+ }
35494
+ function hasOtherToolTags(xmlString, validTools = []) {
35495
+ const toolsToCheck = validTools.length > 0 ? validTools : DEFAULT_VALID_TOOLS;
35496
+ for (const tool4 of toolsToCheck) {
35497
+ if (tool4 !== "attempt_completion" && xmlString.includes(`<${tool4}`)) {
35498
+ return true;
35499
+ }
35500
+ }
35501
+ return false;
35502
+ }
35503
+ function processXmlWithThinkingAndRecovery(xmlString, validTools = []) {
35504
+ const thinkingContent = extractThinkingContent(xmlString);
35505
+ const cleanedXmlString = removeThinkingTags(xmlString);
35506
+ const recoveryResult = checkAttemptCompleteRecovery(cleanedXmlString, validTools);
35507
+ if (process.env.DEBUG === "1" && thinkingContent) {
35508
+ console.log(`[DEBUG] AI Thinking Process:
35509
+ ${thinkingContent}`);
35510
+ }
35511
+ return {
35512
+ cleanedXmlString,
35513
+ thinkingContent,
35514
+ recoveryResult
35515
+ };
35516
+ }
35517
+ var init_xmlParsingUtils = __esm({
35518
+ "src/agent/xmlParsingUtils.js"() {
35519
+ "use strict";
35520
+ init_common2();
35521
+ }
35522
+ });
35523
+
35524
+ // src/agent/tools.js
35525
+ function createTools(configOptions) {
35526
+ const tools2 = {};
35527
+ const isToolAllowed = configOptions.isToolAllowed || ((toolName) => {
35528
+ if (!configOptions.allowedTools) return true;
35529
+ return configOptions.allowedTools.isEnabled(toolName);
35530
+ });
35531
+ if (isToolAllowed("search")) {
35532
+ tools2.searchTool = searchTool(configOptions);
35533
+ }
35534
+ if (isToolAllowed("query")) {
35535
+ tools2.queryTool = queryTool(configOptions);
35536
+ }
35537
+ if (isToolAllowed("extract")) {
35538
+ tools2.extractTool = extractTool(configOptions);
35539
+ }
35540
+ if (configOptions.enableDelegate && isToolAllowed("delegate")) {
35541
+ tools2.delegateTool = delegateTool(configOptions);
35542
+ }
35543
+ if (configOptions.enableBash && isToolAllowed("bash")) {
35544
+ tools2.bashTool = bashTool(configOptions);
35545
+ }
35546
+ if (configOptions.allowEdit && isToolAllowed("edit")) {
35547
+ tools2.editTool = editTool(configOptions);
35548
+ }
35549
+ if (configOptions.allowEdit && isToolAllowed("create")) {
35550
+ tools2.createTool = createTool(configOptions);
35551
+ }
35552
+ return tools2;
35553
+ }
35554
+ function parseXmlToolCallWithThinking(xmlString, validTools) {
35555
+ const { cleanedXmlString, recoveryResult } = processXmlWithThinkingAndRecovery(xmlString, validTools);
35556
+ if (recoveryResult) {
35557
+ return recoveryResult;
35558
+ }
35559
+ return parseXmlToolCall(cleanedXmlString, validTools);
35560
+ }
35561
+ var import_crypto2, implementToolDefinition, listFilesToolDefinition, searchFilesToolDefinition, readImageToolDefinition;
35562
+ var init_tools = __esm({
35563
+ "src/agent/tools.js"() {
35564
+ "use strict";
35565
+ init_index();
35566
+ import_crypto2 = require("crypto");
35567
+ init_xmlParsingUtils();
35568
+ implementToolDefinition = `
35569
+ ## implement
35570
+ Description: Implement a given task. Can modify files. Can be used ONLY if task explicitly stated that something requires modification or implementation.
35571
+
35572
+ Parameters:
35573
+ - task: (required) The task description. Should be as detailed as possible, ideally pointing to exact files which needs be modified or created.
35574
+ - autoCommits: (optional) Whether to enable auto-commits in aider. Default is false.
35575
+
35576
+ Usage Example:
35577
+
35578
+ <examples>
35579
+
35580
+ User: Can you implement a function to calculate Fibonacci numbers in main.js?
35581
+ <implement>
35582
+ <task>Implement a recursive function to calculate the nth Fibonacci number in main.js</task>
35583
+ </implement>
35584
+
35585
+ User: Can you implement a function to calculate Fibonacci numbers in main.js with auto-commits?
35586
+ <implement>
35587
+ <task>Implement a recursive function to calculate the nth Fibonacci number in main.js</task>
35588
+ <autoCommits>true</autoCommits>
35589
+ </implement>
35590
+
35591
+ </examples>
35592
+ `;
35593
+ listFilesToolDefinition = `
35594
+ ## listFiles
35595
+ Description: List files and directories in a specified location.
35596
+
35597
+ Parameters:
35598
+ - directory: (optional) The directory path to list files from. Defaults to current directory if not specified.
35599
+
35600
+ Usage Example:
35601
+
35602
+ <examples>
35603
+
35604
+ User: Can you list the files in the src directory?
35605
+ <listFiles>
35606
+ <directory>src</directory>
35607
+ </listFiles>
35608
+
35609
+ User: What files are in the current directory?
35610
+ <listFiles>
35611
+ </listFiles>
35612
+
35613
+ </examples>
35614
+ `;
35615
+ searchFilesToolDefinition = `
35616
+ ## searchFiles
35617
+ Description: Find files with name matching a glob pattern with recursive search capability.
35618
+
35619
+ Parameters:
35620
+ - pattern: (required) The glob pattern to search for (e.g., "**/*.js", "*.md").
35621
+ - directory: (optional) The directory to search in. Defaults to current directory if not specified.
35622
+ - recursive: (optional) Whether to search recursively. Defaults to true.
35623
+
35624
+ Usage Example:
35625
+
35626
+ <examples>
35627
+
35628
+ User: Can you find all JavaScript files in the project?
35629
+ <searchFiles>
35630
+ <pattern>**/*.js</pattern>
35631
+ </searchFiles>
35632
+
35633
+ User: Find all markdown files in the docs directory, but only at the top level.
35634
+ <searchFiles>
35635
+ <pattern>*.md</pattern>
35636
+ <directory>docs</directory>
35637
+ <recursive>false</recursive>
35638
+ </searchFiles>
35639
+
35640
+ </examples>
35641
+ `;
35642
+ readImageToolDefinition = `
35643
+ ## readImage
35644
+ Description: Read and load an image file so it can be viewed by the AI. Use this when you need to analyze, describe, or work with image content. Images from user messages are automatically loaded, but use this tool to explicitly read images mentioned in tool outputs or when you need to examine specific image files.
35645
+
35646
+ Parameters:
35647
+ - path: (required) The path to the image file to read. Supports png, jpg, jpeg, webp, bmp, and svg formats.
35648
+
35649
+ Usage Example:
35650
+
35651
+ <examples>
35652
+
35653
+ User: Can you describe what's in screenshot.png?
35654
+ <readImage>
35655
+ <path>screenshot.png</path>
35656
+ </readImage>
35657
+
35658
+ User: Analyze the diagram in docs/architecture.svg
35659
+ <readImage>
35660
+ <path>docs/architecture.svg</path>
35661
+ </readImage>
35662
+
35663
+ </examples>
35664
+ `;
35665
+ }
35666
+ });
35667
+
35336
35668
  // node_modules/balanced-match/index.js
35337
35669
  var require_balanced_match = __commonJS({
35338
35670
  "node_modules/balanced-match/index.js"(exports2, module2) {
@@ -36178,7 +36510,7 @@ var init_escape = __esm({
36178
36510
  });
36179
36511
 
36180
36512
  // node_modules/minimatch/dist/esm/index.js
36181
- var import_brace_expansion, minimatch, starDotExtRE, starDotExtTest, starDotExtTestDot, starDotExtTestNocase, starDotExtTestNocaseDot, starDotStarRE, starDotStarTest, starDotStarTestDot, dotStarRE, dotStarTest, starRE, starTest, starTestDot, qmarksRE, qmarksTestNocase, qmarksTestNocaseDot, qmarksTestDot, qmarksTest, qmarksTestNoExt, qmarksTestNoExtDot, defaultPlatform, path5, sep, GLOBSTAR, qmark2, star2, twoStarDot, twoStarNoDot, filter, ext, defaults, braceExpand, makeRe, match, globMagic, regExpEscape2, Minimatch;
36513
+ var import_brace_expansion, minimatch, starDotExtRE, starDotExtTest, starDotExtTestDot, starDotExtTestNocase, starDotExtTestNocaseDot, starDotStarRE, starDotStarTest, starDotStarTestDot, dotStarRE, dotStarTest, starRE, starTest, starTestDot, qmarksRE, qmarksTestNocase, qmarksTestNocaseDot, qmarksTestDot, qmarksTest, qmarksTestNoExt, qmarksTestNoExtDot, defaultPlatform, path5, sep2, GLOBSTAR, qmark2, star2, twoStarDot, twoStarNoDot, filter, ext, defaults, braceExpand, makeRe, match, globMagic, regExpEscape2, Minimatch;
36182
36514
  var init_esm = __esm({
36183
36515
  "node_modules/minimatch/dist/esm/index.js"() {
36184
36516
  import_brace_expansion = __toESM(require_brace_expansion(), 1);
@@ -36251,8 +36583,8 @@ var init_esm = __esm({
36251
36583
  win32: { sep: "\\" },
36252
36584
  posix: { sep: "/" }
36253
36585
  };
36254
- sep = defaultPlatform === "win32" ? path5.win32.sep : path5.posix.sep;
36255
- minimatch.sep = sep;
36586
+ sep2 = defaultPlatform === "win32" ? path5.win32.sep : path5.posix.sep;
36587
+ minimatch.sep = sep2;
36256
36588
  GLOBSTAR = Symbol("globstar **");
36257
36589
  minimatch.GLOBSTAR = GLOBSTAR;
36258
36590
  qmark2 = "[^/]";
@@ -39166,22 +39498,22 @@ var init_esm3 = __esm({
39166
39498
  });
39167
39499
 
39168
39500
  // node_modules/path-scurry/dist/esm/index.js
39169
- var import_node_path, import_node_url, import_fs4, actualFS, import_promises, realpathSync, defaultFS, fsFromOption, uncDriveRegexp, uncToDrive, eitherSep, UNKNOWN, IFIFO, IFCHR, IFDIR, IFBLK, IFREG, IFLNK, IFSOCK, IFMT, IFMT_UNKNOWN, READDIR_CALLED, LSTAT_CALLED, ENOTDIR, ENOENT, ENOREADLINK, ENOREALPATH, ENOCHILD, TYPEMASK, entToType, normalizeCache, normalize, normalizeNocaseCache, normalizeNocase, ResolveCache, ChildrenCache, setAsCwd, PathBase, PathWin32, PathPosix, PathScurryBase, PathScurryWin32, PathScurryPosix, PathScurryDarwin, Path, PathScurry;
39501
+ var import_node_path, import_node_url, import_fs6, actualFS, import_promises, realpathSync, defaultFS, fsFromOption, uncDriveRegexp, uncToDrive, eitherSep, UNKNOWN, IFIFO, IFCHR, IFDIR, IFBLK, IFREG, IFLNK, IFSOCK, IFMT, IFMT_UNKNOWN, READDIR_CALLED, LSTAT_CALLED, ENOTDIR, ENOENT, ENOREADLINK, ENOREALPATH, ENOCHILD, TYPEMASK, entToType, normalizeCache, normalize, normalizeNocaseCache, normalizeNocase, ResolveCache, ChildrenCache, setAsCwd, PathBase, PathWin32, PathPosix, PathScurryBase, PathScurryWin32, PathScurryPosix, PathScurryDarwin, Path, PathScurry;
39170
39502
  var init_esm4 = __esm({
39171
39503
  "node_modules/path-scurry/dist/esm/index.js"() {
39172
39504
  init_esm2();
39173
39505
  import_node_path = require("node:path");
39174
39506
  import_node_url = require("node:url");
39175
- import_fs4 = require("fs");
39507
+ import_fs6 = require("fs");
39176
39508
  actualFS = __toESM(require("node:fs"), 1);
39177
39509
  import_promises = require("node:fs/promises");
39178
39510
  init_esm3();
39179
- realpathSync = import_fs4.realpathSync.native;
39511
+ realpathSync = import_fs6.realpathSync.native;
39180
39512
  defaultFS = {
39181
- lstatSync: import_fs4.lstatSync,
39182
- readdir: import_fs4.readdir,
39183
- readdirSync: import_fs4.readdirSync,
39184
- readlinkSync: import_fs4.readlinkSync,
39513
+ lstatSync: import_fs6.lstatSync,
39514
+ readdir: import_fs6.readdir,
39515
+ readdirSync: import_fs6.readdirSync,
39516
+ readlinkSync: import_fs6.readlinkSync,
39185
39517
  realpathSync,
39186
39518
  promises: {
39187
39519
  lstat: import_promises.lstat,
@@ -42090,7 +42422,7 @@ function createWrappedTools(baseTools) {
42090
42422
  }
42091
42423
  return wrappedTools;
42092
42424
  }
42093
- var import_child_process6, import_util11, import_crypto3, import_events, import_fs5, import_fs6, import_path6, toolCallEmitter, activeToolExecutions, wrapToolWithEmitter, listFilesTool, searchFilesTool, listFilesToolInstance, searchFilesToolInstance;
42425
+ var import_child_process6, import_util11, import_crypto3, import_events, import_fs7, import_fs8, import_path7, toolCallEmitter, activeToolExecutions, wrapToolWithEmitter, listFilesTool, searchFilesTool, listFilesToolInstance, searchFilesToolInstance;
42094
42426
  var init_probeTool = __esm({
42095
42427
  "src/agent/probeTool.js"() {
42096
42428
  "use strict";
@@ -42099,9 +42431,9 @@ var init_probeTool = __esm({
42099
42431
  import_util11 = require("util");
42100
42432
  import_crypto3 = require("crypto");
42101
42433
  import_events = require("events");
42102
- import_fs5 = __toESM(require("fs"), 1);
42103
- import_fs6 = require("fs");
42104
- import_path6 = __toESM(require("path"), 1);
42434
+ import_fs7 = __toESM(require("fs"), 1);
42435
+ import_fs8 = require("fs");
42436
+ import_path7 = __toESM(require("path"), 1);
42105
42437
  init_esm5();
42106
42438
  init_symlink_utils();
42107
42439
  toolCallEmitter = new import_events.EventEmitter();
@@ -42190,17 +42522,17 @@ var init_probeTool = __esm({
42190
42522
  execute: async (params) => {
42191
42523
  const { directory = ".", workingDirectory } = params;
42192
42524
  const baseCwd = workingDirectory || process.cwd();
42193
- const secureBaseDir = import_path6.default.resolve(baseCwd);
42525
+ const secureBaseDir = import_path7.default.resolve(baseCwd);
42194
42526
  const isDependencyPath = directory.startsWith("/dep/") || directory.startsWith("go:") || directory.startsWith("js:") || directory.startsWith("rust:");
42195
42527
  let targetDir;
42196
- if (import_path6.default.isAbsolute(directory)) {
42197
- targetDir = import_path6.default.resolve(directory);
42198
- if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path6.default.sep) && targetDir !== secureBaseDir) {
42528
+ if (import_path7.default.isAbsolute(directory)) {
42529
+ targetDir = import_path7.default.resolve(directory);
42530
+ if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path7.default.sep) && targetDir !== secureBaseDir) {
42199
42531
  throw new Error(`Path traversal attempt detected. Cannot access directory outside workspace: ${directory}`);
42200
42532
  }
42201
42533
  } else {
42202
- targetDir = import_path6.default.resolve(secureBaseDir, directory);
42203
- if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path6.default.sep) && targetDir !== secureBaseDir) {
42534
+ targetDir = import_path7.default.resolve(secureBaseDir, directory);
42535
+ if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path7.default.sep) && targetDir !== secureBaseDir) {
42204
42536
  throw new Error(`Path traversal attempt detected. Access denied: ${directory}`);
42205
42537
  }
42206
42538
  }
@@ -42209,7 +42541,7 @@ var init_probeTool = __esm({
42209
42541
  console.log(`[DEBUG] Listing files in directory: ${targetDir}`);
42210
42542
  }
42211
42543
  try {
42212
- const files = await import_fs6.promises.readdir(targetDir, { withFileTypes: true });
42544
+ const files = await import_fs8.promises.readdir(targetDir, { withFileTypes: true });
42213
42545
  const formatSize = (size) => {
42214
42546
  if (size < 1024) return `${size}B`;
42215
42547
  if (size < 1024 * 1024) return `${(size / 1024).toFixed(1)}K`;
@@ -42217,7 +42549,7 @@ var init_probeTool = __esm({
42217
42549
  return `${(size / (1024 * 1024 * 1024)).toFixed(1)}G`;
42218
42550
  };
42219
42551
  const entries = await Promise.all(files.map(async (file) => {
42220
- const fullPath = import_path6.default.join(targetDir, file.name);
42552
+ const fullPath = import_path7.default.join(targetDir, file.name);
42221
42553
  const entryType = await getEntryType(file, fullPath);
42222
42554
  return {
42223
42555
  name: file.name,
@@ -42254,17 +42586,17 @@ var init_probeTool = __esm({
42254
42586
  throw new Error("Pattern is required for file search");
42255
42587
  }
42256
42588
  const baseCwd = workingDirectory || process.cwd();
42257
- const secureBaseDir = import_path6.default.resolve(baseCwd);
42589
+ const secureBaseDir = import_path7.default.resolve(baseCwd);
42258
42590
  const isDependencyPath = directory.startsWith("/dep/") || directory.startsWith("go:") || directory.startsWith("js:") || directory.startsWith("rust:");
42259
42591
  let targetDir;
42260
- if (import_path6.default.isAbsolute(directory)) {
42261
- targetDir = import_path6.default.resolve(directory);
42262
- if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path6.default.sep) && targetDir !== secureBaseDir) {
42592
+ if (import_path7.default.isAbsolute(directory)) {
42593
+ targetDir = import_path7.default.resolve(directory);
42594
+ if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path7.default.sep) && targetDir !== secureBaseDir) {
42263
42595
  throw new Error(`Path traversal attempt detected. Cannot access directory outside workspace: ${directory}`);
42264
42596
  }
42265
42597
  } else {
42266
- targetDir = import_path6.default.resolve(secureBaseDir, directory);
42267
- if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path6.default.sep) && targetDir !== secureBaseDir) {
42598
+ targetDir = import_path7.default.resolve(secureBaseDir, directory);
42599
+ if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path7.default.sep) && targetDir !== secureBaseDir) {
42268
42600
  throw new Error(`Path traversal attempt detected. Access denied: ${directory}`);
42269
42601
  }
42270
42602
  }
@@ -80589,11 +80921,11 @@ function loadMCPConfigurationFromPath(configPath) {
80589
80921
  if (!configPath) {
80590
80922
  throw new Error("Config path is required");
80591
80923
  }
80592
- if (!(0, import_fs7.existsSync)(configPath)) {
80924
+ if (!(0, import_fs9.existsSync)(configPath)) {
80593
80925
  throw new Error(`MCP configuration file not found: ${configPath}`);
80594
80926
  }
80595
80927
  try {
80596
- const content = (0, import_fs7.readFileSync)(configPath, "utf8");
80928
+ const content = (0, import_fs9.readFileSync)(configPath, "utf8");
80597
80929
  const config = JSON.parse(content);
80598
80930
  if (process.env.DEBUG === "1" || process.env.DEBUG_MCP === "1") {
80599
80931
  console.error(`[MCP DEBUG] Loaded configuration from: ${configPath}`);
@@ -80608,19 +80940,19 @@ function loadMCPConfiguration() {
80608
80940
  // Environment variable path
80609
80941
  process.env.MCP_CONFIG_PATH,
80610
80942
  // Local project paths
80611
- (0, import_path7.join)(process.cwd(), ".mcp", "config.json"),
80612
- (0, import_path7.join)(process.cwd(), "mcp.config.json"),
80943
+ (0, import_path8.join)(process.cwd(), ".mcp", "config.json"),
80944
+ (0, import_path8.join)(process.cwd(), "mcp.config.json"),
80613
80945
  // Home directory paths
80614
- (0, import_path7.join)((0, import_os3.homedir)(), ".config", "probe", "mcp.json"),
80615
- (0, import_path7.join)((0, import_os3.homedir)(), ".mcp", "config.json"),
80946
+ (0, import_path8.join)((0, import_os3.homedir)(), ".config", "probe", "mcp.json"),
80947
+ (0, import_path8.join)((0, import_os3.homedir)(), ".mcp", "config.json"),
80616
80948
  // Claude-style config location
80617
- (0, import_path7.join)((0, import_os3.homedir)(), "Library", "Application Support", "Claude", "mcp_config.json")
80949
+ (0, import_path8.join)((0, import_os3.homedir)(), "Library", "Application Support", "Claude", "mcp_config.json")
80618
80950
  ].filter(Boolean);
80619
80951
  let config = null;
80620
80952
  for (const configPath of configPaths) {
80621
- if ((0, import_fs7.existsSync)(configPath)) {
80953
+ if ((0, import_fs9.existsSync)(configPath)) {
80622
80954
  try {
80623
- const content = (0, import_fs7.readFileSync)(configPath, "utf8");
80955
+ const content = (0, import_fs9.readFileSync)(configPath, "utf8");
80624
80956
  config = JSON.parse(content);
80625
80957
  if (process.env.DEBUG === "1" || process.env.DEBUG_MCP === "1") {
80626
80958
  console.error(`[MCP DEBUG] Loaded configuration from: ${configPath}`);
@@ -80732,16 +81064,16 @@ function parseEnabledServers(config) {
80732
81064
  }
80733
81065
  return servers;
80734
81066
  }
80735
- var import_fs7, import_path7, import_os3, import_url4, __filename4, __dirname4, DEFAULT_TIMEOUT, MAX_TIMEOUT, DEFAULT_CONFIG;
81067
+ var import_fs9, import_path8, import_os3, import_url4, __filename4, __dirname4, DEFAULT_TIMEOUT, MAX_TIMEOUT, DEFAULT_CONFIG;
80736
81068
  var init_config = __esm({
80737
81069
  "src/agent/mcp/config.js"() {
80738
81070
  "use strict";
80739
- import_fs7 = require("fs");
80740
- import_path7 = require("path");
81071
+ import_fs9 = require("fs");
81072
+ import_path8 = require("path");
80741
81073
  import_os3 = require("os");
80742
81074
  import_url4 = require("url");
80743
81075
  __filename4 = (0, import_url4.fileURLToPath)("file:///");
80744
- __dirname4 = (0, import_path7.dirname)(__filename4);
81076
+ __dirname4 = (0, import_path8.dirname)(__filename4);
80745
81077
  DEFAULT_TIMEOUT = 3e4;
80746
81078
  MAX_TIMEOUT = 6e5;
80747
81079
  DEFAULT_CONFIG = {
@@ -80749,7 +81081,7 @@ var init_config = __esm({
80749
81081
  // Example probe server configuration
80750
81082
  "probe-local": {
80751
81083
  command: "node",
80752
- args: [(0, import_path7.join)(__dirname4, "../../../examples/chat/mcpServer.js")],
81084
+ args: [(0, import_path8.join)(__dirname4, "../../../examples/chat/mcpServer.js")],
80753
81085
  transport: "stdio",
80754
81086
  enabled: false
80755
81087
  },
@@ -82871,12 +83203,12 @@ async function createEnhancedClaudeCLIEngine(options = {}) {
82871
83203
  console.log("[DEBUG] Built-in MCP server started");
82872
83204
  console.log("[DEBUG] MCP URL:", `http://${host}:${port}/mcp`);
82873
83205
  }
82874
- mcpConfigPath = import_path8.default.join(import_os4.default.tmpdir(), `probe-mcp-${session.id}.json`);
83206
+ mcpConfigPath = import_path9.default.join(import_os4.default.tmpdir(), `probe-mcp-${session.id}.json`);
82875
83207
  const mcpConfig = {
82876
83208
  mcpServers: {
82877
83209
  probe: {
82878
83210
  command: "node",
82879
- args: [import_path8.default.join(process.cwd(), "mcp-probe-server.js")],
83211
+ args: [import_path9.default.join(process.cwd(), "mcp-probe-server.js")],
82880
83212
  env: {
82881
83213
  PROBE_WORKSPACE: process.cwd(),
82882
83214
  DEBUG: debug ? "true" : "false"
@@ -83245,14 +83577,14 @@ function combinePrompts(systemPrompt, customPrompt, agent) {
83245
83577
  }
83246
83578
  return systemPrompt || "";
83247
83579
  }
83248
- var import_child_process7, import_crypto5, import_promises2, import_path8, import_os4, import_events3;
83580
+ var import_child_process7, import_crypto5, import_promises2, import_path9, import_os4, import_events3;
83249
83581
  var init_enhanced_claude_code = __esm({
83250
83582
  "src/agent/engines/enhanced-claude-code.js"() {
83251
83583
  "use strict";
83252
83584
  import_child_process7 = require("child_process");
83253
83585
  import_crypto5 = require("crypto");
83254
83586
  import_promises2 = __toESM(require("fs/promises"), 1);
83255
- import_path8 = __toESM(require("path"), 1);
83587
+ import_path9 = __toESM(require("path"), 1);
83256
83588
  import_os4 = __toESM(require("os"), 1);
83257
83589
  import_events3 = require("events");
83258
83590
  init_built_in_server();
@@ -83596,11 +83928,11 @@ function createEnhancedVercelEngine(agent) {
83596
83928
  }
83597
83929
  };
83598
83930
  }
83599
- var import_ai;
83931
+ var import_ai2;
83600
83932
  var init_enhanced_vercel = __esm({
83601
83933
  "src/agent/engines/enhanced-vercel.js"() {
83602
83934
  "use strict";
83603
- import_ai = require("ai");
83935
+ import_ai2 = require("ai");
83604
83936
  }
83605
83937
  });
83606
83938
 
@@ -83609,7 +83941,7 @@ var ProbeAgent_exports = {};
83609
83941
  __export(ProbeAgent_exports, {
83610
83942
  ProbeAgent: () => ProbeAgent
83611
83943
  });
83612
- var import_dotenv, import_anthropic2, import_openai2, import_google2, import_ai2, import_crypto7, import_events4, import_fs8, import_promises3, import_path9, MAX_TOOL_ITERATIONS, MAX_HISTORY_MESSAGES, MAX_IMAGE_FILE_SIZE, ProbeAgent;
83944
+ var import_dotenv, import_anthropic2, import_openai2, import_google2, import_ai3, import_crypto7, import_events4, import_fs10, import_promises3, import_path10, MAX_TOOL_ITERATIONS, MAX_HISTORY_MESSAGES, MAX_IMAGE_FILE_SIZE, ProbeAgent;
83613
83945
  var init_ProbeAgent = __esm({
83614
83946
  "src/agent/ProbeAgent.js"() {
83615
83947
  "use strict";
@@ -83618,12 +83950,12 @@ var init_ProbeAgent = __esm({
83618
83950
  import_openai2 = require("@ai-sdk/openai");
83619
83951
  import_google2 = require("@ai-sdk/google");
83620
83952
  init_dist3();
83621
- import_ai2 = require("ai");
83953
+ import_ai3 = require("ai");
83622
83954
  import_crypto7 = require("crypto");
83623
83955
  import_events4 = require("events");
83624
- import_fs8 = require("fs");
83956
+ import_fs10 = require("fs");
83625
83957
  import_promises3 = require("fs/promises");
83626
- import_path9 = require("path");
83958
+ import_path10 = require("path");
83627
83959
  init_tokenCounter();
83628
83960
  init_InMemoryStorageAdapter();
83629
83961
  init_HookManager();
@@ -83950,7 +84282,7 @@ var init_ProbeAgent = __esm({
83950
84282
  if (!imagePath) {
83951
84283
  throw new Error("Image path is required");
83952
84284
  }
83953
- const filename = (0, import_path9.basename)(imagePath);
84285
+ const filename = (0, import_path10.basename)(imagePath);
83954
84286
  const extension = filename.toLowerCase().split(".").pop();
83955
84287
  if (!extension || !SUPPORTED_IMAGE_EXTENSIONS.includes(extension)) {
83956
84288
  throw new Error(`Invalid or unsupported image extension: ${extension}. Supported formats: ${SUPPORTED_IMAGE_EXTENSIONS.join(", ")}`);
@@ -84268,7 +84600,7 @@ var init_ProbeAgent = __esm({
84268
84600
  }
84269
84601
  if (!this.fallbackManager) {
84270
84602
  return await this.retryManager.executeWithRetry(
84271
- () => (0, import_ai2.streamText)(options),
84603
+ () => (0, import_ai3.streamText)(options),
84272
84604
  {
84273
84605
  provider: this.apiType,
84274
84606
  model: this.model
@@ -84290,7 +84622,7 @@ var init_ProbeAgent = __esm({
84290
84622
  debug: this.debug
84291
84623
  });
84292
84624
  return await providerRetryManager.executeWithRetry(
84293
- () => (0, import_ai2.streamText)(fallbackOptions),
84625
+ () => (0, import_ai3.streamText)(fallbackOptions),
84294
84626
  {
84295
84627
  provider: config.provider,
84296
84628
  model
@@ -84505,7 +84837,7 @@ var init_ProbeAgent = __esm({
84505
84837
  let resolvedPath2 = imagePath;
84506
84838
  if (!imagePath.includes("/") && !imagePath.includes("\\")) {
84507
84839
  for (const dir of listFilesDirectories) {
84508
- const potentialPath = (0, import_path9.resolve)(dir, imagePath);
84840
+ const potentialPath = (0, import_path10.resolve)(dir, imagePath);
84509
84841
  const loaded = await this.loadImageIfValid(potentialPath);
84510
84842
  if (loaded) {
84511
84843
  if (this.debug) {
@@ -84530,7 +84862,7 @@ var init_ProbeAgent = __esm({
84530
84862
  let match2;
84531
84863
  while ((match2 = fileHeaderPattern.exec(content)) !== null) {
84532
84864
  const filePath = match2[1].trim();
84533
- const dir = (0, import_path9.dirname)(filePath);
84865
+ const dir = (0, import_path10.dirname)(filePath);
84534
84866
  if (dir && dir !== ".") {
84535
84867
  directories.push(dir);
84536
84868
  if (this.debug) {
@@ -84575,17 +84907,17 @@ var init_ProbeAgent = __esm({
84575
84907
  const allowedDirs = this.allowedFolders && this.allowedFolders.length > 0 ? this.allowedFolders : [process.cwd()];
84576
84908
  let absolutePath;
84577
84909
  let isPathAllowed2 = false;
84578
- if ((0, import_path9.isAbsolute)(imagePath)) {
84579
- absolutePath = (0, import_path9.normalize)((0, import_path9.resolve)(imagePath));
84910
+ if ((0, import_path10.isAbsolute)(imagePath)) {
84911
+ absolutePath = (0, import_path10.normalize)((0, import_path10.resolve)(imagePath));
84580
84912
  isPathAllowed2 = allowedDirs.some((dir) => {
84581
- const normalizedDir = (0, import_path9.normalize)((0, import_path9.resolve)(dir));
84582
- return absolutePath === normalizedDir || absolutePath.startsWith(normalizedDir + import_path9.sep);
84913
+ const normalizedDir = (0, import_path10.normalize)((0, import_path10.resolve)(dir));
84914
+ return absolutePath === normalizedDir || absolutePath.startsWith(normalizedDir + import_path10.sep);
84583
84915
  });
84584
84916
  } else {
84585
84917
  for (const dir of allowedDirs) {
84586
- const normalizedDir = (0, import_path9.normalize)((0, import_path9.resolve)(dir));
84587
- const resolvedPath2 = (0, import_path9.normalize)((0, import_path9.resolve)(dir, imagePath));
84588
- if (resolvedPath2 === normalizedDir || resolvedPath2.startsWith(normalizedDir + import_path9.sep)) {
84918
+ const normalizedDir = (0, import_path10.normalize)((0, import_path10.resolve)(dir));
84919
+ const resolvedPath2 = (0, import_path10.normalize)((0, import_path10.resolve)(dir, imagePath));
84920
+ if (resolvedPath2 === normalizedDir || resolvedPath2.startsWith(normalizedDir + import_path10.sep)) {
84589
84921
  absolutePath = resolvedPath2;
84590
84922
  isPathAllowed2 = true;
84591
84923
  break;
@@ -85517,10 +85849,10 @@ ${toolResultContent}
85517
85849
  try {
85518
85850
  let resolvedWorkingDirectory = this.cwd || this.allowedFolders && this.allowedFolders[0] || process.cwd();
85519
85851
  if (params.workingDirectory) {
85520
- const requestedDir = (0, import_path9.isAbsolute)(params.workingDirectory) ? (0, import_path9.resolve)(params.workingDirectory) : (0, import_path9.resolve)(resolvedWorkingDirectory, params.workingDirectory);
85852
+ const requestedDir = (0, import_path10.isAbsolute)(params.workingDirectory) ? (0, import_path10.resolve)(params.workingDirectory) : (0, import_path10.resolve)(resolvedWorkingDirectory, params.workingDirectory);
85521
85853
  const isWithinAllowed = !this.allowedFolders || this.allowedFolders.length === 0 || this.allowedFolders.some((folder) => {
85522
- const resolvedFolder = (0, import_path9.resolve)(folder);
85523
- return requestedDir === resolvedFolder || requestedDir.startsWith(resolvedFolder + import_path9.sep);
85854
+ const resolvedFolder = (0, import_path10.resolve)(folder);
85855
+ return requestedDir === resolvedFolder || requestedDir.startsWith(resolvedFolder + import_path10.sep);
85524
85856
  });
85525
85857
  if (isWithinAllowed) {
85526
85858
  resolvedWorkingDirectory = requestedDir;
@@ -86470,7 +86802,9 @@ async function delegate({
86470
86802
  debug,
86471
86803
  tracer,
86472
86804
  path: path9,
86473
- // Inherit from parent
86805
+ // Workspace root (from delegateTool)
86806
+ cwd: path9,
86807
+ // Explicitly set cwd to workspace root to prevent path doubling
86474
86808
  provider,
86475
86809
  // Inherit from parent
86476
86810
  model,
@@ -86681,11 +87015,11 @@ var init_delegate = __esm({
86681
87015
  });
86682
87016
 
86683
87017
  // src/tools/vercel.js
86684
- var import_ai3, searchTool, queryTool, extractTool, delegateTool;
87018
+ var import_ai4, searchTool, queryTool, extractTool, delegateTool;
86685
87019
  var init_vercel = __esm({
86686
87020
  "src/tools/vercel.js"() {
86687
87021
  "use strict";
86688
- import_ai3 = require("ai");
87022
+ import_ai4 = require("ai");
86689
87023
  init_search();
86690
87024
  init_query();
86691
87025
  init_extract();
@@ -86693,7 +87027,7 @@ var init_vercel = __esm({
86693
87027
  init_common2();
86694
87028
  searchTool = (options = {}) => {
86695
87029
  const { sessionId, maxTokens = 1e4, debug = false, outline = false } = options;
86696
- return (0, import_ai3.tool)({
87030
+ return (0, import_ai4.tool)({
86697
87031
  name: "search",
86698
87032
  description: searchDescription,
86699
87033
  inputSchema: searchSchema,
@@ -86739,7 +87073,7 @@ var init_vercel = __esm({
86739
87073
  };
86740
87074
  queryTool = (options = {}) => {
86741
87075
  const { debug = false } = options;
86742
- return (0, import_ai3.tool)({
87076
+ return (0, import_ai4.tool)({
86743
87077
  name: "query",
86744
87078
  description: queryDescription,
86745
87079
  inputSchema: querySchema,
@@ -86775,7 +87109,7 @@ var init_vercel = __esm({
86775
87109
  };
86776
87110
  extractTool = (options = {}) => {
86777
87111
  const { debug = false, outline = false } = options;
86778
- return (0, import_ai3.tool)({
87112
+ return (0, import_ai4.tool)({
86779
87113
  name: "extract",
86780
87114
  description: extractDescription,
86781
87115
  inputSchema: extractSchema,
@@ -86851,7 +87185,7 @@ var init_vercel = __esm({
86851
87185
  };
86852
87186
  delegateTool = (options = {}) => {
86853
87187
  const { debug = false, timeout = 300, cwd, allowedFolders, enableBash = false, bashConfig } = options;
86854
- return (0, import_ai3.tool)({
87188
+ return (0, import_ai4.tool)({
86855
87189
  name: "delegate",
86856
87190
  description: delegateDescription,
86857
87191
  inputSchema: delegateSchema,
@@ -86880,14 +87214,15 @@ var init_vercel = __esm({
86880
87214
  if (model !== void 0 && model !== null && typeof model !== "string") {
86881
87215
  throw new TypeError("model must be a string, null, or undefined");
86882
87216
  }
86883
- const effectivePath = path9 || cwd || allowedFolders && allowedFolders[0];
87217
+ const workspaceRoot = allowedFolders && allowedFolders[0];
87218
+ const effectivePath = path9 || workspaceRoot || cwd;
86884
87219
  if (debug) {
86885
87220
  console.error(`Executing delegate with task: "${task.substring(0, 100)}${task.length > 100 ? "..." : ""}"`);
86886
87221
  if (parentSessionId) {
86887
87222
  console.error(`Parent session: ${parentSessionId}`);
86888
87223
  }
86889
87224
  if (effectivePath && effectivePath !== path9) {
86890
- console.error(`Using inherited path: ${effectivePath}`);
87225
+ console.error(`Using workspace root: ${effectivePath} (cwd was: ${cwd || "not set"})`);
86891
87226
  }
86892
87227
  }
86893
87228
  const result = await delegate({
@@ -87834,8 +88169,8 @@ async function executeBashCommand(command, options = {}) {
87834
88169
  } = options;
87835
88170
  let cwd = workingDirectory;
87836
88171
  try {
87837
- cwd = (0, import_path10.resolve)(cwd);
87838
- if (!(0, import_fs9.existsSync)(cwd)) {
88172
+ cwd = (0, import_path11.resolve)(cwd);
88173
+ if (!(0, import_fs11.existsSync)(cwd)) {
87839
88174
  throw new Error(`Working directory does not exist: ${cwd}`);
87840
88175
  }
87841
88176
  } catch (error2) {
@@ -88059,7 +88394,7 @@ function validateExecutionOptions(options = {}) {
88059
88394
  if (options.workingDirectory) {
88060
88395
  if (typeof options.workingDirectory !== "string") {
88061
88396
  errors.push("workingDirectory must be a string");
88062
- } else if (!(0, import_fs9.existsSync)(options.workingDirectory)) {
88397
+ } else if (!(0, import_fs11.existsSync)(options.workingDirectory)) {
88063
88398
  errors.push(`workingDirectory does not exist: ${options.workingDirectory}`);
88064
88399
  }
88065
88400
  }
@@ -88072,24 +88407,24 @@ function validateExecutionOptions(options = {}) {
88072
88407
  warnings
88073
88408
  };
88074
88409
  }
88075
- var import_child_process9, import_path10, import_fs9;
88410
+ var import_child_process9, import_path11, import_fs11;
88076
88411
  var init_bashExecutor = __esm({
88077
88412
  "src/agent/bashExecutor.js"() {
88078
88413
  "use strict";
88079
88414
  import_child_process9 = require("child_process");
88080
- import_path10 = require("path");
88081
- import_fs9 = require("fs");
88415
+ import_path11 = require("path");
88416
+ import_fs11 = require("fs");
88082
88417
  init_bashCommandUtils();
88083
88418
  }
88084
88419
  });
88085
88420
 
88086
88421
  // src/tools/bash.js
88087
- var import_ai4, import_path11, bashTool;
88422
+ var import_ai5, import_path12, bashTool;
88088
88423
  var init_bash = __esm({
88089
88424
  "src/tools/bash.js"() {
88090
88425
  "use strict";
88091
- import_ai4 = require("ai");
88092
- import_path11 = require("path");
88426
+ import_ai5 = require("ai");
88427
+ import_path12 = require("path");
88093
88428
  init_bashPermissions();
88094
88429
  init_bashExecutor();
88095
88430
  bashTool = (options = {}) => {
@@ -88118,7 +88453,7 @@ var init_bash = __esm({
88118
88453
  }
88119
88454
  return process.cwd();
88120
88455
  };
88121
- return (0, import_ai4.tool)({
88456
+ return (0, import_ai5.tool)({
88122
88457
  name: "bash",
88123
88458
  description: `Execute bash commands for system exploration and development tasks.
88124
88459
 
@@ -88198,12 +88533,12 @@ For code exploration, try these safe alternatives:
88198
88533
  - npm list, pip list for package information`;
88199
88534
  }
88200
88535
  const defaultDir = getDefaultWorkingDirectory();
88201
- const workingDir = workingDirectory ? (0, import_path11.isAbsolute)(workingDirectory) ? (0, import_path11.resolve)(workingDirectory) : (0, import_path11.resolve)(defaultDir, workingDirectory) : defaultDir;
88536
+ const workingDir = workingDirectory ? (0, import_path12.isAbsolute)(workingDirectory) ? (0, import_path12.resolve)(workingDirectory) : (0, import_path12.resolve)(defaultDir, workingDirectory) : defaultDir;
88202
88537
  if (allowedFolders && allowedFolders.length > 0) {
88203
- const resolvedWorkingDir = (0, import_path11.resolve)(workingDir);
88538
+ const resolvedWorkingDir = (0, import_path12.resolve)(workingDir);
88204
88539
  const isAllowed = allowedFolders.some((folder) => {
88205
- const resolvedFolder = (0, import_path11.resolve)(folder);
88206
- return resolvedWorkingDir === resolvedFolder || resolvedWorkingDir.startsWith(resolvedFolder + import_path11.sep);
88540
+ const resolvedFolder = (0, import_path12.resolve)(folder);
88541
+ return resolvedWorkingDir === resolvedFolder || resolvedWorkingDir.startsWith(resolvedFolder + import_path12.sep);
88207
88542
  });
88208
88543
  if (!isAllowed) {
88209
88544
  return `Error: Working directory "${workingDir}" is not within allowed folders: ${allowedFolders.join(", ")}`;
@@ -88255,323 +88590,6 @@ Command failed with exit code ${result.exitCode}`;
88255
88590
  }
88256
88591
  });
88257
88592
 
88258
- // src/tools/edit.js
88259
- function isPathAllowed(filePath, allowedFolders) {
88260
- if (!allowedFolders || allowedFolders.length === 0) {
88261
- const resolvedPath3 = (0, import_path12.resolve)(filePath);
88262
- const cwd = (0, import_path12.resolve)(process.cwd());
88263
- return resolvedPath3 === cwd || resolvedPath3.startsWith(cwd + import_path12.sep);
88264
- }
88265
- const resolvedPath2 = (0, import_path12.resolve)(filePath);
88266
- return allowedFolders.some((folder) => {
88267
- const allowedPath = (0, import_path12.resolve)(folder);
88268
- return resolvedPath2 === allowedPath || resolvedPath2.startsWith(allowedPath + import_path12.sep);
88269
- });
88270
- }
88271
- function parseFileToolOptions(options = {}) {
88272
- return {
88273
- debug: options.debug || false,
88274
- allowedFolders: options.allowedFolders || [],
88275
- cwd: options.cwd
88276
- };
88277
- }
88278
- var import_ai5, import_fs10, import_path12, import_fs11, editTool, createTool, editSchema, createSchema, editDescription, createDescription, editToolDefinition, createToolDefinition;
88279
- var init_edit = __esm({
88280
- "src/tools/edit.js"() {
88281
- "use strict";
88282
- import_ai5 = require("ai");
88283
- import_fs10 = require("fs");
88284
- import_path12 = require("path");
88285
- import_fs11 = require("fs");
88286
- editTool = (options = {}) => {
88287
- const { debug, allowedFolders, cwd } = parseFileToolOptions(options);
88288
- return (0, import_ai5.tool)({
88289
- name: "edit",
88290
- description: `Edit files using exact string replacement (Claude Code style).
88291
-
88292
- 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.
88293
-
88294
- Parameters:
88295
- - file_path: Path to the file to edit (absolute or relative)
88296
- - old_string: Exact text to find and replace (must be unique in the file unless replace_all is true)
88297
- - new_string: Text to replace with
88298
- - replace_all: (optional) Replace all occurrences instead of requiring uniqueness
88299
-
88300
- Important:
88301
- - The old_string must match EXACTLY including whitespace
88302
- - If old_string appears multiple times and replace_all is false, the edit will fail
88303
- - Use larger context around the string to ensure uniqueness when needed`,
88304
- inputSchema: {
88305
- type: "object",
88306
- properties: {
88307
- file_path: {
88308
- type: "string",
88309
- description: "Path to the file to edit"
88310
- },
88311
- old_string: {
88312
- type: "string",
88313
- description: "Exact text to find and replace"
88314
- },
88315
- new_string: {
88316
- type: "string",
88317
- description: "Text to replace with"
88318
- },
88319
- replace_all: {
88320
- type: "boolean",
88321
- description: "Replace all occurrences (default: false)",
88322
- default: false
88323
- }
88324
- },
88325
- required: ["file_path", "old_string", "new_string"]
88326
- },
88327
- execute: async ({ file_path, old_string, new_string, replace_all = false }) => {
88328
- try {
88329
- if (!file_path || typeof file_path !== "string" || file_path.trim() === "") {
88330
- return `Error editing file: Invalid file_path - must be a non-empty string`;
88331
- }
88332
- if (old_string === void 0 || old_string === null || typeof old_string !== "string") {
88333
- return `Error editing file: Invalid old_string - must be a string`;
88334
- }
88335
- if (new_string === void 0 || new_string === null || typeof new_string !== "string") {
88336
- return `Error editing file: Invalid new_string - must be a string`;
88337
- }
88338
- const resolvedPath2 = (0, import_path12.isAbsolute)(file_path) ? file_path : (0, import_path12.resolve)(cwd || process.cwd(), file_path);
88339
- if (debug) {
88340
- console.error(`[Edit] Attempting to edit file: ${resolvedPath2}`);
88341
- }
88342
- if (!isPathAllowed(resolvedPath2, allowedFolders)) {
88343
- return `Error editing file: Permission denied - ${file_path} is outside allowed directories`;
88344
- }
88345
- if (!(0, import_fs11.existsSync)(resolvedPath2)) {
88346
- return `Error editing file: File not found - ${file_path}`;
88347
- }
88348
- const content = await import_fs10.promises.readFile(resolvedPath2, "utf-8");
88349
- if (!content.includes(old_string)) {
88350
- return `Error editing file: String not found - the specified old_string was not found in ${file_path}`;
88351
- }
88352
- const occurrences = content.split(old_string).length - 1;
88353
- if (!replace_all && occurrences > 1) {
88354
- 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.`;
88355
- }
88356
- let newContent;
88357
- if (replace_all) {
88358
- newContent = content.replaceAll(old_string, new_string);
88359
- } else {
88360
- newContent = content.replace(old_string, new_string);
88361
- }
88362
- if (newContent === content) {
88363
- return `Error editing file: No changes made - old_string and new_string might be the same`;
88364
- }
88365
- await import_fs10.promises.writeFile(resolvedPath2, newContent, "utf-8");
88366
- const replacedCount = replace_all ? occurrences : 1;
88367
- if (debug) {
88368
- console.error(`[Edit] Successfully edited ${resolvedPath2}, replaced ${replacedCount} occurrence(s)`);
88369
- }
88370
- return `Successfully edited ${file_path} (${replacedCount} replacement${replacedCount !== 1 ? "s" : ""})`;
88371
- } catch (error2) {
88372
- console.error("[Edit] Error:", error2);
88373
- return `Error editing file: ${error2.message}`;
88374
- }
88375
- }
88376
- });
88377
- };
88378
- createTool = (options = {}) => {
88379
- const { debug, allowedFolders, cwd } = parseFileToolOptions(options);
88380
- return (0, import_ai5.tool)({
88381
- name: "create",
88382
- description: `Create new files with specified content.
88383
-
88384
- This tool creates new files in the filesystem. It will create parent directories if they don't exist.
88385
-
88386
- Parameters:
88387
- - file_path: Path where the file should be created (absolute or relative)
88388
- - content: Content to write to the file
88389
- - overwrite: (optional) Whether to overwrite if file exists (default: false)
88390
-
88391
- Important:
88392
- - By default, will fail if the file already exists
88393
- - Set overwrite: true to replace existing files
88394
- - Parent directories will be created automatically if needed`,
88395
- inputSchema: {
88396
- type: "object",
88397
- properties: {
88398
- file_path: {
88399
- type: "string",
88400
- description: "Path where the file should be created"
88401
- },
88402
- content: {
88403
- type: "string",
88404
- description: "Content to write to the file"
88405
- },
88406
- overwrite: {
88407
- type: "boolean",
88408
- description: "Overwrite if file exists (default: false)",
88409
- default: false
88410
- }
88411
- },
88412
- required: ["file_path", "content"]
88413
- },
88414
- execute: async ({ file_path, content, overwrite = false }) => {
88415
- try {
88416
- if (!file_path || typeof file_path !== "string" || file_path.trim() === "") {
88417
- return `Error creating file: Invalid file_path - must be a non-empty string`;
88418
- }
88419
- if (content === void 0 || content === null || typeof content !== "string") {
88420
- return `Error creating file: Invalid content - must be a string`;
88421
- }
88422
- const resolvedPath2 = (0, import_path12.isAbsolute)(file_path) ? file_path : (0, import_path12.resolve)(cwd || process.cwd(), file_path);
88423
- if (debug) {
88424
- console.error(`[Create] Attempting to create file: ${resolvedPath2}`);
88425
- }
88426
- if (!isPathAllowed(resolvedPath2, allowedFolders)) {
88427
- return `Error creating file: Permission denied - ${file_path} is outside allowed directories`;
88428
- }
88429
- if ((0, import_fs11.existsSync)(resolvedPath2) && !overwrite) {
88430
- return `Error creating file: File already exists - ${file_path}. Use overwrite: true to replace it.`;
88431
- }
88432
- const dir = (0, import_path12.dirname)(resolvedPath2);
88433
- await import_fs10.promises.mkdir(dir, { recursive: true });
88434
- await import_fs10.promises.writeFile(resolvedPath2, content, "utf-8");
88435
- const action = (0, import_fs11.existsSync)(resolvedPath2) && overwrite ? "overwrote" : "created";
88436
- const bytes = Buffer.byteLength(content, "utf-8");
88437
- if (debug) {
88438
- console.error(`[Create] Successfully ${action} ${resolvedPath2}`);
88439
- }
88440
- return `Successfully ${action} ${file_path} (${bytes} bytes)`;
88441
- } catch (error2) {
88442
- console.error("[Create] Error:", error2);
88443
- return `Error creating file: ${error2.message}`;
88444
- }
88445
- }
88446
- });
88447
- };
88448
- editSchema = {
88449
- type: "object",
88450
- properties: {
88451
- file_path: {
88452
- type: "string",
88453
- description: "Path to the file to edit"
88454
- },
88455
- old_string: {
88456
- type: "string",
88457
- description: "Exact text to find and replace"
88458
- },
88459
- new_string: {
88460
- type: "string",
88461
- description: "Text to replace with"
88462
- },
88463
- replace_all: {
88464
- type: "boolean",
88465
- description: "Replace all occurrences (default: false)"
88466
- }
88467
- },
88468
- required: ["file_path", "old_string", "new_string"]
88469
- };
88470
- createSchema = {
88471
- type: "object",
88472
- properties: {
88473
- file_path: {
88474
- type: "string",
88475
- description: "Path where the file should be created"
88476
- },
88477
- content: {
88478
- type: "string",
88479
- description: "Content to write to the file"
88480
- },
88481
- overwrite: {
88482
- type: "boolean",
88483
- description: "Overwrite if file exists (default: false)"
88484
- }
88485
- },
88486
- required: ["file_path", "content"]
88487
- };
88488
- editDescription = "Edit files using exact string replacement. Requires exact match including whitespace.";
88489
- createDescription = "Create new files with specified content. Will create parent directories if needed.";
88490
- editToolDefinition = `
88491
- ## edit
88492
- Description: ${editDescription}
88493
-
88494
- When to use:
88495
- - For precise, surgical edits to existing files
88496
- - When you need to change specific lines or blocks of code
88497
- - For renaming functions, variables, or updating configuration values
88498
- - When the exact text to replace is known and unique (or use replace_all for multiple occurrences)
88499
-
88500
- When NOT to use:
88501
- - For creating new files (use 'create' tool instead)
88502
- - When you cannot determine the exact text to replace
88503
- - When changes span multiple locations that would be better handled together
88504
-
88505
- Parameters:
88506
- - file_path: (required) Path to the file to edit
88507
- - old_string: (required) Exact text to find and replace (must match including whitespace, newlines, and indentation)
88508
- - new_string: (required) Text to replace with
88509
- - replace_all: (optional, default: false) Replace all occurrences if the string appears multiple times
88510
-
88511
- Important notes:
88512
- - The old_string MUST match EXACTLY, including all whitespace, indentation, and line breaks
88513
- - If old_string appears multiple times and replace_all is false, the tool will fail
88514
- - Always verify the exact formatting of the text you want to replace
88515
-
88516
- Examples:
88517
- <edit>
88518
- <file_path>src/main.js</file_path>
88519
- <old_string>function oldName() {
88520
- return 42;
88521
- }</old_string>
88522
- <new_string>function newName() {
88523
- return 42;
88524
- }</new_string>
88525
- </edit>
88526
-
88527
- <edit>
88528
- <file_path>config.json</file_path>
88529
- <old_string>"debug": false</old_string>
88530
- <new_string>"debug": true</new_string>
88531
- <replace_all>true</replace_all>
88532
- </edit>`;
88533
- createToolDefinition = `
88534
- ## create
88535
- Description: ${createDescription}
88536
-
88537
- When to use:
88538
- - For creating brand new files from scratch
88539
- - When you need to add configuration files, documentation, or new modules
88540
- - For generating boilerplate code or templates
88541
- - When you have the complete content ready to write
88542
-
88543
- When NOT to use:
88544
- - For editing existing files (use 'edit' tool instead)
88545
- - When a file already exists unless you explicitly want to overwrite it
88546
-
88547
- Parameters:
88548
- - file_path: (required) Path where the file should be created
88549
- - content: (required) Complete content to write to the file
88550
- - overwrite: (optional, default: false) Whether to overwrite if file already exists
88551
-
88552
- Important notes:
88553
- - Parent directories will be created automatically if they don't exist
88554
- - The tool will fail if the file already exists and overwrite is false
88555
- - Be careful with the overwrite option as it completely replaces existing files
88556
-
88557
- Examples:
88558
- <create>
88559
- <file_path>src/newFile.js</file_path>
88560
- <content>export function hello() {
88561
- return "Hello, world!";
88562
- }</content>
88563
- </create>
88564
-
88565
- <create>
88566
- <file_path>README.md</file_path>
88567
- <content># My Project
88568
-
88569
- This is a new project.</content>
88570
- <overwrite>true</overwrite>
88571
- </create>`;
88572
- }
88573
- });
88574
-
88575
88593
  // src/tools/langchain.js
88576
88594
  function createSearchTool(options = {}) {
88577
88595
  const { cwd } = options;
@@ -88796,12 +88814,14 @@ For GitHub-compatible mermaid diagrams, avoid single quotes and parentheses in n
88796
88814
  var tools_exports = {};
88797
88815
  __export(tools_exports, {
88798
88816
  DEFAULT_SYSTEM_MESSAGE: () => DEFAULT_SYSTEM_MESSAGE,
88817
+ DEFAULT_VALID_TOOLS: () => DEFAULT_VALID_TOOLS,
88799
88818
  attemptCompletionSchema: () => attemptCompletionSchema,
88800
88819
  attemptCompletionToolDefinition: () => attemptCompletionToolDefinition,
88801
88820
  bashDescription: () => bashDescription,
88802
88821
  bashSchema: () => bashSchema,
88803
88822
  bashTool: () => bashTool,
88804
88823
  bashToolDefinition: () => bashToolDefinition,
88824
+ buildToolTagPattern: () => buildToolTagPattern,
88805
88825
  createDescription: () => createDescription,
88806
88826
  createExtractTool: () => createExtractTool,
88807
88827
  createQueryTool: () => createQueryTool,