Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: improve bash code #125

Merged
merged 2 commits into from
Nov 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion agents/coder/index.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ instructions: |

1. fs_mkdir: Create new directories in the project structure.
2. fs_create: Generate new files with specified contents.
3. fs_edit: Examine and modify existing files. FULLY.
3. fs_patch: Examine and modify existing files.
4. fs_cat: View the contents of existing files without making changes.
5. fs_ls: Understand the current project structure or locate specific files.
6. web_search: Obtain current information on technologies, libraries, or best practices.
Expand Down
51 changes: 3 additions & 48 deletions agents/coder/tools.sh
Original file line number Diff line number Diff line change
@@ -1,64 +1,19 @@
#!/usr/bin/env bash
set -e

ROOT_DIR="${LLM_ROOT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}"

# @env LLM_OUTPUT=/dev/stdout The output path

# @cmd Create a new file at the specified path with contents.
# @option --path! The path where the file should be created
# @option --contents! The contents of the file
fs_create() {
_guard_path "$argc_path" Create
"$ROOT_DIR/utils/guard_path.sh" "$argc_path" "Create '$argc_path'?"
mkdir -p "$(dirname "$argc_path")"
printf "%s" "$argc_contents" > "$argc_path"
echo "File created: $argc_path" >> "$LLM_OUTPUT"
}

# @cmd Apply changes to a file. Use this when you need to edit an existing file.
# YOU ALWAYS PROVIDE THE FULL FILE CONTENTS WHEN EDITING. NO PARTIAL CONTENTS OR COMMENTS.
# YOU MUST PROVIDE THE FULL FILE CONTENTS.

# @option --path! The path of the file to edit
# @option --contents! The new contents to apply to the file
# @meta require-tools git
fs_edit() {
if [[ -f "$argc_path" ]]; then
_guard_path "$argc_path" Edit
changed=0
printf "%s" "$argc_contents" | git diff --no-index "$argc_path" - || {
changed=1
}
if [[ "$changed" -eq 0 ]]; then
echo "No changes detected." >> "$LLM_OUTPUT"
else
if [ -t 1 ]; then
echo
read -r -p "Apply changes? [Y/n] " ans
if [[ "$ans" == "N" || "$ans" == "n" ]]; then
echo "Aborted!"
exit 1
fi
fi
printf "%s" "$argc_contents" > "$argc_path"
echo "Applied changes" >> "$LLM_OUTPUT"
fi
else
echo "Not found file: $argc_path" >> "$LLM_OUTPUT"
fi
}

_guard_path() {
path="$(realpath -m "$1")"
action="$2"
if [[ ! "$path" == "$(pwd)"* ]]; then
if [ -t 1 ]; then
read -r -p "$action $path? [Y/n] " ans
if [[ "$ans" == "N" || "$ans" == "n" ]]; then
echo "Aborted!"
exit 1
fi
fi
fi
}

# See more details at https://github.com/sigoden/argc
eval "$(argc --argc-eval "$0" "$@")"
1 change: 1 addition & 0 deletions agents/coder/tools.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
fs_mkdir.sh
fs_ls.sh
fs_patch.sh
fs_cat.sh
web_search.sh
10 changes: 3 additions & 7 deletions agents/todo/tools.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#!/usr/bin/env bash
set -e

ROOT_DIR="${LLM_ROOT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}"

# @env LLM_OUTPUT=/dev/stdout The output path

