diff options
| -rwxr-xr-x | tools/fs_cat.sh | 36 | ||||
| -rwxr-xr-x | tools/fs_ls.sh | 26 | ||||
| -rwxr-xr-x | tools/fs_mkdir.sh | 25 | ||||
| -rwxr-xr-x | tools/fs_patch.sh | 62 | ||||
| -rwxr-xr-x | tools/fs_rm.sh | 32 | ||||
| -rwxr-xr-x | tools/fs_write.sh | 53 |
6 files changed, 179 insertions, 55 deletions
diff --git a/tools/fs_cat.sh b/tools/fs_cat.sh index 9fcf702..d02ca21 100755 --- a/tools/fs_cat.sh +++ b/tools/fs_cat.sh @@ -1,15 +1,43 @@ #!/usr/bin/env bash -set -e +set -uo pipefail # @describe Read the contents of a file at the specified path. # Use this when you need to examine the contents of an existing file. - # @option --path! The path of the file to read - # @env LLM_OUTPUT=/dev/stdout The output path +OUT="${LLM_OUTPUT:-/dev/stdout}" +MAX_BYTES="${LLM_MAX_BYTES:-200000}" + +sanitize() { + if command -v iconv >/dev/null 2>&1; then + iconv -f UTF-8 -t UTF-8 -c + else + cat + fi +} + +err() { + echo "ERROR: $*" >> "$OUT" + exit 0 +} + main() { - cat "$argc_path" >> "$LLM_OUTPUT" + path="${argc_path:-}" + [[ -z "$path" ]] && err "missing --path" + [[ ! -e "$path" ]] && err "file not found: $path" + [[ ! -f "$path" ]] && err "not a regular file: $path" + [[ ! -r "$path" ]] && err "file not readable: $path" + + # Heuristik: Binärdateien nicht in den Chat kippen + if LC_ALL=C grep -qP '\x00' "$path" 2>/dev/null; then + err "file appears to be binary (NUL bytes detected): $path" + fi + + head -c "$MAX_BYTES" "$path" | sanitize >> "$OUT" + exit 0 } eval "$(argc --argc-eval "$0" "$@")" +main + diff --git a/tools/fs_ls.sh b/tools/fs_ls.sh index d26132f..e62ee89 100755 --- a/tools/fs_ls.sh +++ b/tools/fs_ls.sh @@ -1,14 +1,32 @@ #!/usr/bin/env bash -set -e +set -uo pipefail # @describe List all files and directories at the specified path. - # @option --path! The path of the directory to list - # @env LLM_OUTPUT=/dev/stdout The output path +OUT="${LLM_OUTPUT:-/dev/stdout}" + +err() { + echo "ERROR: $*" >> "$OUT" + exit 0 +} + main() { - ls -1 "$argc_path" >> "$LLM_OUTPUT" + path="${argc_path:-}" + [[ -z "$path" ]] && err "missing --path" + [[ ! -e "$path" ]] && err "path not found: $path" + [[ ! -d "$path" ]] && err "not a directory: $path" + + # -1A: ein Eintrag pro Zeile, inkl. dotfiles (ohne . und ..) + if ! ls -1A "$path" >> "$OUT" 2>/tmp/fs_ls.err; then + msg="$(cat /tmp/fs_ls.err 2>/dev/null || true)" + err "ls failed for $path: ${msg:-unknown error}" + fi + + exit 0 } eval "$(argc --argc-eval "$0" "$@")" +main + diff --git a/tools/fs_mkdir.sh b/tools/fs_mkdir.sh index a91954f..f2e9b27 100755 --- a/tools/fs_mkdir.sh +++ b/tools/fs_mkdir.sh @@ -1,15 +1,30 @@ #!/usr/bin/env bash -set -e +set -uo pipefail # @describe Create a new directory at the specified path. - # @option --path! The path of the directory to create - # @env LLM_OUTPUT=/dev/stdout The output path +OUT="${LLM_OUTPUT:-/dev/stdout}" + +err() { + echo "ERROR: $*" >> "$OUT" + exit 0 +} + main() { - mkdir -p "$argc_path" - echo "Directory created: $argc_path" >> "$LLM_OUTPUT" + path="${argc_path:-}" + [[ -z "$path" ]] && err "missing --path" + + if ! mkdir -p "$path" 2>/tmp/fs_mkdir.err; then + msg="$(cat /tmp/fs_mkdir.err 2>/dev/null || true)" + err "mkdir failed for $path: ${msg:-unknown error}" + fi + + echo "Directory created: $path" >> "$OUT" + exit 0 } eval "$(argc --argc-eval "$0" "$@")" +main + diff --git a/tools/fs_patch.sh b/tools/fs_patch.sh index ce71628..84ae49e 100755 --- a/tools/fs_patch.sh +++ b/tools/fs_patch.sh @@ -1,36 +1,52 @@ #!/usr/bin/env bash -set -e +set -uo pipefail # @describe Apply a patch to a file at the specified path. -# This can be used to edit the file, without having to rewrite the whole file. - # @option --path! The path of the file to apply to # @option --contents! The patch to apply to the file -# -# Here is an example of a patch block that can be applied to modify the file to request the user's name: -# --- a/hello.py -# +++ b/hello.py -# \@@ ... @@ -# def hello(): -# - print("Hello World") -# + name = input("What is your name? ") -# + print(f"Hello {name}") - # @env LLM_OUTPUT=/dev/stdout The output path ROOT_DIR="${LLM_ROOT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}" +OUT="${LLM_OUTPUT:-/dev/stdout}" + +err() { + echo "ERROR: $*" >> "$OUT" + exit 0 +} main() { - if [ ! -f "$argc_path" ]; then - echo "Not found file: $argc_path" - exit 1 - fi - new_contents="$(awk -f "$ROOT_DIR/utils/patch.awk" "$argc_path" <(printf "%s" "$argc_contents"))" - printf "%s" "$new_contents" | git diff --no-index "$argc_path" - || true - "$ROOT_DIR/utils/guard_operation.sh" "Apply changes?" - printf "%s" "$new_contents" > "$argc_path" - - echo "The patch applied to: $argc_path" >> "$LLM_OUTPUT" + path="${argc_path:-}" + patch="${argc_contents:-}" + + [[ -z "$path" ]] && err "missing --path" + [[ -z "$patch" ]] && err "missing --contents" + [[ ! -e "$path" ]] && err "file not found: $path" + [[ ! -f "$path" ]] && err "not a regular file: $path" + [[ ! -r "$path" ]] && err "file not readable: $path" + + new_contents="" + if ! new_contents="$(awk -f "$ROOT_DIR/utils/patch.awk" "$path" <(printf "%s" "$patch") 2>/tmp/fs_patch.err)"; then + msg="$(cat /tmp/fs_patch.err 2>/dev/null || true)" + err "patch apply failed for $path: ${msg:-unknown error}" + fi + + # Diff in Tool-Output schreiben (damit das LLM es sieht) + printf "%s" "$new_contents" | git diff --no-index "$path" - >> "$OUT" 2>/dev/null || true + + # Guard kann “abbrechen” -> als ERROR ausgeben, aber exit 0 + if ! "$ROOT_DIR/utils/guard_operation.sh" "Apply changes?" >>"$OUT" 2>&1; then + err "operation cancelled by user" + fi + + if ! printf "%s" "$new_contents" > "$path" 2>/tmp/fs_patch_write.err; then + msg="$(cat /tmp/fs_patch_write.err 2>/dev/null || true)" + err "failed to write patched file $path: ${msg:-unknown error}" + fi + + echo "The patch applied to: $path" >> "$OUT" + exit 0 } eval "$(argc --argc-eval "$0" "$@")" +main + diff --git a/tools/fs_rm.sh b/tools/fs_rm.sh index 9d9386f..e667b0e 100755 --- a/tools/fs_rm.sh +++ b/tools/fs_rm.sh @@ -1,20 +1,36 @@ #!/usr/bin/env bash -set -e +set -uo pipefail # @describe Remove the file or directory at the specified path. - # @option --path! The path of the file or directory to remove - # @env LLM_OUTPUT=/dev/stdout The output path ROOT_DIR="${LLM_ROOT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}" +OUT="${LLM_OUTPUT:-/dev/stdout}" + +err() { + echo "ERROR: $*" >> "$OUT" + exit 0 +} main() { - if [[ -f "$argc_path" ]]; then - "$ROOT_DIR/utils/guard_path.sh" "$argc_path" "Remove '$argc_path'?" - rm -rf "$argc_path" - fi - echo "Path removed: $argc_path" >> "$LLM_OUTPUT" + path="${argc_path:-}" + [[ -z "$path" ]] && err "missing --path" + [[ ! -e "$path" ]] && err "path not found: $path" + + if ! "$ROOT_DIR/utils/guard_path.sh" "$path" "Remove '$path'?" >>"$OUT" 2>&1; then + err "operation cancelled by user" + fi + + if ! rm -rf "$path" 2>/tmp/fs_rm.err; then + msg="$(cat /tmp/fs_rm.err 2>/dev/null || true)" + err "rm failed for $path: ${msg:-unknown error}" + fi + + echo "Path removed: $path" >> "$OUT" + exit 0 } eval "$(argc --argc-eval "$0" "$@")" +main + diff --git a/tools/fs_write.sh b/tools/fs_write.sh index e418835..746c24b 100755 --- a/tools/fs_write.sh +++ b/tools/fs_write.sh @@ -1,25 +1,56 @@ #!/usr/bin/env bash -set -e +set -uo pipefail # @describe Write the full file contents to a file at the specified path. - # @option --path! The path of the file to write to # @option --contents! The full contents to write to the file - # @env LLM_OUTPUT=/dev/stdout The output path ROOT_DIR="${LLM_ROOT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}" +OUT="${LLM_OUTPUT:-/dev/stdout}" + +err() { + echo "ERROR: $*" >> "$OUT" + exit 0 +} main() { - if [[ -f "$argc_path" ]]; then - printf "%s" "$argc_contents" | git diff --no-index "$argc_path" - || true - "$ROOT_DIR/utils/guard_operation.sh" "Apply changes?" - else - "$ROOT_DIR/utils/guard_path.sh" "$argc_path" "Write '$argc_path'?" - mkdir -p "$(dirname "$argc_path")" + path="${argc_path:-}" + contents="${argc_contents:-}" + + [[ -z "$path" ]] && err "missing --path" + # contents darf leer sein – das ist erlaubt (File leeren) + dir="$(dirname "$path")" + + if [[ -e "$path" && ! -f "$path" ]]; then + err "target exists but is not a regular file: $path" + fi + + if [[ -f "$path" ]]; then + # Diff in Output schreiben (damit LLM es sieht) + printf "%s" "$contents" | git diff --no-index "$path" - >> "$OUT" 2>/dev/null || true + if ! "$ROOT_DIR/utils/guard_operation.sh" "Apply changes?" >>"$OUT" 2>&1; then + err "operation cancelled by user" + fi + else + if ! "$ROOT_DIR/utils/guard_path.sh" "$path" "Write '$path'?" >>"$OUT" 2>&1; then + err "operation cancelled by user" + fi + if ! mkdir -p "$dir" 2>/tmp/fs_write_mkdir.err; then + msg="$(cat /tmp/fs_write_mkdir.err 2>/dev/null || true)" + err "failed to create parent dir $dir: ${msg:-unknown error}" fi - printf "%s" "$argc_contents" > "$argc_path" - echo "The contents written to: $argc_path" >> "$LLM_OUTPUT" + fi + + if ! printf "%s" "$contents" > "$path" 2>/tmp/fs_write.err; then + msg="$(cat /tmp/fs_write.err 2>/dev/null || true)" + err "failed to write file $path: ${msg:-unknown error}" + fi + + echo "The contents written to: $path" >> "$OUT" + exit 0 } eval "$(argc --argc-eval "$0" "$@")" +main + |
