feat: Embedded baseline MCP config and global tools

This commit is contained in:
2025-10-10 09:58:20 -06:00
parent 0aa908c8d3
commit 882942385b
29 changed files with 3339 additions and 3 deletions
+35
View File
@@ -0,0 +1,35 @@
{
"mcpServers": {
"github": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"GITHUB_PERSONAL_ACCESS_TOKEN",
"ghcr.io/github/github-mcp-server"
],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "{{GITHUB_PERSONAL_ACCESS_TOKEN}}"
}
},
"gitmcp": {
"command": "npx",
"args": ["mcp-remote", "https://gitmcp.io/docs"]
},
"docker": {
"command": "uvx",
"args": ["docker-mcp"]
},
"slack": {
"command": "npx",
"args": ["-y", "slack-mcp-server@latest", "--transport", "stdio"],
"env": {
"SLACK_MCP_XOXC_TOKEN": "{{SLACK_MCP_XOXC_TOKEN}}",
"SLACK_MCP_XOXD_TOKEN": "{{SLACK_MCP_XOXD_TOKEN}}",
"SLACK_MCP_ADD_MESSAGE_TOOL": true
}
}
}
}
+24
View File
@@ -0,0 +1,24 @@
# demo_py.py
# demo_sh.sh
execute_command.sh
# execute_py_code.py
# execute_sql_code.sh
# fetch_url_via_curl.sh
# fetch_url_via_jina.sh
fs_cat.sh
fs_ls.sh
# fs_mkdir.sh
# fs_patch.sh
# fs_write.sh
get_current_time.sh
# get_current_weather.py
get_current_weather.sh
query_jira_issues.sh
# search_arxiv.sh
# search_wikipedia.sh
# search_wolframalpha.sh
# send_mail.sh
# send_twilio.sh
# web_search_loki.sh
# web_search_perplexity.sh
# web_search_tavily.sh
+38
View File
@@ -0,0 +1,38 @@
import os
from typing import List, Literal, Optional
def run(
string: str,
string_enum: Literal["foo", "bar"],
boolean: bool,
integer: int,
number: float,
array: List[str],
string_optional: Optional[str] = None,
array_optional: Optional[List[str]] = None,
):
"""Demonstrates how to create a tool using Python and how to use comments.
Args:
string: Define a required string property
string_enum: Define a required string property with enum
boolean: Define a required boolean property
integer: Define a required integer property
number: Define a required number property
array: Define a required string array property
string_optional: Define an optional string property
array_optional: Define an optional string array property
"""
output = f"""string: {string}
string_enum: {string_enum}
string_optional: {string_optional}
boolean: {boolean}
integer: {integer}
number: {number}
array: {array}
array_optional: {array_optional}"""
for key, value in os.environ.items():
if key.startswith("LLM_"):
output = f"{output}\n{key}: {value}"
return output
+29
View File
@@ -0,0 +1,29 @@
#!/usr/bin/env bash
set -e
# @describe Demonstrate how to create a tool using Bash and how to use comment tags.
# @option --string! Define a required string property
# @option --string-enum![foo|bar] Define a required string property with enum
# @option --string-optional Define a optional string property
# @flag --boolean Define a boolean property
# @option --integer! <INT> Define a required integer property
# @option --number! <NUM> Define a required number property
# @option --array+ <VALUE> Define a required string array property
# @option --array-optional* Define a optional string array property
# @env LLM_OUTPUT=/dev/stdout The output path
# shellcheck disable=SC2154
main() {
cat <<EOF >> "$LLM_OUTPUT"
string: ${argc_string}
string_enum: ${argc_string_enum}
string_optional: ${argc_string_optional}
boolean: ${argc_boolean}
integer: ${argc_integer}
number: ${argc_number}
array: ${argc_array[@]}
array_optional: ${argc_array_optional[@]}
$(printenv | grep '^LLM_')
EOF
}
+204
View File
@@ -0,0 +1,204 @@
#!/usr/bin/env bash
set -e
# @describe Execute the shell command.
# @option --command! The command to execute.
# @env LLM_OUTPUT=/dev/stdout The output path
PROMPT_UTILS="${LLM_ROOT_DIR:-$(dirname "${BASH_SOURCE[0]}")/..}/utils/prompt-utils.sh"
# shellcheck disable=SC1090
source "$PROMPT_UTILS"
main() {
guard_operation
# shellcheck disable=SC2154
eval "$argc_command" >> "$LLM_OUTPUT"
}
# ARGC-BUILD {
# This block was generated by argc (https://github.com/sigoden/argc).
# Modifying it manually is not recommended
_argc_run() {
if [[ "${1:-}" == "___internal___" ]]; then
_argc_die "error: unsupported ___internal___ command"
fi
if [[ "${OS:-}" == "Windows_NT" ]] && [[ -n "${MSYSTEM:-}" ]]; then
set -o igncr
fi
argc__args=("$(basename "$0" .sh)" "$@")
argc__positionals=()
_argc_index=1
_argc_len="${#argc__args[@]}"
_argc_tools=()
_argc_parse
if [ -n "${argc__fn:-}" ]; then
$argc__fn "${argc__positionals[@]}"
fi
}
_argc_usage() {
cat <<-'EOF'
Execute the shell command.
USAGE: --command <COMMAND>
OPTIONS:
--command <COMMAND> The command to execute.
-h, --help Print help
-V, --version Print version
ENVIRONMENTS:
LLM_OUTPUT The output path [default: /dev/stdout]
EOF
exit
}
_argc_version() {
echo 0.0.0
exit
}
_argc_parse() {
local _argc_key _argc_action
local _argc_subcmds=""
while [[ $_argc_index -lt $_argc_len ]]; do
_argc_item="${argc__args[_argc_index]}"
_argc_key="${_argc_item%%=*}"
case "$_argc_key" in
--help | -help | -h)
_argc_usage
;;
--version | -version | -V)
_argc_version
;;
--)
_argc_dash="${#argc__positionals[@]}"
argc__positionals+=("${argc__args[@]:$((_argc_index + 1))}")
_argc_index=$_argc_len
break
;;
--command)
_argc_take_args "--command <COMMAND>" 1 1 "-" ""
_argc_index=$((_argc_index + _argc_take_args_len + 1))
if [[ -z "${argc_command:-}" ]]; then
argc_command="${_argc_take_args_values[0]:-}"
else
_argc_die "error: the argument \`--command\` cannot be used multiple times"
fi
;;
*)
if _argc_maybe_flag_option "-" "$_argc_item"; then
_argc_die "error: unexpected argument \`$_argc_key\` found"
fi
argc__positionals+=("$_argc_item")
_argc_index=$((_argc_index + 1))
;;
esac
done
_argc_require_params "error: the following required arguments were not provided:" \
'argc_command:--command <COMMAND>'
if [[ -n "${_argc_action:-}" ]]; then
$_argc_action
else
argc__fn=main
if [[ "${argc__positionals[0]:-}" == "help" ]] && [[ "${#argc__positionals[@]}" -eq 1 ]]; then
_argc_usage
fi
if [[ -z "${LLM_OUTPUT:-}" ]]; then
export LLM_OUTPUT=/dev/stdout
fi
fi
}
_argc_take_args() {
_argc_take_args_values=()
_argc_take_args_len=0
local param="$1" min="$2" max="$3" signs="$4" delimiter="$5"
if [[ "$min" -eq 0 ]] && [[ "$max" -eq 0 ]]; then
return
fi
local _argc_take_index=$((_argc_index + 1)) _argc_take_value
if [[ "$_argc_item" == *=* ]]; then
_argc_take_args_values=("${_argc_item##*=}")
else
while [[ $_argc_take_index -lt $_argc_len ]]; do
_argc_take_value="${argc__args[_argc_take_index]}"
if _argc_maybe_flag_option "$signs" "$_argc_take_value"; then
if [[ "${#_argc_take_value}" -gt 1 ]]; then
break
fi
fi
_argc_take_args_values+=("$_argc_take_value")
_argc_take_args_len=$((_argc_take_args_len + 1))
if [[ "$_argc_take_args_len" -ge "$max" ]]; then
break
fi
_argc_take_index=$((_argc_take_index + 1))
done
fi
if [[ "${#_argc_take_args_values[@]}" -lt "$min" ]]; then
_argc_die "error: incorrect number of values for \`$param\`"
fi
if [[ -n "$delimiter" ]] && [[ "${#_argc_take_args_values[@]}" -gt 0 ]]; then
local item values arr=()
for item in "${_argc_take_args_values[@]}"; do
IFS="$delimiter" read -r -a values <<<"$item"
arr+=("${values[@]}")
done
_argc_take_args_values=("${arr[@]}")
fi
}
_argc_require_params() {
local message="$1" missed_envs="" item name render_name
for item in "${@:2}"; do
name="${item%%:*}"
render_name="${item##*:}"
if [[ -z "${!name:-}" ]]; then
missed_envs="$missed_envs"$'\n'" $render_name"
fi
done
if [[ -n "${missed_envs}" ]]; then
_argc_die "$message$missed_envs"
fi
}
_argc_maybe_flag_option() {
local signs="$1" arg="$2"
if [[ -z "$signs" ]]; then
return 1
fi
local cond=false
if [[ "$signs" == *"+"* ]]; then
if [[ "$arg" =~ ^\+[^+].* ]]; then
cond=true
fi
elif [[ "$arg" == -* ]]; then
if (( ${#arg} < 3 )) || [[ ! "$arg" =~ ^---.* ]]; then
cond=true
fi
fi
if [[ "$cond" == "false" ]]; then
return 1
fi
local value="${arg%%=*}"
if [[ "$value" =~ [[:space:]] ]]; then
return 1
fi
return 0
}
_argc_die() {
if [[ $# -eq 0 ]]; then
cat
else
echo "$*" >&2
fi
exit 1
}
_argc_run "$@"
# ARGC-BUILD }
+33
View File
@@ -0,0 +1,33 @@
import ast
import io
from contextlib import redirect_stdout
def run(code: str):
"""Execute the python code.
Args:
code: Python code to execute, such as `print("hello world")`
"""
output = io.StringIO()
with redirect_stdout(output):
value = exec_with_return(code, {}, {})
if value is not None:
output.write(str(value))
return output.getvalue()
def exec_with_return(code: str, globals: dict, locals: dict):
a = ast.parse(code)
last_expression = None
if a.body:
if isinstance(a_last := a.body[-1], ast.Expr):
last_expression = ast.unparse(a.body.pop())
elif isinstance(a_last, ast.Assign):
last_expression = ast.unparse(a_last.targets[0])
elif isinstance(a_last, (ast.AnnAssign, ast.AugAssign)):
last_expression = ast.unparse(a_last.target)
exec(ast.unparse(a), globals, locals)
if last_expression:
return eval(last_expression, globals, locals)
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/env bash
set -e
# @describe Execute sql code.
# @option --code! The code to execute.
# @meta require-tools usql
# @env USQL_DSN! The database connection url. e.g. pgsql://user:pass@host:port
# @env LLM_OUTPUT=/dev/stdout The output path
PROMPT_UTILS="${LLM_ROOT_DIR:-$(dirname "${BASH_SOURCE[0]}")/..}/utils/prompt-utils.sh"
# shellcheck disable=SC1090
source "$PROMPT_UTILS"
# shellcheck disable=SC2154
main() {
if ! grep -qi '^select' <<<"$argc_code"; then
guard_operation ""
fi
usql -c "$argc_code" "$USQL_DSN" >> "$LLM_OUTPUT"
}
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/env bash
set -e
# @describe Extract the content from a given URL.
# @option --url! The URL to scrape.
# @meta require-tools pandoc
# @env LLM_OUTPUT=/dev/stdout The output path
# shellcheck disable=SC2154
main() {
# span and div tags are dropped from the HTML https://pandoc.org/MANUAL.html#raw-htmltex and sed removes any inline SVG images in image tags from the Markdown content.
curl -fsSL "$argc_url" | \
pandoc -f html-native_divs-native_spans -t gfm-raw_html --wrap=none | \
sed -E 's/!\[[^]]*\]\([^)]*\)//g' \
>> "$LLM_OUTPUT"
}
+17
View File
@@ -0,0 +1,17 @@
#!/usr/bin/env bash
set -e
# @describe Extract the content from a given URL.
# @option --url! The URL to scrape.
# @env JINA_API_KEY Your Jina API key
# @env LLM_OUTPUT=/dev/stdout The output path
# shellcheck disable=SC2154
main() {
curl_args=()
if [[ -n "$JINA_API_KEY" ]]; then
curl_args+=("-H" "Authorization: Bearer $JINA_API_KEY")
fi
curl -fsSL "${curl_args[@]}" "https://r.jina.ai/$argc_url" >> "$LLM_OUTPUT"
}
+202
View File
@@ -0,0 +1,202 @@
#!/usr/bin/env bash
set -e
# @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
main() {
# shellcheck disable=SC2154
cat "$argc_path" >> "$LLM_OUTPUT"
}
# ARGC-BUILD {
# This block was generated by argc (https://github.com/sigoden/argc).
# Modifying it manually is not recommended
_argc_run() {
if [[ "${1:-}" == "___internal___" ]]; then
_argc_die "error: unsupported ___internal___ command"
fi
if [[ "${OS:-}" == "Windows_NT" ]] && [[ -n "${MSYSTEM:-}" ]]; then
set -o igncr
fi
argc__args=("$(basename "$0" .sh)" "$@")
argc__positionals=()
_argc_index=1
_argc_len="${#argc__args[@]}"
_argc_tools=()
_argc_parse
if [ -n "${argc__fn:-}" ]; then
$argc__fn "${argc__positionals[@]}"
fi
}
_argc_usage() {
cat <<-'EOF'
Read the contents of a file at the specified path.
Use this when you need to examine the contents of an existing file.
USAGE: --path <PATH>
OPTIONS:
--path <PATH> The path of the file to read
-h, --help Print help
-V, --version Print version
ENVIRONMENTS:
LLM_OUTPUT The output path [default: /dev/stdout]
EOF
exit
}
_argc_version() {
echo 0.0.0
exit
}
_argc_parse() {
local _argc_key _argc_action
local _argc_subcmds=""
while [[ $_argc_index -lt $_argc_len ]]; do
_argc_item="${argc__args[_argc_index]}"
_argc_key="${_argc_item%%=*}"
case "$_argc_key" in
--help | -help | -h)
_argc_usage
;;
--version | -version | -V)
_argc_version
;;
--)
_argc_dash="${#argc__positionals[@]}"
argc__positionals+=("${argc__args[@]:$((_argc_index + 1))}")
_argc_index=$_argc_len
break
;;
--path)
_argc_take_args "--path <PATH>" 1 1 "-" ""
_argc_index=$((_argc_index + _argc_take_args_len + 1))
if [[ -z "${argc_path:-}" ]]; then
argc_path="${_argc_take_args_values[0]:-}"
else
_argc_die "error: the argument \`--path\` cannot be used multiple times"
fi
;;
*)
if _argc_maybe_flag_option "-" "$_argc_item"; then
_argc_die "error: unexpected argument \`$_argc_key\` found"
fi
argc__positionals+=("$_argc_item")
_argc_index=$((_argc_index + 1))
;;
esac
done
_argc_require_params "error: the following required arguments were not provided:" \
'argc_path:--path <PATH>'
if [[ -n "${_argc_action:-}" ]]; then
$_argc_action
else
argc__fn=main
if [[ "${argc__positionals[0]:-}" == "help" ]] && [[ "${#argc__positionals[@]}" -eq 1 ]]; then
_argc_usage
fi
if [[ -z "${LLM_OUTPUT:-}" ]]; then
export LLM_OUTPUT=/dev/stdout
fi
fi
}
_argc_take_args() {
_argc_take_args_values=()
_argc_take_args_len=0
local param="$1" min="$2" max="$3" signs="$4" delimiter="$5"
if [[ "$min" -eq 0 ]] && [[ "$max" -eq 0 ]]; then
return
fi
local _argc_take_index=$((_argc_index + 1)) _argc_take_value
if [[ "$_argc_item" == *=* ]]; then
_argc_take_args_values=("${_argc_item##*=}")
else
while [[ $_argc_take_index -lt $_argc_len ]]; do
_argc_take_value="${argc__args[_argc_take_index]}"
if _argc_maybe_flag_option "$signs" "$_argc_take_value"; then
if [[ "${#_argc_take_value}" -gt 1 ]]; then
break
fi
fi
_argc_take_args_values+=("$_argc_take_value")
_argc_take_args_len=$((_argc_take_args_len + 1))
if [[ "$_argc_take_args_len" -ge "$max" ]]; then
break
fi
_argc_take_index=$((_argc_take_index + 1))
done
fi
if [[ "${#_argc_take_args_values[@]}" -lt "$min" ]]; then
_argc_die "error: incorrect number of values for \`$param\`"
fi
if [[ -n "$delimiter" ]] && [[ "${#_argc_take_args_values[@]}" -gt 0 ]]; then
local item values arr=()
for item in "${_argc_take_args_values[@]}"; do
IFS="$delimiter" read -r -a values <<<"$item"
arr+=("${values[@]}")
done
_argc_take_args_values=("${arr[@]}")
fi
}
_argc_require_params() {
local message="$1" missed_envs="" item name render_name
for item in "${@:2}"; do
name="${item%%:*}"
render_name="${item##*:}"
if [[ -z "${!name:-}" ]]; then
missed_envs="$missed_envs"$'\n'" $render_name"
fi
done
if [[ -n "${missed_envs}" ]]; then
_argc_die "$message$missed_envs"
fi
}
_argc_maybe_flag_option() {
local signs="$1" arg="$2"
if [[ -z "$signs" ]]; then
return 1
fi
local cond=false
if [[ "$signs" == *"+"* ]]; then
if [[ "$arg" =~ ^\+[^+].* ]]; then
cond=true
fi
elif [[ "$arg" == -* ]]; then
if (( ${#arg} < 3 )) || [[ ! "$arg" =~ ^---.* ]]; then
cond=true
fi
fi
if [[ "$cond" == "false" ]]; then
return 1
fi
local value="${arg%%=*}"
if [[ "$value" =~ [[:space:]] ]]; then
return 1
fi
return 0
}
_argc_die() {
if [[ $# -eq 0 ]]; then
cat
else
echo "$*" >&2
fi
exit 1
}
_argc_run "$@"
# ARGC-BUILD }
+200
View File
@@ -0,0 +1,200 @@
#!/usr/bin/env bash
set -e
# @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
main() {
# shellcheck disable=SC2154
ls -1 "$argc_path" >> "$LLM_OUTPUT"
}
# ARGC-BUILD {
# This block was generated by argc (https://github.com/sigoden/argc).
# Modifying it manually is not recommended
_argc_run() {
if [[ "${1:-}" == "___internal___" ]]; then
_argc_die "error: unsupported ___internal___ command"
fi
if [[ "${OS:-}" == "Windows_NT" ]] && [[ -n "${MSYSTEM:-}" ]]; then
set -o igncr
fi
argc__args=("$(basename "$0" .sh)" "$@")
argc__positionals=()
_argc_index=1
_argc_len="${#argc__args[@]}"
_argc_tools=()
_argc_parse
if [ -n "${argc__fn:-}" ]; then
$argc__fn "${argc__positionals[@]}"
fi
}
_argc_usage() {
cat <<-'EOF'
List all files and directories at the specified path.
USAGE: --path <PATH>
OPTIONS:
--path <PATH> The path of the directory to list
-h, --help Print help
-V, --version Print version
ENVIRONMENTS:
LLM_OUTPUT The output path [default: /dev/stdout]
EOF
exit
}
_argc_version() {
echo 0.0.0
exit
}
_argc_parse() {
local _argc_key _argc_action
local _argc_subcmds=""
while [[ $_argc_index -lt $_argc_len ]]; do
_argc_item="${argc__args[_argc_index]}"
_argc_key="${_argc_item%%=*}"
case "$_argc_key" in
--help | -help | -h)
_argc_usage
;;
--version | -version | -V)
_argc_version
;;
--)
_argc_dash="${#argc__positionals[@]}"
argc__positionals+=("${argc__args[@]:$((_argc_index + 1))}")
_argc_index=$_argc_len
break
;;
--path)
_argc_take_args "--path <PATH>" 1 1 "-" ""
_argc_index=$((_argc_index + _argc_take_args_len + 1))
if [[ -z "${argc_path:-}" ]]; then
argc_path="${_argc_take_args_values[0]:-}"
else
_argc_die "error: the argument \`--path\` cannot be used multiple times"
fi
;;
*)
if _argc_maybe_flag_option "-" "$_argc_item"; then
_argc_die "error: unexpected argument \`$_argc_key\` found"
fi
argc__positionals+=("$_argc_item")
_argc_index=$((_argc_index + 1))
;;
esac
done
_argc_require_params "error: the following required arguments were not provided:" \
'argc_path:--path <PATH>'
if [[ -n "${_argc_action:-}" ]]; then
$_argc_action
else
argc__fn=main
if [[ "${argc__positionals[0]:-}" == "help" ]] && [[ "${#argc__positionals[@]}" -eq 1 ]]; then
_argc_usage
fi
if [[ -z "${LLM_OUTPUT:-}" ]]; then
export LLM_OUTPUT=/dev/stdout
fi
fi
}
_argc_take_args() {
_argc_take_args_values=()
_argc_take_args_len=0
local param="$1" min="$2" max="$3" signs="$4" delimiter="$5"
if [[ "$min" -eq 0 ]] && [[ "$max" -eq 0 ]]; then
return
fi
local _argc_take_index=$((_argc_index + 1)) _argc_take_value
if [[ "$_argc_item" == *=* ]]; then
_argc_take_args_values=("${_argc_item##*=}")
else
while [[ $_argc_take_index -lt $_argc_len ]]; do
_argc_take_value="${argc__args[_argc_take_index]}"
if _argc_maybe_flag_option "$signs" "$_argc_take_value"; then
if [[ "${#_argc_take_value}" -gt 1 ]]; then
break
fi
fi
_argc_take_args_values+=("$_argc_take_value")
_argc_take_args_len=$((_argc_take_args_len + 1))
if [[ "$_argc_take_args_len" -ge "$max" ]]; then
break
fi
_argc_take_index=$((_argc_take_index + 1))
done
fi
if [[ "${#_argc_take_args_values[@]}" -lt "$min" ]]; then
_argc_die "error: incorrect number of values for \`$param\`"
fi
if [[ -n "$delimiter" ]] && [[ "${#_argc_take_args_values[@]}" -gt 0 ]]; then
local item values arr=()
for item in "${_argc_take_args_values[@]}"; do
IFS="$delimiter" read -r -a values <<<"$item"
arr+=("${values[@]}")
done
_argc_take_args_values=("${arr[@]}")
fi
}
_argc_require_params() {
local message="$1" missed_envs="" item name render_name
for item in "${@:2}"; do
name="${item%%:*}"
render_name="${item##*:}"
if [[ -z "${!name:-}" ]]; then
missed_envs="$missed_envs"$'\n'" $render_name"
fi
done
if [[ -n "${missed_envs}" ]]; then
_argc_die "$message$missed_envs"
fi
}
_argc_maybe_flag_option() {
local signs="$1" arg="$2"
if [[ -z "$signs" ]]; then
return 1
fi
local cond=false
if [[ "$signs" == *"+"* ]]; then
if [[ "$arg" =~ ^\+[^+].* ]]; then
cond=true
fi
elif [[ "$arg" == -* ]]; then
if (( ${#arg} < 3 )) || [[ ! "$arg" =~ ^---.* ]]; then
cond=true
fi
fi
if [[ "$cond" == "false" ]]; then
return 1
fi
local value="${arg%%=*}"
if [[ "$value" =~ [[:space:]] ]]; then
return 1
fi
return 0
}
_argc_die() {
if [[ $# -eq 0 ]]; then
cat
else
echo "$*" >&2
fi
exit 1
}
_argc_run "$@"
# ARGC-BUILD }
+201
View File
@@ -0,0 +1,201 @@
#!/usr/bin/env bash
set -e
# @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
main() {
# shellcheck disable=SC2154
mkdir -p "$argc_path"
echo "Directory created: $argc_path" >> "$LLM_OUTPUT"
}
# ARGC-BUILD {
# This block was generated by argc (https://github.com/sigoden/argc).
# Modifying it manually is not recommended
_argc_run() {
if [[ "${1:-}" == "___internal___" ]]; then
_argc_die "error: unsupported ___internal___ command"
fi
if [[ "${OS:-}" == "Windows_NT" ]] && [[ -n "${MSYSTEM:-}" ]]; then
set -o igncr
fi
argc__args=("$(basename "$0" .sh)" "$@")
argc__positionals=()
_argc_index=1
_argc_len="${#argc__args[@]}"
_argc_tools=()
_argc_parse
if [ -n "${argc__fn:-}" ]; then
$argc__fn "${argc__positionals[@]}"
fi
}
_argc_usage() {
cat <<-'EOF'
Create a new directory at the specified path.
USAGE: --path <PATH>
OPTIONS:
--path <PATH> The path of the directory to create
-h, --help Print help
-V, --version Print version
ENVIRONMENTS:
LLM_OUTPUT The output path [default: /dev/stdout]
EOF
exit
}
_argc_version() {
echo 0.0.0
exit
}
_argc_parse() {
local _argc_key _argc_action
local _argc_subcmds=""
while [[ $_argc_index -lt $_argc_len ]]; do
_argc_item="${argc__args[_argc_index]}"
_argc_key="${_argc_item%%=*}"
case "$_argc_key" in
--help | -help | -h)
_argc_usage
;;
--version | -version | -V)
_argc_version
;;
--)
_argc_dash="${#argc__positionals[@]}"
argc__positionals+=("${argc__args[@]:$((_argc_index + 1))}")
_argc_index=$_argc_len
break
;;
--path)
_argc_take_args "--path <PATH>" 1 1 "-" ""
_argc_index=$((_argc_index + _argc_take_args_len + 1))
if [[ -z "${argc_path:-}" ]]; then
argc_path="${_argc_take_args_values[0]:-}"
else
_argc_die "error: the argument \`--path\` cannot be used multiple times"
fi
;;
*)
if _argc_maybe_flag_option "-" "$_argc_item"; then
_argc_die "error: unexpected argument \`$_argc_key\` found"
fi
argc__positionals+=("$_argc_item")
_argc_index=$((_argc_index + 1))
;;
esac
done
_argc_require_params "error: the following required arguments were not provided:" \
'argc_path:--path <PATH>'
if [[ -n "${_argc_action:-}" ]]; then
$_argc_action
else
argc__fn=main
if [[ "${argc__positionals[0]:-}" == "help" ]] && [[ "${#argc__positionals[@]}" -eq 1 ]]; then
_argc_usage
fi
if [[ -z "${LLM_OUTPUT:-}" ]]; then
export LLM_OUTPUT=/dev/stdout
fi
fi
}
_argc_take_args() {
_argc_take_args_values=()
_argc_take_args_len=0
local param="$1" min="$2" max="$3" signs="$4" delimiter="$5"
if [[ "$min" -eq 0 ]] && [[ "$max" -eq 0 ]]; then
return
fi
local _argc_take_index=$((_argc_index + 1)) _argc_take_value
if [[ "$_argc_item" == *=* ]]; then
_argc_take_args_values=("${_argc_item##*=}")
else
while [[ $_argc_take_index -lt $_argc_len ]]; do
_argc_take_value="${argc__args[_argc_take_index]}"
if _argc_maybe_flag_option "$signs" "$_argc_take_value"; then
if [[ "${#_argc_take_value}" -gt 1 ]]; then
break
fi
fi
_argc_take_args_values+=("$_argc_take_value")
_argc_take_args_len=$((_argc_take_args_len + 1))
if [[ "$_argc_take_args_len" -ge "$max" ]]; then
break
fi
_argc_take_index=$((_argc_take_index + 1))
done
fi
if [[ "${#_argc_take_args_values[@]}" -lt "$min" ]]; then
_argc_die "error: incorrect number of values for \`$param\`"
fi
if [[ -n "$delimiter" ]] && [[ "${#_argc_take_args_values[@]}" -gt 0 ]]; then
local item values arr=()
for item in "${_argc_take_args_values[@]}"; do
IFS="$delimiter" read -r -a values <<<"$item"
arr+=("${values[@]}")
done
_argc_take_args_values=("${arr[@]}")
fi
}
_argc_require_params() {
local message="$1" missed_envs="" item name render_name
for item in "${@:2}"; do
name="${item%%:*}"
render_name="${item##*:}"
if [[ -z "${!name:-}" ]]; then
missed_envs="$missed_envs"$'\n'" $render_name"
fi
done
if [[ -n "${missed_envs}" ]]; then
_argc_die "$message$missed_envs"
fi
}
_argc_maybe_flag_option() {
local signs="$1" arg="$2"
if [[ -z "$signs" ]]; then
return 1
fi
local cond=false
if [[ "$signs" == *"+"* ]]; then
if [[ "$arg" =~ ^\+[^+].* ]]; then
cond=true
fi
elif [[ "$arg" == -* ]]; then
if (( ${#arg} < 3 )) || [[ ! "$arg" =~ ^---.* ]]; then
cond=true
fi
fi
if [[ "$cond" == "false" ]]; then
return 1
fi
local value="${arg%%=*}"
if [[ "$value" =~ [[:space:]] ]]; then
return 1
fi
return 0
}
_argc_die() {
if [[ $# -eq 0 ]]; then
cat
else
echo "$*" >&2
fi
exit 1
}
_argc_run "$@"
# ARGC-BUILD }
+229
View File
@@ -0,0 +1,229 @@
#!/usr/bin/env bash
set -e
# @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 the patch to
# @option --contents! The patch to apply to the file
# @env LLM_OUTPUT=/dev/stdout The output path
PROMPT_UTILS="${LLM_ROOT_DIR:-$(dirname "${BASH_SOURCE[0]}")/..}/utils/prompt-utils.sh"
# shellcheck disable=SC1090
source "$PROMPT_UTILS"
# shellcheck disable=SC2154
main() {
if [[ ! -f "$argc_path" ]]; then
error "Unable to find the specified file: $argc_path"
exit 1
fi
new_contents="$(patch_file "$argc_path" <(printf "%s" "$argc_contents"))"
printf "%s" "$new_contents" | git diff --no-index "$argc_path" - || true
guard_operation "Apply changes?"
printf "%s" "$new_contents" > "$argc_path"
info "Applied the patch to: $argc_path" >> "$LLM_OUTPUT"
}
# ARGC-BUILD {
# This block was generated by argc (https://github.com/sigoden/argc).
# Modifying it manually is not recommended
_argc_run() {
if [[ "${1:-}" == "___internal___" ]]; then
_argc_die "error: unsupported ___internal___ command"
fi
if [[ "${OS:-}" == "Windows_NT" ]] && [[ -n "${MSYSTEM:-}" ]]; then
set -o igncr
fi
argc__args=("$(basename "$0" .sh)" "$@")
argc__positionals=()
_argc_index=1
_argc_len="${#argc__args[@]}"
_argc_tools=()
_argc_parse
if [ -n "${argc__fn:-}" ]; then
$argc__fn "${argc__positionals[@]}"
fi
}
_argc_usage() {
cat <<-'EOF'
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.
USAGE: --path <PATH> --contents <CONTENTS>
OPTIONS:
--path <PATH> The path of the file to apply the patch to
--contents <CONTENTS> The patch to apply to the file
-h, --help Print help
-V, --version Print version
ENVIRONMENTS:
LLM_OUTPUT The output path [default: /dev/stdout]
EOF
exit
}
_argc_version() {
echo 0.0.0
exit
}
_argc_parse() {
local _argc_key _argc_action
local _argc_subcmds=""
while [[ $_argc_index -lt $_argc_len ]]; do
_argc_item="${argc__args[_argc_index]}"
_argc_key="${_argc_item%%=*}"
case "$_argc_key" in
--help | -help | -h)
_argc_usage
;;
--version | -version | -V)
_argc_version
;;
--)
_argc_dash="${#argc__positionals[@]}"
argc__positionals+=("${argc__args[@]:$((_argc_index + 1))}")
_argc_index=$_argc_len
break
;;
--path)
_argc_take_args "--path <PATH>" 1 1 "-" ""
_argc_index=$((_argc_index + _argc_take_args_len + 1))
if [[ -z "${argc_path:-}" ]]; then
argc_path="${_argc_take_args_values[0]:-}"
else
_argc_die "error: the argument \`--path\` cannot be used multiple times"
fi
;;
--contents)
_argc_take_args "--contents <CONTENTS>" 1 1 "-" ""
_argc_index=$((_argc_index + _argc_take_args_len + 1))
if [[ -z "${argc_contents:-}" ]]; then
argc_contents="${_argc_take_args_values[0]:-}"
else
_argc_die "error: the argument \`--contents\` cannot be used multiple times"
fi
;;
*)
if _argc_maybe_flag_option "-" "$_argc_item"; then
_argc_die "error: unexpected argument \`$_argc_key\` found"
fi
argc__positionals+=("$_argc_item")
_argc_index=$((_argc_index + 1))
;;
esac
done
_argc_require_params "error: the following required arguments were not provided:" \
'argc_path:--path <PATH>' 'argc_contents:--contents <CONTENTS>'
if [[ -n "${_argc_action:-}" ]]; then
$_argc_action
else
argc__fn=main
if [[ "${argc__positionals[0]:-}" == "help" ]] && [[ "${#argc__positionals[@]}" -eq 1 ]]; then
_argc_usage
fi
if [[ -z "${LLM_OUTPUT:-}" ]]; then
export LLM_OUTPUT=/dev/stdout
fi
fi
}
_argc_take_args() {
_argc_take_args_values=()
_argc_take_args_len=0
local param="$1" min="$2" max="$3" signs="$4" delimiter="$5"
if [[ "$min" -eq 0 ]] && [[ "$max" -eq 0 ]]; then
return
fi
local _argc_take_index=$((_argc_index + 1)) _argc_take_value
if [[ "$_argc_item" == *=* ]]; then
_argc_take_args_values=("${_argc_item##*=}")
else
while [[ $_argc_take_index -lt $_argc_len ]]; do
_argc_take_value="${argc__args[_argc_take_index]}"
if _argc_maybe_flag_option "$signs" "$_argc_take_value"; then
if [[ "${#_argc_take_value}" -gt 1 ]]; then
break
fi
fi
_argc_take_args_values+=("$_argc_take_value")
_argc_take_args_len=$((_argc_take_args_len + 1))
if [[ "$_argc_take_args_len" -ge "$max" ]]; then
break
fi
_argc_take_index=$((_argc_take_index + 1))
done
fi
if [[ "${#_argc_take_args_values[@]}" -lt "$min" ]]; then
_argc_die "error: incorrect number of values for \`$param\`"
fi
if [[ -n "$delimiter" ]] && [[ "${#_argc_take_args_values[@]}" -gt 0 ]]; then
local item values arr=()
for item in "${_argc_take_args_values[@]}"; do
IFS="$delimiter" read -r -a values <<<"$item"
arr+=("${values[@]}")
done
_argc_take_args_values=("${arr[@]}")
fi
}
_argc_require_params() {
local message="$1" missed_envs="" item name render_name
for item in "${@:2}"; do
name="${item%%:*}"
render_name="${item##*:}"
if [[ -z "${!name:-}" ]]; then
missed_envs="$missed_envs"$'\n'" $render_name"
fi
done
if [[ -n "${missed_envs}" ]]; then
_argc_die "$message$missed_envs"
fi
}
_argc_maybe_flag_option() {
local signs="$1" arg="$2"
if [[ -z "$signs" ]]; then
return 1
fi
local cond=false
if [[ "$signs" == *"+"* ]]; then
if [[ "$arg" =~ ^\+[^+].* ]]; then
cond=true
fi
elif [[ "$arg" == -* ]]; then
if (( ${#arg} < 3 )) || [[ ! "$arg" =~ ^---.* ]]; then
cond=true
fi
fi
if [[ "$cond" == "false" ]]; then
return 1
fi
local value="${arg%%=*}"
if [[ "$value" =~ [[:space:]] ]]; then
return 1
fi
return 0
}
_argc_die() {
if [[ $# -eq 0 ]]; then
cat
else
echo "$*" >&2
fi
exit 1
}
_argc_run "$@"
# ARGC-BUILD }
+210
View File
@@ -0,0 +1,210 @@
#!/usr/bin/env bash
set -e
# @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
PROMPT_UTILS="${LLM_ROOT_DIR:-$(dirname "${BASH_SOURCE[0]}")/..}/utils/prompt-utils.sh"
# shellcheck disable=SC1090
source "$PROMPT_UTILS"
# shellcheck disable=SC2154
main() {
if [[ -f "$argc_path" ]]; then
guard_path "$argc_path" "Remove '$argc_path'?"
rm -rf "$argc_path"
fi
echo "Path removed: $argc_path" >> "$LLM_OUTPUT"
}
# ARGC-BUILD {
# This block was generated by argc (https://github.com/sigoden/argc).
# Modifying it manually is not recommended
_argc_run() {
if [[ "${1:-}" == "___internal___" ]]; then
_argc_die "error: unsupported ___internal___ command"
fi
if [[ "${OS:-}" == "Windows_NT" ]] && [[ -n "${MSYSTEM:-}" ]]; then
set -o igncr
fi
argc__args=("$(basename "$0" .sh)" "$@")
argc__positionals=()
_argc_index=1
_argc_len="${#argc__args[@]}"
_argc_tools=()
_argc_parse
if [ -n "${argc__fn:-}" ]; then
$argc__fn "${argc__positionals[@]}"
fi
}
_argc_usage() {
cat <<-'EOF'
Remove the file or directory at the specified path.
USAGE: --path <PATH>
OPTIONS:
--path <PATH> The path of the file or directory to remove
-h, --help Print help
-V, --version Print version
ENVIRONMENTS:
LLM_OUTPUT The output path [default: /dev/stdout]
EOF
exit
}
_argc_version() {
echo 0.0.0
exit
}
_argc_parse() {
local _argc_key _argc_action
local _argc_subcmds=""
while [[ $_argc_index -lt $_argc_len ]]; do
_argc_item="${argc__args[_argc_index]}"
_argc_key="${_argc_item%%=*}"
case "$_argc_key" in
--help | -help | -h)
_argc_usage
;;
--version | -version | -V)
_argc_version
;;
--)
_argc_dash="${#argc__positionals[@]}"
argc__positionals+=("${argc__args[@]:$((_argc_index + 1))}")
_argc_index=$_argc_len
break
;;
--path)
_argc_take_args "--path <PATH>" 1 1 "-" ""
_argc_index=$((_argc_index + _argc_take_args_len + 1))
if [[ -z "${argc_path:-}" ]]; then
argc_path="${_argc_take_args_values[0]:-}"
else
_argc_die "error: the argument \`--path\` cannot be used multiple times"
fi
;;
*)
if _argc_maybe_flag_option "-" "$_argc_item"; then
_argc_die "error: unexpected argument \`$_argc_key\` found"
fi
argc__positionals+=("$_argc_item")
_argc_index=$((_argc_index + 1))
;;
esac
done
_argc_require_params "error: the following required arguments were not provided:" \
'argc_path:--path <PATH>'
if [[ -n "${_argc_action:-}" ]]; then
$_argc_action
else
argc__fn=main
if [[ "${argc__positionals[0]:-}" == "help" ]] && [[ "${#argc__positionals[@]}" -eq 1 ]]; then
_argc_usage
fi
if [[ -z "${LLM_OUTPUT:-}" ]]; then
export LLM_OUTPUT=/dev/stdout
fi
fi
}
_argc_take_args() {
_argc_take_args_values=()
_argc_take_args_len=0
local param="$1" min="$2" max="$3" signs="$4" delimiter="$5"
if [[ "$min" -eq 0 ]] && [[ "$max" -eq 0 ]]; then
return
fi
local _argc_take_index=$((_argc_index + 1)) _argc_take_value
if [[ "$_argc_item" == *=* ]]; then
_argc_take_args_values=("${_argc_item##*=}")
else
while [[ $_argc_take_index -lt $_argc_len ]]; do
_argc_take_value="${argc__args[_argc_take_index]}"
if _argc_maybe_flag_option "$signs" "$_argc_take_value"; then
if [[ "${#_argc_take_value}" -gt 1 ]]; then
break
fi
fi
_argc_take_args_values+=("$_argc_take_value")
_argc_take_args_len=$((_argc_take_args_len + 1))
if [[ "$_argc_take_args_len" -ge "$max" ]]; then
break
fi
_argc_take_index=$((_argc_take_index + 1))
done
fi
if [[ "${#_argc_take_args_values[@]}" -lt "$min" ]]; then
_argc_die "error: incorrect number of values for \`$param\`"
fi
if [[ -n "$delimiter" ]] && [[ "${#_argc_take_args_values[@]}" -gt 0 ]]; then
local item values arr=()
for item in "${_argc_take_args_values[@]}"; do
IFS="$delimiter" read -r -a values <<<"$item"
arr+=("${values[@]}")
done
_argc_take_args_values=("${arr[@]}")
fi
}
_argc_require_params() {
local message="$1" missed_envs="" item name render_name
for item in "${@:2}"; do
name="${item%%:*}"
render_name="${item##*:}"
if [[ -z "${!name:-}" ]]; then
missed_envs="$missed_envs"$'\n'" $render_name"
fi
done
if [[ -n "${missed_envs}" ]]; then
_argc_die "$message$missed_envs"
fi
}
_argc_maybe_flag_option() {
local signs="$1" arg="$2"
if [[ -z "$signs" ]]; then
return 1
fi
local cond=false
if [[ "$signs" == *"+"* ]]; then
if [[ "$arg" =~ ^\+[^+].* ]]; then
cond=true
fi
elif [[ "$arg" == -* ]]; then
if (( ${#arg} < 3 )) || [[ ! "$arg" =~ ^---.* ]]; then
cond=true
fi
fi
if [[ "$cond" == "false" ]]; then
return 1
fi
local value="${arg%%=*}"
if [[ "$value" =~ [[:space:]] ]]; then
return 1
fi
return 0
}
_argc_die() {
if [[ $# -eq 0 ]]; then
cat
else
echo "$*" >&2
fi
exit 1
}
_argc_run "$@"
# ARGC-BUILD }
+224
View File
@@ -0,0 +1,224 @@
#!/usr/bin/env bash
set -e
# @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
PROMPT_UTILS="${LLM_ROOT_DIR:-$(dirname "${BASH_SOURCE[0]}")/..}/utils/prompt-utils.sh"
# shellcheck disable=SC1090
source "$PROMPT_UTILS"
# shellcheck disable=SC2154
main() {
if [[ -f "$argc_path" ]]; then
printf "%s" "$argc_contents" | git diff --no-index "$argc_path" - || true
guard_operation "Apply changes?"
else
guard_path "$argc_path" "Write '$argc_path'?"
mkdir -p "$(dirname "$argc_path")"
fi
printf "%s" "$argc_contents" > "$argc_path"
echo "The File contents were written to: $argc_path" >> "$LLM_OUTPUT"
}
# ARGC-BUILD {
# This block was generated by argc (https://github.com/sigoden/argc).
# Modifying it manually is not recommended
_argc_run() {
if [[ "${1:-}" == "___internal___" ]]; then
_argc_die "error: unsupported ___internal___ command"
fi
if [[ "${OS:-}" == "Windows_NT" ]] && [[ -n "${MSYSTEM:-}" ]]; then
set -o igncr
fi
argc__args=("$(basename "$0" .sh)" "$@")
argc__positionals=()
_argc_index=1
_argc_len="${#argc__args[@]}"
_argc_tools=()
_argc_parse
if [ -n "${argc__fn:-}" ]; then
$argc__fn "${argc__positionals[@]}"
fi
}
_argc_usage() {
cat <<-'EOF'
Write the full file contents to a file at the specified path.
USAGE: --path <PATH> --contents <CONTENTS>
OPTIONS:
--path <PATH> The path of the file to write to
--contents <CONTENTS> The full contents to write to the file
-h, --help Print help
-V, --version Print version
ENVIRONMENTS:
LLM_OUTPUT The output path [default: /dev/stdout]
EOF
exit
}
_argc_version() {
echo 0.0.0
exit
}
_argc_parse() {
local _argc_key _argc_action
local _argc_subcmds=""
while [[ $_argc_index -lt $_argc_len ]]; do
_argc_item="${argc__args[_argc_index]}"
_argc_key="${_argc_item%%=*}"
case "$_argc_key" in
--help | -help | -h)
_argc_usage
;;
--version | -version | -V)
_argc_version
;;
--)
_argc_dash="${#argc__positionals[@]}"
argc__positionals+=("${argc__args[@]:$((_argc_index + 1))}")
_argc_index=$_argc_len
break
;;
--path)
_argc_take_args "--path <PATH>" 1 1 "-" ""
_argc_index=$((_argc_index + _argc_take_args_len + 1))
if [[ -z "${argc_path:-}" ]]; then
argc_path="${_argc_take_args_values[0]:-}"
else
_argc_die "error: the argument \`--path\` cannot be used multiple times"
fi
;;
--contents)
_argc_take_args "--contents <CONTENTS>" 1 1 "-" ""
_argc_index=$((_argc_index + _argc_take_args_len + 1))
if [[ -z "${argc_contents:-}" ]]; then
argc_contents="${_argc_take_args_values[0]:-}"
else
_argc_die "error: the argument \`--contents\` cannot be used multiple times"
fi
;;
*)
if _argc_maybe_flag_option "-" "$_argc_item"; then
_argc_die "error: unexpected argument \`$_argc_key\` found"
fi
argc__positionals+=("$_argc_item")
_argc_index=$((_argc_index + 1))
;;
esac
done
_argc_require_params "error: the following required arguments were not provided:" \
'argc_path:--path <PATH>' 'argc_contents:--contents <CONTENTS>'
if [[ -n "${_argc_action:-}" ]]; then
$_argc_action
else
argc__fn=main
if [[ "${argc__positionals[0]:-}" == "help" ]] && [[ "${#argc__positionals[@]}" -eq 1 ]]; then
_argc_usage
fi
if [[ -z "${LLM_OUTPUT:-}" ]]; then
export LLM_OUTPUT=/dev/stdout
fi
fi
}
_argc_take_args() {
_argc_take_args_values=()
_argc_take_args_len=0
local param="$1" min="$2" max="$3" signs="$4" delimiter="$5"
if [[ "$min" -eq 0 ]] && [[ "$max" -eq 0 ]]; then
return
fi
local _argc_take_index=$((_argc_index + 1)) _argc_take_value
if [[ "$_argc_item" == *=* ]]; then
_argc_take_args_values=("${_argc_item##*=}")
else
while [[ $_argc_take_index -lt $_argc_len ]]; do
_argc_take_value="${argc__args[_argc_take_index]}"
if _argc_maybe_flag_option "$signs" "$_argc_take_value"; then
if [[ "${#_argc_take_value}" -gt 1 ]]; then
break
fi
fi
_argc_take_args_values+=("$_argc_take_value")
_argc_take_args_len=$((_argc_take_args_len + 1))
if [[ "$_argc_take_args_len" -ge "$max" ]]; then
break
fi
_argc_take_index=$((_argc_take_index + 1))
done
fi
if [[ "${#_argc_take_args_values[@]}" -lt "$min" ]]; then
_argc_die "error: incorrect number of values for \`$param\`"
fi
if [[ -n "$delimiter" ]] && [[ "${#_argc_take_args_values[@]}" -gt 0 ]]; then
local item values arr=()
for item in "${_argc_take_args_values[@]}"; do
IFS="$delimiter" read -r -a values <<<"$item"
arr+=("${values[@]}")
done
_argc_take_args_values=("${arr[@]}")
fi
}
_argc_require_params() {
local message="$1" missed_envs="" item name render_name
for item in "${@:2}"; do
name="${item%%:*}"
render_name="${item##*:}"
if [[ -z "${!name:-}" ]]; then
missed_envs="$missed_envs"$'\n'" $render_name"
fi
done
if [[ -n "${missed_envs}" ]]; then
_argc_die "$message$missed_envs"
fi
}
_argc_maybe_flag_option() {
local signs="$1" arg="$2"
if [[ -z "$signs" ]]; then
return 1
fi
local cond=false
if [[ "$signs" == *"+"* ]]; then
if [[ "$arg" =~ ^\+[^+].* ]]; then
cond=true
fi
elif [[ "$arg" == -* ]]; then
if (( ${#arg} < 3 )) || [[ ! "$arg" =~ ^---.* ]]; then
cond=true
fi
fi
if [[ "$cond" == "false" ]]; then
return 1
fi
local value="${arg%%=*}"
if [[ "$value" =~ [[:space:]] ]]; then
return 1
fi
return 0
}
_argc_die() {
if [[ $# -eq 0 ]]; then
cat
else
echo "$*" >&2
fi
exit 1
}
_argc_run "$@"
# ARGC-BUILD }
+10
View File
@@ -0,0 +1,10 @@
#!/usr/bin/env bash
set -e
# @describe Get the current time.
# @env LLM_OUTPUT=/dev/stdout The output path
main() {
date >> "$LLM_OUTPUT"
}
@@ -0,0 +1,35 @@
import os
from pathlib import Path
from typing import Optional
from urllib.parse import quote_plus
from urllib.request import urlopen
def run(
location: str,
llm_output: Optional[str] = None,
) -> str:
"""Get the current weather in a given location
Args:
location (str): The city and optionally the state or country (e.g., "London", "San Francisco, CA").
Returns:
str: A single-line formatted weather string from wttr.in (``format=4`` with metric units).
"""
url = f"https://wttr.in/{quote_plus(location)}?format=4&M"
with urlopen(url, timeout=10) as resp:
weather = resp.read().decode("utf-8", errors="replace")
dest = llm_output if llm_output is not None else os.environ.get("LLM_OUTPUT", "/dev/stdout")
if dest not in {"-", "/dev/stdout"}:
path = Path(dest)
path.parent.mkdir(parents=True, exist_ok=True)
with path.open("a", encoding="utf-8") as fh:
fh.write(weather)
else:
pass
return weather
+199
View File
@@ -0,0 +1,199 @@
#!/usr/bin/env bash
set -e
# @describe Get the current weather in a given location.
# @option --location! The city and optionally the state or country, e.g., "London", "San Francisco, CA".
# @env LLM_OUTPUT=/dev/stdout The output path
main() {
curl -fsSL "https://wttr.in/$(echo "$argc_location" | sed 's/ /+/g')?format=4&M" \
>> "$LLM_OUTPUT"
}
# ARGC-BUILD {
# This block was generated by argc (https://github.com/sigoden/argc).
# Modifying it manually is not recommended
_argc_run() {
if [[ "${1:-}" == "___internal___" ]]; then
_argc_die "error: unsupported ___internal___ command"
fi
if [[ "${OS:-}" == "Windows_NT" ]] && [[ -n "${MSYSTEM:-}" ]]; then
set -o igncr
fi
argc__args=("$(basename "$0" .sh)" "$@")
argc__positionals=()
_argc_index=1
_argc_len="${#argc__args[@]}"
_argc_tools=()
_argc_parse
if [ -n "${argc__fn:-}" ]; then
$argc__fn "${argc__positionals[@]}"
fi
}
_argc_usage() {
cat <<-'EOF'
Get the current weather in a given location.
USAGE: --location <LOCATION>
OPTIONS:
--location <LOCATION> The city and optionally the state or country, e.g., "London", "San Francisco, CA".
-h, --help Print help
-V, --version Print version
ENVIRONMENTS:
LLM_OUTPUT The output path [default: /dev/stdout]
EOF
exit
}
_argc_version() {
echo 0.0.0
exit
}
_argc_parse() {
local _argc_key _argc_action
local _argc_subcmds=""
while [[ $_argc_index -lt $_argc_len ]]; do
_argc_item="${argc__args[_argc_index]}"
_argc_key="${_argc_item%%=*}"
case "$_argc_key" in
--help | -help | -h)
_argc_usage
;;
--version | -version | -V)
_argc_version
;;
--)
_argc_dash="${#argc__positionals[@]}"
argc__positionals+=("${argc__args[@]:$((_argc_index + 1))}")
_argc_index=$_argc_len
break
;;
--location)
_argc_take_args "--location <LOCATION>" 1 1 "-" ""
_argc_index=$((_argc_index + _argc_take_args_len + 1))
if [[ -z "${argc_location:-}" ]]; then
argc_location="${_argc_take_args_values[0]:-}"
else
_argc_die "error: the argument \`--location\` cannot be used multiple times"
fi
;;
*)
if _argc_maybe_flag_option "-" "$_argc_item"; then
_argc_die "error: unexpected argument \`$_argc_key\` found"
fi
argc__positionals+=("$_argc_item")
_argc_index=$((_argc_index + 1))
;;
esac
done
_argc_require_params "error: the following required arguments were not provided:" \
'argc_location:--location <LOCATION>'
if [[ -n "${_argc_action:-}" ]]; then
$_argc_action
else
argc__fn=main
if [[ "${argc__positionals[0]:-}" == "help" ]] && [[ "${#argc__positionals[@]}" -eq 1 ]]; then
_argc_usage
fi
if [[ -z "${LLM_OUTPUT:-}" ]]; then
export LLM_OUTPUT=/dev/stdout
fi
fi
}
_argc_take_args() {
_argc_take_args_values=()
_argc_take_args_len=0
local param="$1" min="$2" max="$3" signs="$4" delimiter="$5"
if [[ "$min" -eq 0 ]] && [[ "$max" -eq 0 ]]; then
return
fi
local _argc_take_index=$((_argc_index + 1)) _argc_take_value
if [[ "$_argc_item" == *=* ]]; then
_argc_take_args_values=("${_argc_item##*=}")
else
while [[ $_argc_take_index -lt $_argc_len ]]; do
_argc_take_value="${argc__args[_argc_take_index]}"
if _argc_maybe_flag_option "$signs" "$_argc_take_value"; then
if [[ "${#_argc_take_value}" -gt 1 ]]; then
break
fi
fi
_argc_take_args_values+=("$_argc_take_value")
_argc_take_args_len=$((_argc_take_args_len + 1))
if [[ "$_argc_take_args_len" -ge "$max" ]]; then
break
fi
_argc_take_index=$((_argc_take_index + 1))
done
fi
if [[ "${#_argc_take_args_values[@]}" -lt "$min" ]]; then
_argc_die "error: incorrect number of values for \`$param\`"
fi
if [[ -n "$delimiter" ]] && [[ "${#_argc_take_args_values[@]}" -gt 0 ]]; then
local item values arr=()
for item in "${_argc_take_args_values[@]}"; do
IFS="$delimiter" read -r -a values <<<"$item"
arr+=("${values[@]}")
done
_argc_take_args_values=("${arr[@]}")
fi
}
_argc_require_params() {
local message="$1" missed_envs="" item name render_name
for item in "${@:2}"; do
name="${item%%:*}"
render_name="${item##*:}"
if [[ -z "${!name:-}" ]]; then
missed_envs="$missed_envs"$'\n'" $render_name"
fi
done
if [[ -n "${missed_envs}" ]]; then
_argc_die "$message$missed_envs"
fi
}
_argc_maybe_flag_option() {
local signs="$1" arg="$2"
if [[ -z "$signs" ]]; then
return 1
fi
local cond=false
if [[ "$signs" == *"+"* ]]; then
if [[ "$arg" =~ ^\+[^+].* ]]; then
cond=true
fi
elif [[ "$arg" == -* ]]; then
if (( ${#arg} < 3 )) || [[ ! "$arg" =~ ^---.* ]]; then
cond=true
fi
fi
if [[ "$cond" == "false" ]]; then
return 1
fi
local value="${arg%%=*}"
if [[ "$value" =~ [[:space:]] ]]; then
return 1
fi
return 0
}
_argc_die() {
if [[ $# -eq 0 ]]; then
cat
else
echo "$*" >&2
fi
exit 1
}
_argc_run "$@"
# ARGC-BUILD }
+198
View File
@@ -0,0 +1,198 @@
#!/usr/bin/env bash
set -e
# @meta require-tools jira
# @describe Query for jira issues using a Jira Query Language (JQL) query
# @option --jql-query! The Jira Query Language query to execute
# @env LLM_OUTPUT=/dev/stdout The output path
main() {
jira issue ls -q "$argc_jql_query" --plain >> "$LLM_OUTPUT"
}
# ARGC-BUILD {
# This block was generated by argc (https://github.com/sigoden/argc).
# Modifying it manually is not recommended
_argc_run() {
if [[ "${1:-}" == "___internal___" ]]; then
_argc_die "error: unsupported ___internal___ command"
fi
if [[ "${OS:-}" == "Windows_NT" ]] && [[ -n "${MSYSTEM:-}" ]]; then
set -o igncr
fi
argc__args=("$(basename "$0" .sh)" "$@")
argc__positionals=()
_argc_index=1
_argc_len="${#argc__args[@]}"
_argc_tools=()
_argc_parse
if [ -n "${argc__fn:-}" ]; then
$argc__fn "${argc__positionals[@]}"
fi
}
_argc_usage() {
cat <<-'EOF'
Query for jira issues using a Jira Query Language (JQL) query
USAGE: --jql-query <JQL-QUERY>
OPTIONS:
--jql-query <JQL-QUERY> The Jira Query Language query to execute
-h, --help Print help
-V, --version Print version
ENVIRONMENTS:
LLM_OUTPUT The output path [default: /dev/stdout]
EOF
exit
}
_argc_version() {
echo 0.0.0
exit
}
_argc_parse() {
local _argc_key _argc_action
local _argc_subcmds=""
while [[ $_argc_index -lt $_argc_len ]]; do
_argc_item="${argc__args[_argc_index]}"
_argc_key="${_argc_item%%=*}"
case "$_argc_key" in
--help | -help | -h)
_argc_usage
;;
--version | -version | -V)
_argc_version
;;
--)
_argc_dash="${#argc__positionals[@]}"
argc__positionals+=("${argc__args[@]:$((_argc_index + 1))}")
_argc_index=$_argc_len
break
;;
--jql-query)
_argc_take_args "--jql-query <JQL-QUERY>" 1 1 "-" ""
_argc_index=$((_argc_index + _argc_take_args_len + 1))
if [[ -z "${argc_jql_query:-}" ]]; then
argc_jql_query="${_argc_take_args_values[0]:-}"
else
_argc_die "error: the argument \`--jql-query\` cannot be used multiple times"
fi
;;
*)
if _argc_maybe_flag_option "-" "$_argc_item"; then
_argc_die "error: unexpected argument \`$_argc_key\` found"
fi
argc__positionals+=("$_argc_item")
_argc_index=$((_argc_index + 1))
;;
esac
done
_argc_require_params "error: the following required arguments were not provided:" \
'argc_jql_query:--jql-query <JQL-QUERY>'
if [[ -n "${_argc_action:-}" ]]; then
$_argc_action
else
argc__fn=main
if [[ "${argc__positionals[0]:-}" == "help" ]] && [[ "${#argc__positionals[@]}" -eq 1 ]]; then
_argc_usage
fi
if [[ -z "${LLM_OUTPUT:-}" ]]; then
export LLM_OUTPUT=/dev/stdout
fi
fi
}
_argc_take_args() {
_argc_take_args_values=()
_argc_take_args_len=0
local param="$1" min="$2" max="$3" signs="$4" delimiter="$5"
if [[ "$min" -eq 0 ]] && [[ "$max" -eq 0 ]]; then
return
fi
local _argc_take_index=$((_argc_index + 1)) _argc_take_value
if [[ "$_argc_item" == *=* ]]; then
_argc_take_args_values=("${_argc_item##*=}")
else
while [[ $_argc_take_index -lt $_argc_len ]]; do
_argc_take_value="${argc__args[_argc_take_index]}"
if _argc_maybe_flag_option "$signs" "$_argc_take_value"; then
if [[ "${#_argc_take_value}" -gt 1 ]]; then
break
fi
fi
_argc_take_args_values+=("$_argc_take_value")
_argc_take_args_len=$((_argc_take_args_len + 1))
if [[ "$_argc_take_args_len" -ge "$max" ]]; then
break
fi
_argc_take_index=$((_argc_take_index + 1))
done
fi
if [[ "${#_argc_take_args_values[@]}" -lt "$min" ]]; then
_argc_die "error: incorrect number of values for \`$param\`"
fi
if [[ -n "$delimiter" ]] && [[ "${#_argc_take_args_values[@]}" -gt 0 ]]; then
local item values arr=()
for item in "${_argc_take_args_values[@]}"; do
IFS="$delimiter" read -r -a values <<<"$item"
arr+=("${values[@]}")
done
_argc_take_args_values=("${arr[@]}")
fi
}
_argc_require_params() {
local message="$1" missed_envs="" item name render_name
for item in "${@:2}"; do
name="${item%%:*}"
render_name="${item##*:}"
if [[ -z "${!name:-}" ]]; then
missed_envs="$missed_envs"$'\n'" $render_name"
fi
done
if [[ -n "${missed_envs}" ]]; then
_argc_die "$message$missed_envs"
fi
}
_argc_maybe_flag_option() {
local signs="$1" arg="$2"
if [[ -z "$signs" ]]; then
return 1
fi
local cond=false
if [[ "$signs" == *"+"* ]]; then
if [[ "$arg" =~ ^\+[^+].* ]]; then
cond=true
fi
elif [[ "$arg" == -* ]]; then
if (( ${#arg} < 3 )) || [[ ! "$arg" =~ ^---.* ]]; then
cond=true
fi
fi
if [[ "$cond" == "false" ]]; then
return 1
fi
local value="${arg%%=*}"
if [[ "$value" =~ [[:space:]] ]]; then
return 1
fi
return 0
}
_argc_die() {
if [[ $# -eq 0 ]]; then
cat
else
echo "$*" >&2
fi
exit 1
}
_argc_run "$@"
# ARGC-BUILD }
+16
View File
@@ -0,0 +1,16 @@
#!/usr/bin/env bash
set -e
# @describe Search arXiv using the given search query and return the top papers.
# @option --query! The search query.
# @env ARXIV_MAX_RESULTS=3 The max results to return.
# @env LLM_OUTPUT=/dev/stdout The output path
main() {
# shellcheck disable=SC2154
encoded_query="$(jq -nr --arg q "$argc_query" '$q|@uri')"
url="http://export.arxiv.org/api/query?search_query=all:$encoded_query&max_results=$ARXIV_MAX_RESULTS"
curl -fsSL "$url" >> "$LLM_OUTPUT"
}
+29
View File
@@ -0,0 +1,29 @@
#!/usr/bin/env bash
set -e
# @describe Search Wikipedia using the given search query.
# Use it to get detailed information about a public figure, interpretation of a complex scientific concept or in-depth connectivity of a significant historical event, etc.
# @option --query! The search query.
# @env LLM_OUTPUT=/dev/stdout The output path
# shellcheck disable=SC2154
main() {
encoded_query="$(jq -nr --arg q "$argc_query" '$q|@uri')"
base_url="https://en.wikipedia.org/w/api.php"
url="$base_url?action=query&list=search&srprop=&srlimit=1&limit=1&srsearch=$encoded_query&srinfo=suggestion&format=json"
json="$(curl -fsSL "$url")"
# suggestion="$(echo "$json" | jq -r '.query.searchinfo.suggestion // empty')"
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 for '$argc_query'" >&2
exit 1
fi
title="$(echo "$title" | tr ' ' '_')"
url="$base_url?action=query&prop=extracts&explaintext=&titles=$title&exintro=&format=json"
curl -fsSL "$url" | jq -r '.query.pages["'"$pageid"'"].extract' >> "$LLM_OUTPUT"
}
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/env bash
set -e
# @describe Get an answer to a question using Wolfram Alpha. The input query should be in English.
# Use it to answer user questions that require computation, detailed facts, data analysis, or complex queries.
# @option --query! The search/computation query to pass to Wolfram Alpha
# @env WOLFRAM_API_ID! Your Wolfram Alpha API ID
# @env LLM_OUTPUT=/dev/stdout The output path
# shellcheck disable=SC2154
main() {
encoded_query="$(jq -nr --arg q "$argc_query" '$q|@uri')"
url="https://api.wolframalpha.com/v2/query?appid=${WOLFRAM_API_ID}&input=$encoded_query&output=json&format=plaintext"
curl -fsSL "$url" | jq '[.queryresult | .pods[] | {title:.title, values:[.subpods[].plaintext | select(. != "")]}]' \
>> "$LLM_OUTPUT"
}
+30
View File
@@ -0,0 +1,30 @@
#!/usr/bin/env bash
set -e
# @describe Send an email.
# @option --recipient! The recipient of the email.
# @option --subject! The subject of the email.
# @option --body! The body of the email.
# @env EMAIL_SMTP_ADDR! The SMTP Address, e.g. smtps://smtp.gmail.com:465
# @env EMAIL_SMTP_USER! The SMTP User, e.g. alice@gmail.com
# @env EMAIL_SMTP_PASS! The SMTP Password
# @env EMAIL_SENDER_NAME The sender's name
# @env LLM_OUTPUT=/dev/stdout The output path
# shellcheck disable=SC2154
main() {
sender_name="${EMAIL_SENDER_NAME:-$(echo "$EMAIL_SMTP_USER" | awk -F'@' '{print $1}')}"
printf "%s\n" "From: $sender_name <$EMAIL_SMTP_USER>
To: $argc_recipient
Subject: $argc_subject
$argc_body" | \
curl -fsS --ssl-reqd \
--url "$EMAIL_SMTP_ADDR" \
--user "$EMAIL_SMTP_USER:$EMAIL_SMTP_PASS" \
--mail-from "$EMAIL_SMTP_USER" \
--mail-rcpt "$argc_recipient" \
--upload-file -
echo "Email sent successfully" >> "$LLM_OUTPUT"
}
+50
View File
@@ -0,0 +1,50 @@
#!/usr/bin/env bash
set -e
# @describe Send SMS or Twilio Messaging Channels messages using the Twilio API.
# @option --to-number! The recipient's phone number. Prefix it with 'whatsapp:' for WhatsApp messages, e.g. whatsapp:+1234567890
# @option --message! The content of the message to be sent
# @env TWILIO_ACCOUNT_SID! The twilio account sid
# @env TWILIO_AUTH_TOKEN! The twilio auth token
# @env TWILIO_FROM_NUMBER! The twilio from number
# @env LLM_OUTPUT=/dev/stdout The output path
# shellcheck disable=SC2154
main() {
from_number="$TWILIO_FROM_NUMBER"
to_number="$argc_to_number"
if [[ "$to_number" == 'whatsapp:'* ]]; then
from_number="whatsapp:$from_number"
fi
if [[ "$to_number" != 'whatsapp:'* && "$to_number" != '+'* ]]; then
to_number="+$to_number"
fi
res="$(curl -s -X POST "https://api.twilio.com/2010-04-01/Accounts/$TWILIO_ACCOUNT_SID/Messages.json" \
-u "$TWILIO_ACCOUNT_SID:$TWILIO_AUTH_TOKEN" \
-w "\n%{http_code}" \
--data-urlencode "From=$from_number" \
--data-urlencode "To=$to_number" \
--data-urlencode "Body=$argc_message")"
status="$(echo "$res" | tail -n 1)"
body="$(echo "$res" | head -n -1)"
if [[ "$status" -ge 200 && "$status" -lt 300 ]]; then
if [[ "$(echo "$body" | jq -r 'has("sid")')" == "true" ]]; then
echo "Message sent successfully" >> "$LLM_OUTPUT"
else
_die "error: $body"
fi
else
_die "error: $body"
fi
}
_die() {
echo "$*" >&2
exit 1
}
+254
View File
@@ -0,0 +1,254 @@
#!/usr/bin/env bash
set -e
# @describe Perform a web search to get up-to-date information or additional context.
# Use this when you need current information or feel a search could provide a better answer.
# @option --query! The search query.
# @meta require-tools loki
# @env WEB_SEARCH_MODEL=gemini:gemini-2.5-flash The model for web-searching.
#
# supported loki models:
# - gemini:gemini-2.0-*
# - vertexai:gemini-*
# - perplexity:*
# - ernie:*
# @env LLM_OUTPUT=/dev/stdout The output path
# shellcheck disable=SC2154
main() {
client="${WEB_SEARCH_MODEL%%:*}"
if [[ "$client" == "gemini" ]]; then
export LOKI_PATCH_GEMINI_CHAT_COMPLETIONS='{".*":{"body":{"tools":[{"google_search":{}}]}}}'
elif [[ "$client" == "vertexai" ]]; then
export LOKI_PATCH_VERTEXAI_CHAT_COMPLETIONS='{
"gemini-1.5-.*":{"body":{"tools":[{"googleSearchRetrieval":{}}]}},
"gemini-2.0-.*":{"body":{"tools":[{"google_search":{}}]}}
}'
elif [[ "$client" == "ernie" ]]; then
export LOKI_PATCH_ERNIE_CHAT_COMPLETIONS='{".*":{"body":{"web_search":{"enable":true}}}}'
fi
loki -m "$WEB_SEARCH_MODEL" "$argc_query" >> "$LLM_OUTPUT"
}
# ARGC-BUILD {
# This block was generated by argc (https://github.com/sigoden/argc).
# Modifying it manually is not recommended
_argc_run() {
if [[ "${1:-}" == "___internal___" ]]; then
_argc_die "error: unsupported ___internal___ command"
fi
if [[ "${OS:-}" == "Windows_NT" ]] && [[ -n "${MSYSTEM:-}" ]]; then
set -o igncr
fi
argc__args=("$(basename "$0" .sh)" "$@")
argc__positionals=()
_argc_index=1
_argc_len="${#argc__args[@]}"
_argc_tools=()
_argc_parse
_argc_require_tools "${_argc_tools[@]}"
if [ -n "${argc__fn:-}" ]; then
$argc__fn "${argc__positionals[@]}"
fi
}
_argc_usage() {
cat <<-'EOF'
Perform a web search to get up-to-date information or additional context.
Use this when you need current information or feel a search could provide a better answer.
USAGE: --query <QUERY>
OPTIONS:
--query <QUERY> The query to search for.
-h, --help Print help
-V, --version Print version
ENVIRONMENTS:
WEB_SEARCH_MODEL
The model for web-searching.
supported loki models:
- gemini:gemini-2.0-*
- vertexai:gemini-*
- perplexity:*
- ernie:*
[default: gemini:gemini-2.5-flash]
LLM_OUTPUT
The output path [default: /dev/stdout]
EOF
exit
}
_argc_version() {
echo 0.0.0
exit
}
_argc_parse() {
local _argc_key _argc_action
local _argc_subcmds=""
while [[ $_argc_index -lt $_argc_len ]]; do
_argc_item="${argc__args[_argc_index]}"
_argc_key="${_argc_item%%=*}"
case "$_argc_key" in
--help | -help | -h)
_argc_usage
;;
--version | -version | -V)
_argc_version
;;
--)
_argc_dash="${#argc__positionals[@]}"
argc__positionals+=("${argc__args[@]:$((_argc_index + 1))}")
_argc_index=$_argc_len
break
;;
--query)
_argc_take_args "--query <QUERY>" 1 1 "-" ""
_argc_index=$((_argc_index + _argc_take_args_len + 1))
if [[ -z "${argc_query:-}" ]]; then
argc_query="${_argc_take_args_values[0]:-}"
else
_argc_die "error: the argument \`--query\` cannot be used multiple times"
fi
;;
*)
if _argc_maybe_flag_option "-" "$_argc_item"; then
_argc_die "error: unexpected argument \`$_argc_key\` found"
fi
argc__positionals+=("$_argc_item")
_argc_index=$((_argc_index + 1))
;;
esac
done
_argc_require_params "error: the following required arguments were not provided:" \
'argc_query:--query <QUERY>'
_argc_tools=(loki)
if [[ -n "${_argc_action:-}" ]]; then
$_argc_action
else
argc__fn=main
if [[ "${argc__positionals[0]:-}" == "help" ]] && [[ "${#argc__positionals[@]}" -eq 1 ]]; then
_argc_usage
fi
if [[ -z "${WEB_SEARCH_MODEL:-}" ]]; then
export WEB_SEARCH_MODEL=gemini:gemini-2.5-flash
fi
if [[ -z "${LLM_OUTPUT:-}" ]]; then
export LLM_OUTPUT=/dev/stdout
fi
fi
}
_argc_take_args() {
_argc_take_args_values=()
_argc_take_args_len=0
local param="$1" min="$2" max="$3" signs="$4" delimiter="$5"
if [[ "$min" -eq 0 ]] && [[ "$max" -eq 0 ]]; then
return
fi
local _argc_take_index=$((_argc_index + 1)) _argc_take_value
if [[ "$_argc_item" == *=* ]]; then
_argc_take_args_values=("${_argc_item##*=}")
else
while [[ $_argc_take_index -lt $_argc_len ]]; do
_argc_take_value="${argc__args[_argc_take_index]}"
if _argc_maybe_flag_option "$signs" "$_argc_take_value"; then
if [[ "${#_argc_take_value}" -gt 1 ]]; then
break
fi
fi
_argc_take_args_values+=("$_argc_take_value")
_argc_take_args_len=$((_argc_take_args_len + 1))
if [[ "$_argc_take_args_len" -ge "$max" ]]; then
break
fi
_argc_take_index=$((_argc_take_index + 1))
done
fi
if [[ "${#_argc_take_args_values[@]}" -lt "$min" ]]; then
_argc_die "error: incorrect number of values for \`$param\`"
fi
if [[ -n "$delimiter" ]] && [[ "${#_argc_take_args_values[@]}" -gt 0 ]]; then
local item values arr=()
for item in "${_argc_take_args_values[@]}"; do
IFS="$delimiter" read -r -a values <<<"$item"
arr+=("${values[@]}")
done
_argc_take_args_values=("${arr[@]}")
fi
}
_argc_require_params() {
local message="$1" missed_envs="" item name render_name
for item in "${@:2}"; do
name="${item%%:*}"
render_name="${item##*:}"
if [[ -z "${!name:-}" ]]; then
missed_envs="$missed_envs"$'\n'" $render_name"
fi
done
if [[ -n "${missed_envs}" ]]; then
_argc_die "$message$missed_envs"
fi
}
_argc_maybe_flag_option() {
local signs="$1" arg="$2"
if [[ -z "$signs" ]]; then
return 1
fi
local cond=false
if [[ "$signs" == *"+"* ]]; then
if [[ "$arg" =~ ^\+[^+].* ]]; then
cond=true
fi
elif [[ "$arg" == -* ]]; then
if (( ${#arg} < 3 )) || [[ ! "$arg" =~ ^---.* ]]; then
cond=true
fi
fi
if [[ "$cond" == "false" ]]; then
return 1
fi
local value="${arg%%=*}"
if [[ "$value" =~ [[:space:]] ]]; then
return 1
fi
return 0
}
_argc_require_tools() {
local tool missing_tools=()
for tool in "$@"; do
if ! command -v "$tool" >/dev/null 2>&1; then
missing_tools+=("$tool")
fi
done
if [[ "${#missing_tools[@]}" -gt 0 ]]; then
echo "error: missing tools: ${missing_tools[*]}" >&2
exit 1
fi
}
_argc_die() {
if [[ $# -eq 0 ]]; then
cat
else
echo "$*" >&2
fi
exit 1
}
_argc_run "$@"
# ARGC-BUILD }
+32
View File
@@ -0,0 +1,32 @@
#!/usr/bin/env bash
set -e
# @describe Perform a web search using the Perplexity API to get up-to-date information or additional context.
# Use this when you need current information or feel a search could provide a better answer.
# @option --query! The search query.
# @env PERPLEXITY_API_KEY! Your Perplexity API key
# @env PERPLEXITY_WEB_SEARCH_MODEL=llama-3.1-sonar-small-128k-online The LLM model to use for the search
# @env LLM_OUTPUT=/dev/stdout The output path
# shellcheck disable=SC2154
main() {
curl -fsS -X POST https://api.perplexity.ai/chat/completions \
-H "authorization: Bearer $PERPLEXITY_API_KEY" \
-H "accept: application/json" \
-H "content-type: application/json" \
--data '
{
"model": "'"$PERPLEXITY_WEB_SEARCH_MODEL"'",
"messages": [
{
"role": "user",
"content": "'"$argc_query"'"
}
]
}
' | \
jq -r '.choices[0].message.content' \
>> "$LLM_OUTPUT"
}
+24
View File
@@ -0,0 +1,24 @@
#!/usr/bin/env bash
set -e
# @describe Perform a web search using the Tavily API to get up-to-date information or additional context.
# Use this when you need current information or feel a search could provide a better answer.
# @option --query! The search query.
# @env TAVILY_API_KEY! Your Tavile API key
# @env LLM_OUTPUT=/dev/stdout The output path The output path
# shellcheck disable=SC2154
main() {
curl -fsSL -X POST https://api.tavily.com/search \
-H "content-type: application/json" \
-d '
{
"api_key": "'"$TAVILY_API_KEY"'",
"query": "'"$argc_query"'",
"include_answer": true
}' | \
jq -r '.answer' >> "$LLM_OUTPUT"
}
+716
View File
@@ -0,0 +1,716 @@
#!/usr/bin/env bash
# Bash helper utilities for prompting users.
# This is a modified version of the excellent Bash TUI toolkit
# (https://github.com/timo-reymann/bash-tui-toolkit)
#
# It includes the following functions for you to use in your
# bash tool commands:
#
# - password Password prompt
# - checked Checkbox
# - text Text input with validation
# - list Select an option from a given list
# - range Prompt the user for a value within a range
# - confirm Confirmation prompt
# - editor Open the user's preferred editor for input
# - detect_os Detect the current OS
# - get_opener Get the file opener for the current OS
# - open_link Open the given link in the default browser
# See https://github.com/timo-reymann/bash-tui-toolkit/blob/main/test.sh
# for examples on how to use these commands
#
# - guard_operation Prompt for permission to run an operation
# - guard_path Prompt for permission to perform path operations
# - patch_file Patch a file
# - error Log an error
# - warn Log a warning
# - info Log info
# - debug Log a debug message
# - trace Log a trace message
# - red Output given text in red
# - green Output given text in green
# - gold Output given text in gold
# - blue Output given text in blue
# - magenta Output given text in magenta
# - cyan Output given text in cyan
# - white Output given text in white
# shellcheck disable=SC2034
red=$(tput setaf 1)
green=$(tput setaf 2)
gold=$(tput setaf 3)
blue=$(tput setaf 4)
magenta=$(tput setaf 5)
cyan=$(tput setaf 6)
white=$(tput setaf 7)
default=$(tput sgr0)
gray=$(tput setaf 243)
bold=$(tput bold)
underlined=$(tput smul)
error() {
echo -e "${red}${bold}ERROR:${default}${red} $1${default}"
}
warn() {
echo -e "${gold}${bold}WARN:${default}${gold} $1${default}"
}
info() {
echo -e "${cyan}${bold}INFO:${default}${cyan} $1${default}"
}
debug() {
echo -e "${blue}${bold}DEBUG:${default}${blue} $1${default}"
}
trace() {
echo -e "${gray}${bold}TRACE:${default}${gray} $1${default}"
}
success() {
echo -e "${green}${bold}SUCCESS:${default}${green} $1${default}"
}
red() {
echo -e "${red}$1${default}"
}
green() {
echo -e "${green}$1${default}"
}
gold() {
echo -e "${gold}$1${default}"
}
blue() {
echo -e "${blue}$1${default}"
}
magenta() {
echo -e "${magenta}$1${default}"
}
cyan() {
echo -e "${cyan}$1${default}"
}
white() {
echo -e "${white}$1${default}"
}
_read_stdin() {
read -r "$@" </dev/tty
}
_get_cursor_row() {
declare IFS=';'
_read_stdin -sdR -p $'\E[6n' ROW COL
echo "${ROW#*[}"
}
_cursor_blink_on() {
echo -en "\033[?25h" >&2
}
_cursor_blink_off() {
echo -en "\033[?25l" >&2
}
_cursor_to() {
echo -en "\033[$1;$2H" >&2
}
# shellcheck disable=SC2154
_key_input() {
declare ESC=$'\033'
declare IFS=''
_read_stdin -rsn1 a
if [[ "$ESC" == "$a" ]]; then
_read_stdin -rsn2 b
fi
declare input="${a}${b}"
case "$input" in
"${ESC}[A" | "k") echo up ;;
"${ESC}[B" | "j") echo down ;;
"${ESC}[C" | "l") echo right ;;
"${ESC}[D" | "h") echo left ;;
'') echo enter ;;
' ') echo space ;;
esac
}
_new_line_foreach_item() {
count=0
while [[ $count -lt $1 ]]; do
echo "" >&2
((count++))
done
}
_prompt_text() {
echo -en "\033[32m?\033[0m\033[1m ${1}\033[0m " >&2
}
_decrement_selected() {
declare selected=$1
((selected--))
if [[ "${selected}" -lt 0 ]]; then
selected=$(($2 - 1))
fi
echo -n $selected
}
_increment_selected() {
declare selected=$1
((selected++))
if [[ "${selected}" -ge "${opts_count}" ]]; then
selected=0
fi
echo -n $selected
}
# shellcheck disable=SC2154
input() {
_prompt_text "$1"
echo -en "\033[36m\c" >&2
_read_stdin -r text
echo -n "${text}"
}
confirm() {
trap "stty echo; exit" EXIT
_prompt_text "$1 (y/N)"
echo -en "\033[36m\c " >&2
declare first_row
first_row=$(_get_cursor_row)
declare current_row
current_row=$((first_row - 1))
declare result=""
echo -n " " >&2
while true; do
echo -e "\033[1D\c " >&2
_read_stdin -n1 result
case "$result" in
y | Y)
echo -n 1
break
;;
n | N | *)
echo -n 0
break
;;
esac
done
echo -en "\033[0m" >&2
echo "" >&2
}
list() {
_prompt_text "$1 "
declare opts=("${@:2}")
declare opts_count=$(($# - 1))
_new_line_foreach_item "${#opts[@]}"
declare last_row
last_row=$(_get_cursor_row)
declare first_row
first_row=$((last_row - opts_count + 1))
trap "_cursor_blink_on; stty echo; exit" 2
_cursor_blink_off
declare selected=0
while true; do
declare idx=0
for opt in "${opts[@]}"; do
_cursor_to $((first_row + idx))
if [[ $idx -eq "$selected" ]]; then
printf "\033[0m\033[36m\033[0m \033[36m%s\033[0m" "$opt" >&2
else
printf " %s" "$opt" >&2
fi
((idx++))
done
case $(_key_input) in
enter) break ;;
up) selected=$(_decrement_selected "${selected}" "${opts_count}") ;;
down) selected=$(_increment_selected "${selected}" "${opts_count}") ;;
esac
done
echo -en "\n" >&2
_cursor_to "${last_row}"
_cursor_blink_on
echo -n "${selected}"
}
checkbox() {
_prompt_text "$1"
declare opts
opts=("${@:2}")
declare opts_count
opts_count=$(($# - 1))
_new_line_foreach_item "${#opts[@]}"
declare last_row
last_row=$(_get_cursor_row)
declare first_row
first_row=$((last_row - opts_count + 1))
trap "_cursor_blink_on; stty echo; exit" 2
_cursor_blink_off
declare selected=0
declare checked=()
while true; do
declare idx=0
for opt in "${opts[@]}"; do
_cursor_to $((first_row + idx))
declare icon="◯"
for item in "${checked[@]}"; do
if [[ "$item" == "$idx" ]]; then
icon="◉"
break
fi
done
if [[ $idx -eq "$selected" ]]; then
printf "%s \e[0m\e[36m\e[0m \e[36m%-50s\e[0m" "$icon" "$opt" >&2
else
printf "%s %-50s" "$icon" "$opt" >&2
fi
((idx++))
done
case $(_key_input) in
enter) break ;;
space)
declare found=0
for item in "${checked[@]}"; do
if [[ "$item" == "$selected" ]]; then
found=1
break
fi
done
if [ $found -eq 1 ]; then
checked=("${checked[@]/$selected/}")
else
checked+=("${selected}")
fi
;;
up) selected=$(_decrement_selected "${selected}" "${opts_count}") ;;
down) selected=$(_increment_selected "${selected}" "${opts_count}") ;;
esac
done
_cursor_to "${last_row}"
_cursor_blink_on
IFS="" echo -n "${checked[@]}"
}
password() {
_prompt_text "$1"
echo -en "\033[36m" >&2
declare password=''
declare IFS=
while _read_stdin -r -s -n1 char; do
[[ -z "${char}" ]] && {
printf '\n' >&2
break
}
if [[ "${char}" == $'\x7f' ]]; then
if [[ "${#password}" -gt 0 ]]; then
password="${password%?}"
echo -en '\b \b' >&2
fi
else
password+=$char
echo -en '*' >&2
fi
done
echo -en "\e[0m" >&2
echo -n "${password}"
}
editor() {
tmpfile=$(mktemp)
_prompt_text "$1"
echo "" >&2
"${EDITOR:-vi}" "${tmpfile}" >/dev/tty
echo -en "\033[36m" >&2
sed -e 's/^/ /' "${tmpfile}" >&2
echo -en "\033[0m" >&2
cat "${tmpfile}"
}
with_validate() {
while true; do
declare val
val="$(eval "$1")"
if ($2 "$val" >/dev/null); then
echo "$val"
break
else
show_error "$($2 "$val")"
fi
done
}
range() {
declare min="$2"
declare current="$3"
declare max="$4"
declare selected="${current}"
declare max_len_current
max_len_current=0
if [[ "${#min}" -gt "${#max}" ]]; then
max_len_current="${#min}"
else
max_len_current="${#max}"
fi
declare padding
padding="$(printf "%-${max_len_current}s" "")"
declare first_row
first_row=$(_get_cursor_row)
declare current_row
current_row=$((first_row - 1))
trap "_cursor_blink_on; stty echo; exit" 2
_cursor_blink_off
_check_range() {
val=$1
if [[ "$val" -gt "$max" ]]; then
val=$min
elif [[ "$val" -lt "$min" ]]; then
val=$max
fi
echo "$val"
}
while true; do
_prompt_text "$1"
printf "\033[37m%s\033[0m \033[1;90m\033[0m \033[36m%s%s\033[0m \033[1;90m\033[0m \033[37m%s\033[0m\n" "$min" "${padding:${#selected}}" "$selected" "$max" >&2
case $(_key_input) in
enter)
break
;;
left)
selected="$(_check_range $((selected - 1)))"
;;
right)
selected="$(_check_range $((selected + 1)))"
;;
esac
_cursor_to "$current_row"
done
echo "$selected"
}
validate_present() {
if [ "$1" != "" ]; then
return 0
else
error "Please specify the value"
return 1
fi
}
show_error() {
echo -e "\033[91;1m✘ $1\033[0m" >&2
}
show_success() {
echo -e "\033[92;1m✔ $1\033[0m" >&2
}
detect_os() {
case "$OSTYPE" in
solaris*) echo "solaris" ;;
darwin*) echo "macos" ;;
linux*) echo "linux" ;;
bsd*) echo "bsd" ;;
msys*) echo "windows" ;;
cygwin*) echo "windows" ;;
*) echo "unknown" ;;
esac
}
get_opener() {
declare cmd
case "$(detect_os)" in
macos) cmd="open" ;;
linux) cmd="xdg-open" ;;
windows) cmd="start" ;;
*) cmd="" ;;
esac
echo "$cmd"
}
open_link() {
cmd="$(get_opener)"
if [[ "$cmd" == "" ]]; then
error "Your platform is not supported for opening links."
red "Please open the following URL in your preferred browser:"
red " ${1}"
return 1
fi
$cmd "$1"
if [[ $? -eq 1 ]]; then
error "Failed to open your browser."
red "Please open the following URL in your browser:"
red "${1}"
return 1
fi
return 0
}
guard_operation() {
if [[ -t 1 ]]; then
ans="$(confirm "${1:-Are you sure you want to continue?}")"
if [[ "$ans" == 0 ]]; then
error "Operation aborted!" 2>&1
exit 1
fi
fi
}
# 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}")
patch_file() {
awk '
FNR == NR {
lines[FNR] = $0
next;
}
{
patchLines[FNR] = $0
}
END {
totalPatchLines=length(patchLines)
totalLines = length(lines)
patchLineIndex = 1
mode = "none"
while (patchLineIndex <= totalPatchLines) {
line = patchLines[patchLineIndex]
if (line ~ /^--- / || line ~ /^\+\+\+ /) {
patchLineIndex++
continue
}
if (line ~ /^@@ /) {
mode = "hunk"
hunkIndex++
patchLineIndex++
continue
}
if (mode == "hunk") {
while (patchLineIndex <= totalPatchLines && line ~ /^[-+ ]|^\s*$/ && line !~ /^--- /) {
sanitizedLine = substr(line, 2)
if (line !~ /^\+/) {
hunkTotalOriginalLines[hunkIndex]++;
hunkOriginalLines[hunkIndex,hunkTotalOriginalLines[hunkIndex]] = sanitizedLine
}
if (line !~ /^-/) {
hunkTotalUpdatedLines[hunkIndex]++;
hunkUpdatedLines[hunkIndex,hunkTotalUpdatedLines[hunkIndex]] = sanitizedLine
}
patchLineIndex++
line = patchLines[patchLineIndex]
}
mode = "none"
} else {
patchLineIndex++
}
}
if (hunkIndex == 0) {
print "error: no patch" > "/dev/stderr"
exit 1
}
totalHunks = hunkIndex
hunkIndex = 1
for (lineIndex = 1; lineIndex <= totalLines; lineIndex++) {
line = lines[lineIndex]
nextLineIndex = 0
if (hunkIndex <= totalHunks && line == hunkOriginalLines[hunkIndex,1]) {
nextLineIndex = lineIndex + 1
for (i = 2; i <= hunkTotalOriginalLines[hunkIndex]; i++) {
if (lines[nextLineIndex] != hunkOriginalLines[hunkIndex,i]) {
nextLineIndex = 0
break
}
nextLineIndex++
}
}
if (nextLineIndex > 0) {
for (i = 1; i <= hunkTotalUpdatedLines[hunkIndex]; i++) {
print hunkUpdatedLines[hunkIndex,i]
}
hunkIndex++
lineIndex = nextLineIndex - 1;
} else {
print line
}
}
if (hunkIndex != totalHunks + 1) {
print "error: unable to apply patch" > "/dev/stderr"
exit 1
}
}
function inspectHunks() {
print "/* Begin inspecting hunks"
for (i = 1; i <= totalHunks; i++) {
print ">>>>>> Original"
for (j = 1; j <= hunkTotalOriginalLines[i]; j++) {
print hunkOriginalLines[i,j]
}
print "======"
for (j = 1; j <= hunkTotalUpdatedLines[i]; j++) {
print hunkUpdatedLines[i,j]
}
print "<<<<<< Updated"
}
print "End inspecting hunks */\n"
}' "$1" "$2"
}
guard_path() {
if [[ "$#" -ne 2 ]]; then
echo "Usage: guard_path <path> <confirmation_prompt>" >&2
exit 1
fi
if [[ -t 1 ]]; then
path="$(_to_real_path "$1")"
confirmation_prompt="$2"
if [[ ! "$path" == "$(pwd)"* ]]; then
ans="$(confirm "$confirmation_prompt")"
if [[ "$ans" == 0 ]]; then
error "Operation aborted!" >&2
exit 1
fi
fi
fi
}
_to_real_path() {
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 "/"
}
}
}'
}