Befehls- und Datei-Lese-Werkzeuge: ExecuteCommand / ReadFile / SearchFiles / ListFiles
Verantwortung
Diese Seite behandelt die vier „Capability"-Lese-/Ausführungs-Werkzeuge von Cline, die alle unter dem Interface IFullyManagedTool registriert und vom ToolExecutor einheitlich angesteuert werden:
- ExecuteCommandToolHandler (
ClineDefaultTool.BASH): Führt einen Shell-Befehl im Terminal aus, mit Timeout, Multi-Workspace und Berechtigungsprüfung (class declaration:58). - ReadFileToolHandler (
ClineDefaultTool.FILE_READ): Liest eine einzelne Datei, fügt 1-basierte Zeilennummern hinzu, unterstützt start_line/end_line-Slicing und liefert bei Bilddateien einen image block (class declaration:142). - SearchFilesToolHandler (
ClineDefaultTool.SEARCH): Auf ripgrep basierende Regex-Suche, mit paralleler Suche über mehrere Workspaces und file_pattern-Filter (class declaration:21). - ListFilesToolHandler (
ClineDefaultTool.LIST_FILES): Listet ein Verzeichnis, unterstützt Rekursion, wird bei 200 Einträgen abgeschnitten (class declaration:17).
Diese vier Werkzeuge teilen sich ein Interaktionsmuster: handlePartialBlock schickt früh eine UI-Nachricht, damit der Nutzer sieht „das Modell liest gerade X"; execute übernimmt die Validierung (clineignore + Pfad + Parameter) → Approval → PreToolUse hook → echte Ausführung → Telemetrie. Sie alle respektieren config.isSubagentExecution: Bei Sub-Agent-Ausführung werden Teile der UI-Pushs und asks übersprungen und direkt gearbeitet.
Der wesentliche Unterschied zum WriteToFileToolHandler ist „nur lesend oder externe Seiteneffekte" — Lesen, Auflisten und Suchen verändern den Dateisystemzustand nicht; execute_command verändert zwar den Zustand, aber über das Terminal und ohne Diff-Ansicht. Daher haben diese Werkzeuge keinen Diff-/userEdits-Rückfluss-Pfad.
Entwurfsmotivation
- Einheitliche mistake-Zählung: Jedes Werkzeug führt bei fehlenden Parametern oder clineignore-Treffer
consecutiveMistakeCount++aus und nach erfolgreicher Kernoperation= 0, sodass sich die YOLO-Fehlerschranke werkzeugübergreifend akkumulieren kann (reset counter:377). - Befehlsklassifizierung mit Timeout: execute_command matched typische Long-Running-Befehle (npm install, cargo build, pytest usw.) auf 300 Sekunden Timeout, sonst 30 Sekunden, damit Kurz-Befehle nicht durch langes Timeout aufgehalten werden (
LONG_RUNNING patterns:22-34). - Befehls-Berechtigung mit zweifacher Torsicherung: Segment-Level-Whitelist über die Umgebungsvariable
CLINE_COMMAND_PERMISSIONSplus clineignore-Pfadprüfung, zwei unabhängige Ablehnungs-Schichten (permission checks:162-190). - Dedup-Cache für Datei-Lesung:
fileReadCachespeichert nur Metadaten (readCount + mtime + imageBlock), keinen Inhalt; bei Treffer und unveränderter mtime wird direkt ein „bereits gelesen"-Hinweis zurückgegeben, um zu verhindern, dass das Modell Tokens wiederholt in dieselbe Datei verbrennt (dedup cache:298-314). - Zeilennummern-Darstellung:
formatFileContentWithLineNumbersfügt jeder Zeile einN |-Präfix hinzu und anhängt einen continuation-Hinweis, damit das Modell mit start_line präzise weiterliest (formatFileContentWithLineNumbers:79). - Parallele Suche über mehrere Workspaces: SearchFilesToolHandler führt im Multi-Workspace-Modus alle searchPaths parallel per
Promise.allaus und fasst sie dann nach Workspace-Namen zusammen (parallel search:279-285). - ListFiles 200-Limit: listFiles bekommt als dritten Parameter limit=200; bei Überschreitung wird didHitLimit=true zurückgegeben und formatFilesList fügt einen Hinweis an, damit das Modell mit einem spezifischeren Pfad den Bereich eingrenzt (
listFiles call:100).
Schlüsseldateien
LONG_RUNNING patterns:22-34— Regex-Array für Long-Running-Befehle: npm/cargo/pytest/docker build/torchrun usw.timeout resolution:36-56—isLikelyLongRunningCommand+resolveCommandTimeoutSeconds, bevorzugt den vom Modell gegebenen timeout-Parameter.ExecuteCommand class:58—name = ClineDefaultTool.BASH, handlePartialBlock wartet bei auto-approve auf den vollständigen Block, bevor say aufgerufen wird.workspace hint:135-159— Parse des Befehlspräfixes@workspace:command, das executionDir auf den entsprechenden Workspace-Root umgestellt.permission checks:162-190—commandPermissionController.validateCommand+clineIgnoreController.validateCommand.approval flow:223-279— Auto-approve erfordert!requiresApprovalPerLLM && autoApproveSafeoder für risky-Befehle die doppelte TorsierungautoApproveSafe && autoApproveAll.cache clear:319-327— Nach der Befehlsausführung wird das gesamtefileReadCache.clear()aufgerufen, da sed/git checkout/mv Dateien unvorhersehbar verändern können.formatFileContentWithLineNumbers:79— Slicing, Zeilennummern anhängen, Hinweis „Showing lines X-Y of Z".ReadFile class:142—name = ClineDefaultTool.FILE_READ.dedup cache:298-356— mtime-Vergleich + readCount-Akkumulation, ab dem 3. Mal DUPLICATE READ-Warnung.extract + cache:359-373— RuftextractFileContentauf (Bilder liefern imageBlock); bei Misserfolg tool error statt Werfen nach oben.determineSearchPaths:35— Entfaltet im Multi-Workspace-Modus anhand eines hint oder über alle Workspaces die Suchpfade.executeSearch:74— RuftregexSearchFiles(ripgrep) auf und filtert die Ergebnisse mit clineIgnoreController.formatSearchResults:120— Bei Multi-Workspace nach Workspace-Namen sortiert, bei Single-Workspace direkt zurückgegeben.listFiles call:100—listFiles(absolutePath, recursive, 200)liefert [files, didHitLimit].
Datenfluss
ExecuteCommand ist das komplexeste der vier; der Kern sind Approval-Gate und Timeout-Auflösung. Die vom Modell gelieferten Felder requires_approval + command entscheiden, welcher Approval-Pfad gegangen wird:
// apps/vscode/src/core/task/tools/handlers/ExecuteCommandToolHandler.ts
timeoutSeconds = resolveCommandTimeoutSeconds(
command,
timeoutParam,
config.yoloModeToggled || config.vscodeTerminalExecutionMode === "backgroundExec",
)
// ...
if (
config.isSubagentExecution ||
(!requiresApprovalPerLLM && autoApproveSafe) ||
(requiresApprovalPerLLM && autoApproveSafe && autoApproveAll)
) {
// Auto-approve flow
await config.callbacks.removeLastPartialMessageIfExistsWithType("ask", "command")
await config.callbacks.say("command", actualCommand, undefined, undefined, false)
didAutoApprove = true
} else {
// Manual approval flow
const didApprove = await ToolResultUtils.askApprovalAndPushFeedback(
"command",
actualCommand + `${autoApproveSafe && requiresApprovalPerLLM ? COMMAND_REQ_APP_STRING : ""}`,
config,
)
if (!didApprove) {
return formatResponse.toolDenied()
}
}autoApprover.shouldAutoApproveTool liefert ein 2-Tupel [autoApproveSafe, autoApproveAll]: Ersteres ist „safe-Befehle automatisch freigeben", Zweiteres „alle Befehle automatisch freigeben". Sagt das Modell risky (requires_approval=true) und ist nur safe-Auto-Approve konfiguriert, erfolgt manueller Approval und an den Befehl wird ein strenger Approval-Hinweisstring angehängt (auto-approve logic:223-227). Nach Approval folgen der PreToolUse hook, dann ein 30-Sekunden-Benachrichtigungs-Timer (nur bei Auto-Approve + aktivierter Notification) und schließlich executeCommandTool(finalCommand, timeoutSeconds) im Terminal. Nach Abschluss wird das gesamte fileReadCache geleert.
Der Kern des ReadFileToolHandler ist die Cache-Deduplizierung:
// apps/vscode/src/core/task/tools/handlers/ReadFileToolHandler.ts
const cacheKey = absolutePath.toLowerCase()
const cached = config.taskState.fileReadCache.get(cacheKey)
if (cached) {
try {
const stat = await import("node:fs/promises").then((fs) => fs.stat(absolutePath))
if (stat.mtimeMs !== cached.mtime) {
config.taskState.fileReadCache.delete(cacheKey)
}
} catch {
config.taskState.fileReadCache.delete(cacheKey)
}
}Hat sich die mtime geändert (Nutzer hat im Editor manuell geändert), wird der Cache evicted, sonst weiterverwendet. Im Cache wird kein Inhalt gespeichert, um Speicher zu sparen; bei einem Treffer wird trotzdem neu von der Platte gelesen. Ab dreimaligem readCount wird ein DUPLICATE READ-Hinweis zurückgegeben. Nach erfolgreichem Neu-Lesen holt extractFileContent den Inhalt (bei Bilddateien wird ein imageBlock in den userMessageContent gepusht) und speichert mtime + readCount=1 im Cache.
SearchFiles und ListFiles machen beide Pfadauflösung + clineignore + Approval + Ausführung + Formatierung, die Code-Struktur ist ähnlich. SearchFiles kommt mit Multi-Workspace-Parallelität hinzu:
// apps/vscode/src/core/task/tools/handlers/SearchFilesToolHandler.ts
const searchPromises = searchPaths.map(({ absolutePath, workspaceName, workspaceRoot }) =>
this.executeSearch(config, absolutePath, workspaceName, workspaceRoot, regex, filePattern),
)
const searchResults = await Promise.all(searchPromises)
const results = this.formatSearchResults(config, searchResults, searchPaths)regexSearchFiles ruft das zugrundeliegende ripgrep auf; die Ergebnisse werden nach Workspace-Namen zusammengefasst.
Grenzen und Fehler
- Fehlende Parameter: execute_command ohne command / requires_approval, read/search/list ohne path, search ohne regex: jeweils
consecutiveMistakeCount+++sayAndCreateMissingParamError(missing params:100-112). - Befehl abgelehnt: Lehnt
CLINE_COMMAND_PERMISSIONSab, wirdpermissionDeniedErrormit failedSegment oder matchedPattern zurückgegeben, damit das Modell korrigierende Informationen hat (permission denied:162-181). - Benachrichtigung bei Long-Running-Befehlen: Bei Auto-Approve + aktivierter Notification wird nach 30 Sekunden eine Systembenachrichtigung „Command is still running" angezeigt, damit der Nutzer nicht einen Hänger vermutet (
timeout notification:294-303). - Datei existiert nicht: Ein Wurf aus
extractFileContentwird alstoolError("Error reading file: ...")abgefangen und nicht an die Task-Oberfläche weitergeworfen, sodass das Modell den Fehler sieht und selbst den Pfad korrigiert (read error:361-373). - Cache-mtime inkonsistent: Schlägt stat fehl oder hat sich die mtime geändert, wird der Cache evicted, damit beim nächsten Mal der neueste Inhalt gelesen wird (
mtime check:304-313). - Auflösung des search-Pfads fehlgeschlagen: Wirft
parseWorkspaceInlinePath, wirdError resolving search path: ...zurückgegeben und mistake++ (path resolution error:233-242). - list files überschritten:
listFileswirft oder der Pfad ist falsch und liefertError listing files: ...; nach Erfolg wird didHitLimit vonformatFilesListin einen Hinweis umgewandelt (list error:101-105). - Sub-Agent überspringt UI: Alle vier Handler überspringen bei
isSubagentExecutiondie partial-say- und ask-Abläufe und führen die Aktion direkt aus (subagent skip:155-157).
Zusammenfassung
Diese vier Handler sind die „Augen und Hände" von Cline: ExecuteCommand führt Shell aus, ReadFile liest die Platte, SearchFiles führt ripgrep aus, ListFiles listet Verzeichnisse. Sie teilen sich das Skelett „Validierung → Approval → hook → Ausführung → Telemetrie"; die Unterschiede liegen in den Ausführungsdetails: execute_command hat eine befehlsklassifizierte Timeout-Logik und doppelte Torsierung, read_file eine mtime-Dedup-Cache, search unterstützt parallele Multi-Workspace-Ausführung, list hat das 200-Limit. Bei allen Werkzeugen wird consecutiveMistakeCount nach Erfolg auf null gesetzt; bei Misserfolg wird akkumuliert, bis das YOLO-Limit erreicht ist und angehalten wird.
Wer tiefer einsteigen will, kann weiterlesen bei:
- Werkzeuge zum Schreiben:
/edit-tools/write-to-file - Multi-File-Patches:
/edit-tools/apply-patch - Browser-Werkzeug:
/cap-tools/browser - Web fetch/search:
/cap-tools/web
Siehe offizielle Dokumentation: Cline-Dokumentation · README