|
| 1 | +import * as path from "path" |
| 2 | +import { Cline } from "../Cline" |
| 3 | +import { ClineSayTool } from "../../shared/ExtensionMessage" |
| 4 | +import { ToolParamName, ToolUse } from "../assistant-message" |
| 5 | +import { formatResponse } from "../prompts/responses" |
| 6 | +import { listFiles } from "../../services/glob/list-files" |
| 7 | +import { getReadablePath } from "../../utils/path" |
| 8 | +import { AskApproval, HandleError, PushToolResult } from "./types" |
| 9 | +/** |
| 10 | + * Implements the list_files tool. |
| 11 | + * |
| 12 | + * @param cline - The instance of Cline that is executing this tool. |
| 13 | + * @param block - The block of assistant message content that specifies the |
| 14 | + * parameters for this tool. |
| 15 | + * @param askApproval - A function that asks the user for approval to show a |
| 16 | + * message. |
| 17 | + * @param handleError - A function that handles an error that occurred while |
| 18 | + * executing this tool. |
| 19 | + * @param pushToolResult - A function that pushes the result of this tool to the |
| 20 | + * conversation. |
| 21 | + * @param removeClosingTag - A function that removes a closing tag from a string. |
| 22 | + */ |
| 23 | +export async function listFilesTool( |
| 24 | + cline: Cline, |
| 25 | + block: ToolUse, |
| 26 | + askApproval: AskApproval, |
| 27 | + handleError: HandleError, |
| 28 | + pushToolResult: PushToolResult, |
| 29 | + removeClosingTag: (tag: ToolParamName, text?: string) => string, |
| 30 | +) { |
| 31 | + const relDirPath: string | undefined = block.params.path |
| 32 | + const recursiveRaw: string | undefined = block.params.recursive |
| 33 | + const recursive = recursiveRaw?.toLowerCase() === "true" |
| 34 | + const sharedMessageProps: ClineSayTool = { |
| 35 | + tool: !recursive ? "listFilesTopLevel" : "listFilesRecursive", |
| 36 | + path: getReadablePath(cline.cwd, removeClosingTag("path", relDirPath)), |
| 37 | + } |
| 38 | + try { |
| 39 | + if (block.partial) { |
| 40 | + const partialMessage = JSON.stringify({ |
| 41 | + ...sharedMessageProps, |
| 42 | + content: "", |
| 43 | + } satisfies ClineSayTool) |
| 44 | + await cline.ask("tool", partialMessage, block.partial).catch(() => {}) |
| 45 | + return |
| 46 | + } else { |
| 47 | + if (!relDirPath) { |
| 48 | + cline.consecutiveMistakeCount++ |
| 49 | + pushToolResult(await cline.sayAndCreateMissingParamError("list_files", "path")) |
| 50 | + return |
| 51 | + } |
| 52 | + cline.consecutiveMistakeCount = 0 |
| 53 | + const absolutePath = path.resolve(cline.cwd, relDirPath) |
| 54 | + const [files, didHitLimit] = await listFiles(absolutePath, recursive, 200) |
| 55 | + const { showRooIgnoredFiles = true } = (await cline.providerRef.deref()?.getState()) ?? {} |
| 56 | + const result = formatResponse.formatFilesList( |
| 57 | + absolutePath, |
| 58 | + files, |
| 59 | + didHitLimit, |
| 60 | + cline.rooIgnoreController, |
| 61 | + showRooIgnoredFiles, |
| 62 | + ) |
| 63 | + const completeMessage = JSON.stringify({ |
| 64 | + ...sharedMessageProps, |
| 65 | + content: result, |
| 66 | + } satisfies ClineSayTool) |
| 67 | + const didApprove = await askApproval("tool", completeMessage) |
| 68 | + if (!didApprove) { |
| 69 | + return |
| 70 | + } |
| 71 | + pushToolResult(result) |
| 72 | + return |
| 73 | + } |
| 74 | + } catch (error) { |
| 75 | + await handleError("listing files", error) |
| 76 | + return |
| 77 | + } |
| 78 | +} |
0 commit comments