docs(agents): refine bash guidelines and update code samples

- Expand AGENTS.md with general agent guidance and coding conventions
- Refactor bash snippets in README.md and scripts to align with style guide:
  - Use `#!/usr/bin/env bash` shebang for portability
  - Remove `function` keyword from definitions
  - Replace `[ ]` conditionals with `[[ ]]` for improved reliability
  - Rename local variables to lowercase with `local` keyword
- Introduce CHANGELOG.md to track project changes per Keep a Changelog spec
- Update taskfile.build scripts to follow consistent bash practices
This commit is contained in:
Janik von Rotz committed 2025-10-29 12:32:51 +01:00
1 parent cb0f9330af
commit 5b992d4ee0
25 files changed
+386 -322

No files matched your search

+7 -7
View File
@@ -1,10 +1,10 @@
#!/bin/bash
#!/usr/bin/env bash
function copy-env() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
if test -z "$2"; then echo "\$2 is empty."; exit; fi
copy-env() {
if [[ -z "$1" ]]; then echo "\$1 is empty."; exit; fi
if [[ -z "$2" ]]; then echo "\$2 is empty."; exit; fi
TASK_CONFIG_DIR=${TASK_CONFIG_DIR:="$HOME/.config/taskfile.build"}
SOURCE_ENV="$TASK_CONFIG_DIR/.env.$1"
TARGET_ENV="$TASK_CONFIG_DIR/.env.$2"
cp "$SOURCE_ENV" "$TARGET_ENV"
local source_env="$TASK_CONFIG_DIR/.env.$1"
local target_env="$TASK_CONFIG_DIR/.env.$2"
cp "$source_env" "$target_env"
}
+10 -10
View File
@@ -1,19 +1,19 @@
#!/bin/bash
#!/usr/bin/env bash
function create-nextcloud-env() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
create-nextcloud-env() {
if [[ -z "$1" ]]; then echo "\$1 is empty."; exit; fi
init-config-dir
ENV_FILEPATH="$TASK_CONFIG_DIR/.env.$1"
if [ -f "$ENV_FILEPATH" ]; then
echo "Env file already exists: $ENV_FILEPATH"
local env_filepath="$TASK_CONFIG_DIR/.env.$1"
if [[ -f "$env_filepath" ]]; then
echo "Env file already exists: $env_filepath"
exit 1
fi
echo "Init env file: $ENV_FILEPATH"
echo "NEXTCLOUD_URL=" > "$ENV_FILEPATH"
echo "NEXTCLOUD_USERNAME=" >> "$ENV_FILEPATH"
echo "NEXTCLOUD_PASSWORD=" >> "$ENV_FILEPATH"
echo "Init env file: $env_filepath"
echo "NEXTCLOUD_URL=" > "$env_filepath"
echo "NEXTCLOUD_USERNAME=" >> "$env_filepath"
echo "NEXTCLOUD_PASSWORD=" >> "$env_filepath"
echo "Edit with: task edit-env $1"
}
+11 -11
View File
@@ -1,20 +1,20 @@
#!/bin/bash
#!/usr/bin/env bash
function create-odoo-env() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
create-odoo-env() {
if [[ -z "$1" ]]; then echo "\$1 is empty."; exit; fi
init-config-dir
ENV_FILEPATH="$TASK_CONFIG_DIR/.env.$1"
if [ -f "$ENV_FILEPATH" ]; then
echo "Env file already exists: $ENV_FILEPATH"
local env_filepath="$TASK_CONFIG_DIR/.env.$1"
if [[ -f "$env_filepath" ]]; then
echo "Env file already exists: $env_filepath"
exit 1
fi
echo "Init env file: $ENV_FILEPATH"
echo "ODOO_URL=$ODOO_URL" > "$ENV_FILEPATH"
echo "ODOO_DATABASE=$ODOO_DATABASE" >> "$ENV_FILEPATH"
echo "ODOO_USERNAME=$ODOO_USERNAME" >> "$ENV_FILEPATH"
echo "ODOO_PASSWORD=$ODOO_PASSWORD" >> "$ENV_FILEPATH"
echo "Init env file: $env_filepath"
echo "ODOO_URL=$ODOO_URL" > "$env_filepath"
echo "ODOO_DATABASE=$ODOO_DATABASE" >> "$env_filepath"
echo "ODOO_USERNAME=$ODOO_USERNAME" >> "$env_filepath"
echo "ODOO_PASSWORD=$ODOO_PASSWORD" >> "$env_filepath"
echo "Edit with: task edit-env $1"
}
+5 -5
View File
@@ -1,8 +1,8 @@
#!/bin/bash
#!/usr/bin/env bash
function edit-env() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
edit-env() {
if [[ -z "$1" ]]; then echo "\$1 is empty."; exit; fi
TASK_CONFIG_DIR=${TASK_CONFIG_DIR:="$HOME/.config/taskfile.build"}
ENV_FILEPATH="$TASK_CONFIG_DIR/.env.$1"
"$EDITOR" "$ENV_FILEPATH"
local env_filepath="$TASK_CONFIG_DIR/.env.$1"
"$EDITOR" "$env_filepath"
}
+2 -2
View File
@@ -1,6 +1,6 @@
#!/bin/bash
#!/usr/bin/env bash
function init-config-dir() {
init-config-dir() {
echo "Ensure $TASK_CONFIG_DIR exists"
mkdir -p "$TASK_CONFIG_DIR"
}
+4 -4
View File
@@ -1,13 +1,13 @@
#!/bin/bash
#!/usr/bin/env bash
function init-venv() {
if [ ! -d "venv$GIT_BRANCH" ]; then
init-venv() {
if [[ ! -d "venv$GIT_BRANCH" ]]; then
echo "Create virtualenv venv$GIT_BRANCH."
uv venv "venv$GIT_BRANCH"
fi
}
function activate-venv() {
activate-venv() {
echo "Source virtualenv venv$GIT_BRANCH."
source "venv$GIT_BRANCH/bin/activate"
}
+12 -12
View File
@@ -1,27 +1,27 @@
#!/bin/bash
#!/usr/bin/env bash
function list-env() {
list-env() {
TASK_CONFIG_DIR=${TASK_CONFIG_DIR:="$HOME/.config/taskfile.build"}
# Define column widths
name_width=20
file_width=10
local name_width=20
local file_width=10
# Print table header
printf "| %-${name_width}s | %-${file_width}s |\n" "Name" "Type"
echo "|$(printf '%*s' $((name_width + 2)) '' | tr ' ' '-')|$(printf '%*s' $((file_width + 2)) '' | tr ' ' '-')|"
for ENV_FILE in "$TASK_CONFIG_DIR"/.env.*; do
if [ -f "$ENV_FILE" ]; then
ENV_NAME="${ENV_FILE##*/}"
ENV_NAME="${ENV_NAME#.env.}"
for env_file in "$TASK_CONFIG_DIR"/.env.*; do
if [[ -f "$env_file" ]]; then
local env_name="${env_file##*/}"
env_name="${env_name#.env.}"
ENV_TYPE="Odoo"
if grep -q "NEXTCLOUD" "$ENV_FILE"; then
ENV_TYPE="Nextcloud"
local env_type="Odoo"
if grep -q "NEXTCLOUD" "$env_file"; then
env_type="Nextcloud"
fi
printf "| %-${name_width}s | %-${file_width}s |\n" "$ENV_NAME" "$ENV_TYPE"
printf "| %-${name_width}s | %-${file_width}s |\n" "$env_name" "$env_type"
fi
done
}
+2 -2
View File
@@ -1,6 +1,6 @@
#!/bin/bash
#!/usr/bin/env bash
function load-dotenv-from-keepass {
load-dotenv-from-keepass() {
echo "Restore .env file from keepassxc: $KEEPASS_ENTRY"
keepassxc-cli attachment-export \
--key-file "$KEEPASS_DATABASE_KEY_FILE" \
+2 -2
View File
@@ -1,6 +1,6 @@
#!/bin/bash
#!/usr/bin/env bash
function load-dotenv-from-pass() {
load-dotenv-from-pass() {
if pass find "$PASS_ENTRY" >/dev/null; then
echo "Restore .env file from pass: $PASS_ENTRY"
pass show "$PASS_ENTRY" > .env
+5 -5
View File
@@ -1,10 +1,10 @@
#!/bin/bash
#!/usr/bin/env bash
function load-env() {
load-env() {
TASK_CONFIG_DIR=${TASK_CONFIG_DIR:="$HOME/.config/taskfile.build"}
ENV_FILEPATH="$TASK_CONFIG_DIR/.env.$1"
echo "Source env file $ENV_FILEPATH"
source "$ENV_FILEPATH"
local env_filepath="$TASK_CONFIG_DIR/.env.$1"
echo "Source env file $env_filepath"
source "$env_filepath"
export ODOO_URL
export ODOO_DATABASE
+4 -4
View File
@@ -1,14 +1,14 @@
#!/bin/bash
#!/usr/bin/env bash
function login-docker() {
if [ -z "$1" ]; then
login-docker() {
if [[ -z "$1" ]]; then
echo "Enter Docker login credentials for $DOCKER_REGISTRY registry."
read -p "Enter username: " DOCKER_USERNAME
else
DOCKER_USERNAME="$1"
fi
if [ -z "$2" ]; then
if [[ -z "$2" ]]; then
read -s -p "Enter password: " DOCKER_PASSWORD
else
DOCKER_PASSWORD="$2"
+5 -5
View File
@@ -1,7 +1,7 @@
#!/bin/bash
#!/usr/bin/env bash
function remove-env() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
ENV_FILEPATH="$TASK_CONFIG_DIR/.env.$1"
rm "$ENV_FILEPATH"
remove-env() {
if [[ -z "$1" ]]; then echo "\$1 is empty."; exit; fi
local env_filepath="$TASK_CONFIG_DIR/.env.$1"
rm "$env_filepath"
}
+7 -7
View File
@@ -1,11 +1,11 @@
#!/bin/bash
#!/usr/bin/env bash
function rename-env() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
if test -z "$2"; then echo "\$2 is empty."; exit; fi
rename-env() {
if [[ -z "$1" ]]; then echo "\$1 is empty."; exit; fi
if [[ -z "$2" ]]; then echo "\$2 is empty."; exit; fi
TASK_CONFIG_DIR=${TASK_CONFIG_DIR:="$HOME/.config/taskfile.build"}
SOURCE_ENV="$TASK_CONFIG_DIR/.env.$1"
TARGET_ENV="$TASK_CONFIG_DIR/.env.$2"
local source_env="$TASK_CONFIG_DIR/.env.$1"
local target_env="$TASK_CONFIG_DIR/.env.$2"
echo "Rename $1 to $2."
mv "$SOURCE_ENV" "$TARGET_ENV"
mv "$source_env" "$target_env"
}
+6 -6
View File
@@ -1,12 +1,12 @@
#!/bin/bash
#!/usr/bin/env bash
function restore-env-files() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
restore-env-files() {
if [[ -z "$1" ]]; then echo "\$1 is empty."; exit; fi
TASK_CONFIG_DIR=${TASK_CONFIG_DIR:-$HOME/.config/taskfile.build}
BACKUP_FILEPATH="$1"
local backup_filepath="$1"
echo "Restore env files from: $BACKUP_FILEPATH"
echo "Restore env files from: $backup_filepath"
mkdir -p "$TASK_CONFIG_DIR"
tar -xzf "$BACKUP_FILEPATH" -C "$TASK_CONFIG_DIR"
tar -xzf "$backup_filepath" -C "$TASK_CONFIG_DIR"
}
+3 -3
View File
@@ -1,7 +1,7 @@
#!/bin/bash
#!/usr/bin/env bash
function save-dotenv-to-keepass {
if [ -f .env ]; then
save-dotenv-to-keepass() {
if [[ -f .env ]]; then
echo "Store .env file in keepassxc: $KEEPASS_ENTRY"
keepassxc-cli add \
--key-file "$KEEPASS_DATABASE_KEY_FILE" \
+3 -3
View File
@@ -1,7 +1,7 @@
#!/bin/bash
#!/usr/bin/env bash
function save-dotenv-to-pass() {
if [ -f .env ]; then
save-dotenv-to-pass() {
if [[ -f .env ]]; then
echo "Store .env file in pass: $PASS_ENTRY"
cat .env | pass insert -m -f "$PASS_ENTRY"
else
+6 -6
View File
@@ -1,14 +1,14 @@
#!/bin/bash
#!/usr/bin/env bash
function show-env() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
show-env() {
if [[ -z "$1" ]]; then echo "\$1 is empty."; exit; fi
TASK_CONFIG_DIR=${TASK_CONFIG_DIR:="$HOME/.config/taskfile.build"}
ENV_FILEPATH="$TASK_CONFIG_DIR/.env.$1"
local env_filepath="$TASK_CONFIG_DIR/.env.$1"
if [ ! -f "$ENV_FILEPATH" ]; then
if [[ ! -f "$env_filepath" ]]; then
echo "Environment '$1' not found."
return 1 # Exit with non-zero status if file does not exist
fi
cat "$ENV_FILEPATH" | sed 's/^/export /'
cat "$env_filepath" | sed 's/^/export /'
}
+2 -2
View File
@@ -1,6 +1,6 @@
#!/bin/bash
#!/usr/bin/env bash
function template-dotenv() {
template-dotenv() {
local template=".env.template"
local output=".env"
+2 -2
View File
@@ -1,6 +1,6 @@
#!/bin/bash
#!/usr/bin/env bash
function update-submodule() {
update-submodule() {
echo "Update git submodules."
git submodule update --init --recursive --checkout --depth=1
}
+35 -36
View File
@@ -1,36 +1,35 @@
#!/bin/bash
#!/usr/bin/env bash
function update-with-llm() {
if [ $# -lt 2 ]; then
update-with-llm() {
if [[ $# -lt 2 ]]; then
echo "Usage: update-with-llm [glob] [prompt]"
exit 1
fi
# Get the last argument as the task description
TASK_DESCRIPTION="${@: -1}"
local task_description="${@: -1}"
# All preceding arguments are file paths
FILES=("${@:1:$#-1}")
local files=("${@:1:$#-1}")
echo -e "Load these files into prompt:\n\n${FILES[*]}\n"
echo -e "Task: $TASK_DESCRIPTION"
FILE_CONTENTS=""
for FILE in "${FILES[@]}"; do
FILE_CONTENTS+="<<<$FILE>>>
$(cat "$FILE")
echo -e "Load these files into prompt:\\n\\n${files[*]}\\n"
echo -e "Task: $task_description"
local file_contents=""
for file in "${files[@]}"; do
file_contents+="<<<$file>>>
$(cat "$file")
"
done
# Define prompt content
mkdir -p tmp
PROMPT_FILE="tmp/llm_update"
echo -e "\nWrite prompt to $PROMPT_FILE."
cat << EOF > "$PROMPT_FILE"
local prompt_file="tmp/llm_update"
echo -e "\\nWrite prompt to $prompt_file."
cat << EOF > "$prompt_file"
Look at the code files below and do the following:
$TASK_DESCRIPTION
$task_description
Output all files that you need to change in full again, including your changes.
In the same format as I provide the files below. Under no circumstances output any other text,
@@ -38,43 +37,43 @@ no additional infos, no code formatting chars. Only the code in the given format
Here are the files:
$FILE_CONTENTS
$file_contents
EOF
# Run the llm command
echo -e "Send prompt and wait for the response of the $(llm models | sed -n 's/^Default: //p') LLM."
RESULT=$(cat "$PROMPT_FILE" | llm)
local result=$(cat "$prompt_file" | llm)
# Check if result is empty
if [ -z "$RESULT" ]; then
if [[ -z "$result" ]]; then
echo "No response from the model. Exiting."
exit 1
fi
# Save the result to a file
RESULT_FILE="tmp/llm_update_result"
echo "$RESULT" > "$RESULT_FILE"
echo -e "Saved response to $RESULT_FILE.\n"
local result_file="tmp/llm_update_result"
echo "$result" > "$result_file"
echo -e "Saved response to $result_file.\\n"
# Show a preview of result file
less "$RESULT_FILE"
less "$result_file"
# Ask for confirmation before updating files
read -p "Do you want to apply these updates to the files? (y/n): " CONFIRM
if [[ ! "$CONFIRM" =~ ^[Yy]$ ]]; then
read -p "Do you want to apply these updates to the files? (y/n): " confirm
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
exit 0
fi
# Parse the response from the file and update the files directly
echo -e "Parsing the response and updating files...\n"
CURRENT_FILE=""
while IFS= read -r LINE; do
if [[ $LINE =~ ^"<<<"(.*)">>>" ]]; then
CURRENT_FILE="${BASH_REMATCH[1]}"
echo "Update file $CURRENT_FILE."
> "$CURRENT_FILE"
elif [[ -n $CURRENT_FILE ]]; then
echo "$LINE" >> "$CURRENT_FILE"
echo -e "Parsing the response and updating files...\\n"
local current_file=""
while IFS= read -r line; do
if [[ $line =~ ^"<<<"(.*)">>>" ]]; then
current_file="${BASH_REMATCH[1]}"
echo "Update file $current_file."
> "$current_file"
elif [[ -n $current_file ]]; then
echo "$line" >> "$current_file"
fi
done < "$RESULT_FILE"
}
done < "$result_file"
}