# @cmd Add a new todo item
Expand Down Expand Up @@ -65,13 +67,7 @@ list_todos() {
clear_todos() {
todos_file="$(_get_todos_file)"
if [[ -f "$todos_file" ]]; then
if [ -t 1 ]; then
read -r -p "Clean the entire todo list? [Y/n] " ans
if [[ "$ans" == "N" || "$ans" == "n" ]]; then
echo "Aborted!"
exit 1
fi
fi
"$ROOT_DIR/utils/guard_operation.sh" "Clean the entire todo list?"
rm -rf "$todos_file"
echo "Successfully cleaned the entire todo list" >> "$LLM_OUTPUT"
else
Expand Down
2 changes: 1 addition & 1 deletion scripts/declarations-util.sh
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ end
fi
fi
if [[ -z "$json_type" ]]; then
echo "invalid JSON data"
echo "error: invalid JSON data" >&2
exit 1
fi
}
Expand Down
4 changes: 2 additions & 2 deletions scripts/run-agent.sh
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ load_env() {

run() {
if [[ -z "$agent_data" ]]; then
die "No JSON data"
die "error: no JSON data"
fi

if [[ "$OS" == "Windows_NT" ]]; then
Expand Down Expand Up @@ -81,7 +81,7 @@ def to_args:
EOF
)"
args="$(echo "$agent_data" | jq -r "$jq_script" 2>/dev/null)" || {
die "Invalid JSON data"
die "error: invalid JSON data"
}

no_llm_output=0
Expand Down
4 changes: 2 additions & 2 deletions scripts/run-tool.sh
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ load_env() {

run() {
if [[ -z "$tool_data" ]]; then
die "No JSON data"
die "error: no JSON data"
fi

if [[ "$OS" == "Windows_NT" ]]; then
Expand Down Expand Up @@ -77,7 +77,7 @@ def to_args:
EOF
)"
args="$(echo "$tool_data" | jq -r "$jq_script" 2>/dev/null)" || {
die "Invalid JSON data"
die "error: invalid JSON data"
}

no_llm_output=0
Expand Down
10 changes: 3 additions & 7 deletions tools/execute_command.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,10 @@ set -e

# @env LLM_OUTPUT=/dev/stdout The output path

ROOT_DIR="${LLM_ROOT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"

main() {
if [ -t 1 ]; then
read -r -p "Are you sure you want to continue? [Y/n] " ans
if [[ "$ans" == "N" || "$ans" == "n" ]]; then
echo "Aborted!"
exit 1
fi
fi
"$ROOT_DIR/utils/guard_operation.sh"
eval "$argc_command" >> "$LLM_OUTPUT"
}

Expand Down
10 changes: 3 additions & 7 deletions tools/execute_sql_code.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,11 @@ set -e
# @env USQL_DSN! The database url, e.g. pgsql://user:pass@host/dbname
# @env LLM_OUTPUT=/dev/stdout The output path

ROOT_DIR="${LLM_ROOT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"

main() {
if ! grep -qi '^select' <<<"$argc_code"; then
if [ -t 1 ]; then
read -r -p "Are you sure you want to continue? [Y/n] " ans
if [[ "$ans" == "N" || "$ans" == "n" ]]; then
echo "Aborted!"
exit 1
fi
fi
"$ROOT_DIR/utils/guard_operation.sh"
fi
usql -c "$argc_code" "$USQL_DSN" >> "$LLM_OUTPUT"
}
Expand Down
14 changes: 4 additions & 10 deletions tools/fs_patch.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,16 @@ set -e

# @env LLM_OUTPUT=/dev/stdout The output path

ROOT_DIR="${LLM_ROOT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"

main() {
if [ ! -f "$argc_path" ]; then
echo "Not found file: $argc_path"
exit 1
fi
root_dir="${LLM_ROOT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
new_contents="$(awk -f "$root_dir/utils/patch.awk" "$argc_path" <(printf "%s" "$argc_contents"))"
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
if [ -t 1 ]; then
echo
read -r -p "Apply changes? [Y/n] " ans
if [[ "$ans" == "N" || "$ans" == "n" ]]; then
echo "Aborted!"
exit 1
fi
fi
"$ROOT_DIR/utils/guard_operation.sh" "Apply changes?"
printf "%s" "$new_contents" > "$argc_path"

echo "The patch applied to: $argc_path" >> "$LLM_OUTPUT"
Expand Down
18 changes: 3 additions & 15 deletions tools/fs_rm.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,14 @@ set -e

# @env LLM_OUTPUT=/dev/stdout The output path

ROOT_DIR="${LLM_ROOT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"

main() {
if [[ -f "$argc_path" ]]; then
_guard_path "$argc_path" Remove
"$ROOT_DIR/utils/guard_path.sh" "$argc_path" "Remove '$argc_path'?"
rm -rf "$argc_path"
fi
echo "Path removed: $argc_path" >> "$LLM_OUTPUT"
}

_guard_path() {
path="$(realpath -m "$1")"
action="$2"
if [[ ! "$path" == "$(pwd)"* ]]; then
if [ -t 1 ]; then
read -r -p "$action $path? [Y/n] " ans
if [[ "$ans" == "N" || "$ans" == "n" ]]; then
echo "Aborted!"
exit 1
fi
fi
fi
}

eval "$(argc --argc-eval "$0" "$@")"
18 changes: 3 additions & 15 deletions tools/fs_write.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,13 @@ set -e

# @env LLM_OUTPUT=/dev/stdout The output path

ROOT_DIR="${LLM_ROOT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"

main() {
_guard_path "$argc_path" Write
"$ROOT_DIR/utils/guard_path.sh" "$argc_path" "Write '$argc_path'?"
mkdir -p "$(dirname "$argc_path")"
printf "%s" "$argc_contents" > "$argc_path"
echo "The contents written to: $argc_path" >> "$LLM_OUTPUT"
}

_guard_path() {
path="$(realpath -m "$1")"
action="$2"
if [[ ! "$path" == "$(pwd)"* ]]; then
if [ -t 1 ]; then
read -r -p "$action $path? [Y/n] " ans
if [[ "$ans" == "N" || "$ans" == "n" ]]; then
echo "Aborted!"
exit 1
fi
fi
fi
}

eval "$(argc --argc-eval "$0" "$@")"
2 changes: 1 addition & 1 deletion tools/search_wikipedia.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ main() {
title="$(echo "$json" | jq -r '.query.search[0].title // empty')"
pageid="$(echo "$json" | jq -r '.query.search[0].pageid // empty')"
if [[ -z "$title" || -z "$pageid" ]]; then
echo "Error: No results found for '$argc_query'"
echo "error: no results for '$argc_query'" >&2
exit 1
fi
title="$(echo "$title" | tr ' ' '_')"
Expand Down
4 changes: 2 additions & 2 deletions tools/send_twilio.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ main() {
if [[ "$(echo "$body" | jq -r 'has("sid")')" == "true" ]]; then
echo "Message sent successfully" >> "$LLM_OUTPUT"
else
_die "$body"
_die "error: $body"
fi
else
_die "$body"
_die "error: $body"
fi
}

Expand Down
16 changes: 16 additions & 0 deletions utils/guard_operation.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env bash

# Guard an operation with a confirmation prompt.

main() {
if [ -t 1 ]; then
confirmation_prompt="${1:-"Are you sure you want to continue?"}"
read -r -p "$confirmation_prompt [Y/n] " ans
if [[ "$ans" == "N" || "$ans" == "n" ]]; then
echo "error: aborted!" 2>&1
exit 1
fi
fi
}

main "$@"
60 changes: 60 additions & 0 deletions utils/guard_path.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/usr/bin/env bash

main() {
if [[ "$#" -ne 2 ]]; then
echo "Usage: guard_path.sh <path> <confirmation_prompt>" >&2
exit 1
fi
if [ -t 1 ]; then
path="$(_to_realpath "$1")"
confirmation_prompt="$2"
if [[ ! "$path" == "$(pwd)"* ]]; then
read -r -p "$confirmation_prompt [Y/n] " ans
if [[ "$ans" == "N" || "$ans" == "n" ]]; then
echo "error: aborted!" >&2
exit 1
fi
fi
fi
}

_to_realpath() {
path="$1"
if [[ $OS == "Windows_NT" ]]; then
path="$(cygpath -u "$path")"
fi
awk -v path="$path" -v pwd="$PWD" '
BEGIN {
if (path !~ /^\//) {
path = pwd "/" path
}
if (path ~ /\/\.{1,2}?$/) {
isDir = 1
}
split(path, parts, "/")
newPartsLength = 0
for (i = 1; i <= length(parts); i++) {
part = parts[i]
if (part == "..") {
if (newPartsLength > 0) {
delete newParts[newPartsLength--]
}
} else if (part != "." && part != "") {
newParts[++newPartsLength] = part
}
}
if (isDir == 1 || newPartsLength == 0) {
newParts[++newPartsLength] = ""
}
printf "/"
for (i = 1; i <= newPartsLength; i++) {
newPart = newParts[i]
printf newPart
if (i < newPartsLength) {
printf "/"
}
}
}'
}

main "$@"
4 changes: 2 additions & 2 deletions utils/patch.awk
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ END {
}

if (hunkIndex == 0) {
print "No patch" > "/dev/stderr"
print "error: no patch" > "/dev/stderr"
exit 1
}

Expand Down Expand Up @@ -90,7 +90,7 @@ END {
}

if (hunkIndex != totalHunks + 1) {
print "Failed to patch the file" > "/dev/stderr"
print "error: unable to apply patch" > "/dev/stderr"
exit 1
}
}
Expand Down