Files
coyote/assets/functions/tools/fs_read.sh
T
Dark-Alex-17 2fe6704fbc
CI / All (ubuntu-latest) (push) Failing after 25s
CI / All (macos-latest) (push) Has been cancelled
CI / All (windows-latest) (push) Has been cancelled
fix: fs tools now output better error handling to guide the model more effectively
2026-07-14 12:47:43 -06:00

77 lines
2.9 KiB
Bash

#!/usr/bin/env bash
set -e
# @describe Read a TRUNCATED view of a file with line numbers, offset, and limit. For directories, lists entries.
# IMPORTANT: This tool truncates output — lines over 2000 chars are cut off, and output is capped at 2000 lines by default.
# If you need the FULL, untruncated contents of a file, use fs_cat instead.
# Use this tool when you want line numbers, want to read a specific section via --offset/--limit, or are scanning a large file.
# Use the grep tool to find specific content before reading, then read with offset to target the relevant section.
# @option --path! The absolute path to the file or directory to read
# @option --offset <INT> The line number to start reading from (1-indexed, default: 1)
# @option --limit <INT> The maximum number of lines to read (default: 2000)
# @env LLM_OUTPUT=/dev/stdout The output path
MAX_LINE_LENGTH=2000
MAX_BYTES=51200
main() {
# shellcheck disable=SC2154
local target="$argc_path"
local offset="${argc_offset:-1}"
local limit="${argc_limit:-2000}"
if [[ ! -e "$target" ]]; then
echo "Error: path not found: $target" >&2
exit 1
fi
if [[ -d "$target" ]]; then
ls -1 "$target" >> "$LLM_OUTPUT" 2>&1
return 0
fi
local total_lines file_bytes
# awk counts a final line that lacks a trailing newline; wc -l would undercount it by one.
total_lines=$(awk 'END { print NR }' "$target" 2>/dev/null || echo 0)
file_bytes=$(wc -c < "$target" 2>/dev/null || echo 0)
if [[ "$total_lines" -eq 0 ]]; then
echo "(file is empty: $target)" >> "$LLM_OUTPUT"
return 0
fi
if [[ "$offset" -gt "$total_lines" ]]; then
echo "(offset $offset is past the end of the file, which has $total_lines lines)" >> "$LLM_OUTPUT"
return 0
fi
if [[ "$file_bytes" -gt "$MAX_BYTES" ]] && [[ "$offset" -eq 1 ]] && [[ "$limit" -ge 2000 ]]; then
{
echo "Warning: Large file (${file_bytes} bytes, ${total_lines} lines). Showing first ${limit} lines."
echo "Use --offset and --limit to read specific sections, or use the grep tool to find relevant lines first."
echo ""
} >> "$LLM_OUTPUT"
fi
local end_line=$((offset + limit - 1))
sed -n "${offset},${end_line}p" "$target" 2>/dev/null | {
local line_num=$offset
# `|| [[ -n "$line" ]]` keeps the final line when the file has no trailing newline.
while IFS= read -r line || [[ -n "$line" ]]; do
if [[ ${#line} -gt $MAX_LINE_LENGTH ]]; then
line="${line:0:$MAX_LINE_LENGTH}... (truncated)"
fi
printf "%d: %s\n" "$line_num" "$line"
line_num=$((line_num + 1))
done
} >> "$LLM_OUTPUT"
if [[ "$end_line" -lt "$total_lines" ]]; then
echo "" >> "$LLM_OUTPUT"
echo "(${total_lines} total lines. Use --offset $((end_line + 1)) to read more.)" >> "$LLM_OUTPUT"
fi
}