diff --git a/src/core/Cline.ts b/src/core/Cline.ts index e5ad82895e..620ff96f9d 100644 --- a/src/core/Cline.ts +++ b/src/core/Cline.ts @@ -89,6 +89,7 @@ import { writeToFileTool } from "./tools/writeToFileTool" import { applyDiffTool } from "./tools/applyDiffTool" import { insertContentTool } from "./tools/insertContentTool" import { searchAndReplaceTool } from "./tools/searchAndReplaceTool" +import { listCodeDefinitionNamesTool } from "./tools/listCodeDefinitionNamesTool" export type ToolResponse = string | Array type UserContent = Array @@ -1596,66 +1597,16 @@ export class Cline extends EventEmitter { case "list_files": await listFilesTool(this, block, askApproval, handleError, pushToolResult, removeClosingTag) break - case "list_code_definition_names": { - const relPath: string | undefined = block.params.path - const sharedMessageProps: ClineSayTool = { - tool: "listCodeDefinitionNames", - path: getReadablePath(this.cwd, removeClosingTag("path", relPath)), - } - try { - if (block.partial) { - const partialMessage = JSON.stringify({ - ...sharedMessageProps, - content: "", - } satisfies ClineSayTool) - await this.ask("tool", partialMessage, block.partial).catch(() => {}) - break - } else { - if (!relPath) { - this.consecutiveMistakeCount++ - pushToolResult( - await this.sayAndCreateMissingParamError("list_code_definition_names", "path"), - ) - break - } - this.consecutiveMistakeCount = 0 - const absolutePath = path.resolve(this.cwd, relPath) - let result: string - try { - const stats = await fs.stat(absolutePath) - if (stats.isFile()) { - const fileResult = await parseSourceCodeDefinitionsForFile( - absolutePath, - this.rooIgnoreController, - ) - result = fileResult ?? "No source code definitions found in this file." - } else if (stats.isDirectory()) { - result = await parseSourceCodeForDefinitionsTopLevel( - absolutePath, - this.rooIgnoreController, - ) - } else { - result = "The specified path is neither a file nor a directory." - } - } catch { - result = `${absolutePath}: does not exist or cannot be accessed.` - } - const completeMessage = JSON.stringify({ - ...sharedMessageProps, - content: result, - } satisfies ClineSayTool) - const didApprove = await askApproval("tool", completeMessage) - if (!didApprove) { - break - } - pushToolResult(result) - break - } - } catch (error) { - await handleError("parsing source code definitions", error) - break - } - } + case "list_code_definition_names": + await listCodeDefinitionNamesTool( + this, + block, + askApproval, + handleError, + pushToolResult, + removeClosingTag, + ) + break case "search_files": { const relDirPath: string | undefined = block.params.path const regex: string | undefined = block.params.regex diff --git a/src/core/tools/listCodeDefinitionNamesTool.ts b/src/core/tools/listCodeDefinitionNamesTool.ts new file mode 100644 index 0000000000..46b8afae2b --- /dev/null +++ b/src/core/tools/listCodeDefinitionNamesTool.ts @@ -0,0 +1,69 @@ +import { ToolUse } from "../assistant-message" +import { HandleError, PushToolResult, RemoveClosingTag } from "./types" +import { Cline } from "../Cline" +import { AskApproval } from "./types" +import { ClineSayTool } from "../../shared/ExtensionMessage" +import { getReadablePath } from "../../utils/path" +import path from "path" +import fs from "fs/promises" +import { parseSourceCodeForDefinitionsTopLevel, parseSourceCodeDefinitionsForFile } from "../../services/tree-sitter" + +export async function listCodeDefinitionNamesTool( + cline: Cline, + block: ToolUse, + askApproval: AskApproval, + handleError: HandleError, + pushToolResult: PushToolResult, + removeClosingTag: RemoveClosingTag, +) { + const relPath: string | undefined = block.params.path + const sharedMessageProps: ClineSayTool = { + tool: "listCodeDefinitionNames", + path: getReadablePath(cline.cwd, removeClosingTag("path", relPath)), + } + try { + if (block.partial) { + const partialMessage = JSON.stringify({ + ...sharedMessageProps, + content: "", + } satisfies ClineSayTool) + await cline.ask("tool", partialMessage, block.partial).catch(() => {}) + return + } else { + if (!relPath) { + cline.consecutiveMistakeCount++ + pushToolResult(await cline.sayAndCreateMissingParamError("list_code_definition_names", "path")) + return + } + cline.consecutiveMistakeCount = 0 + const absolutePath = path.resolve(cline.cwd, relPath) + let result: string + try { + const stats = await fs.stat(absolutePath) + if (stats.isFile()) { + const fileResult = await parseSourceCodeDefinitionsForFile(absolutePath, cline.rooIgnoreController) + result = fileResult ?? "No source code definitions found in cline file." + } else if (stats.isDirectory()) { + result = await parseSourceCodeForDefinitionsTopLevel(absolutePath, cline.rooIgnoreController) + } else { + result = "The specified path is neither a file nor a directory." + } + } catch { + result = `${absolutePath}: does not exist or cannot be accessed.` + } + const completeMessage = JSON.stringify({ + ...sharedMessageProps, + content: result, + } satisfies ClineSayTool) + const didApprove = await askApproval("tool", completeMessage) + if (!didApprove) { + return + } + pushToolResult(result) + return + } + } catch (error) { + await handleError("parsing source code definitions", error) + return + } +}