feat(plugins): Added the official bootstrap plugin repository
This commit is contained in:
@@ -41,6 +41,7 @@ Example `plugins.json`:
|
||||
"my_plugin": {
|
||||
"version": "1.0.0",
|
||||
"url": "https://raw.githubusercontent.com/yourusername/repo/main/my_plugin.sh",
|
||||
"bootstrap": "2.1.0",
|
||||
"description": "An awesome plugin that prints logs"
|
||||
}
|
||||
}
|
||||
@@ -49,6 +50,7 @@ Example `plugins.json`:
|
||||
|
||||
* **`version`**: The current semantic version of your plugin. When `bootstrap` detects a version change during `b up`, it automatically clears the cached `.sh` file, forcing a lazy re-download on the next invocation.
|
||||
* **`url`**: The raw, direct URL to your `.sh` plugin script.
|
||||
* **`bootstrap`**: The latest version of `bootstrap` that this plugin has been tested against and is compatible with. If the user's `bootstrap` version is newer than this value, a warning is displayed notifying them of potential incompatibility.
|
||||
|
||||
## 3. Distribution
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
# pardon my french
|
||||
parse_json() {
|
||||
# Tokenize the JSON using grep
|
||||
grep -oE '"([^"\\]|\\.)*"|true|false|null|[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?|[{}[\]:,]' | \
|
||||
grep -oE '"([^"\\]|\\.)*"|true|false|null|[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?|[][}{:,]' | \
|
||||
awk '
|
||||
BEGIN {
|
||||
depth=0;
|
||||
|
||||
13
lib/plugin_cache.sh
Normal file
13
lib/plugin_cache.sh
Normal file
@@ -0,0 +1,13 @@
|
||||
# Auto-generated plugin cache. Do not edit manually.
|
||||
declare -g -A PLUGIN_URLS
|
||||
declare -g -A PLUGIN_VERSIONS
|
||||
declare -g -A PLUGIN_BOOTSTRAP_VERSIONS
|
||||
PLUGIN_VERSIONS["weather"]="1.0.0"
|
||||
PLUGIN_URLS["weather"]="https://git.adityagupta.dev/sortedcord/bootstrap/raw/branch/master/official_plugins/weather.sh"
|
||||
PLUGIN_BOOTSTRAP_VERSIONS["weather"]="2.1.0"
|
||||
PLUGIN_VERSIONS["sysinfo"]="1.0.0"
|
||||
PLUGIN_URLS["sysinfo"]="https://git.adityagupta.dev/sortedcord/bootstrap/raw/branch/master/official_plugins/sysinfo.sh"
|
||||
PLUGIN_BOOTSTRAP_VERSIONS["sysinfo"]="2.1.0"
|
||||
PLUGIN_VERSIONS["todo"]="1.0.0"
|
||||
PLUGIN_URLS["todo"]="https://git.adityagupta.dev/sortedcord/bootstrap/raw/branch/master/official_plugins/todo.sh"
|
||||
PLUGIN_BOOTSTRAP_VERSIONS["todo"]="2.1.0"
|
||||
@@ -39,14 +39,28 @@ parse_plugin_manifest() {
|
||||
print "PLUGIN_VERSIONS[\"" plugin_name "\"]=\"" val "\""
|
||||
} else if (prop == "url") {
|
||||
print "PLUGIN_URLS[\"" plugin_name "\"]=\"" val "\""
|
||||
} else if (prop == "bootstrap") {
|
||||
print "PLUGIN_BOOTSTRAP_VERSIONS[\"" plugin_name "\"]=\"" val "\""
|
||||
}
|
||||
}
|
||||
}
|
||||
}'
|
||||
}
|
||||
|
||||
# Ensures that the plugin sources file exists, initializing it with the official repository by default
|
||||
ensure_sources_file() {
|
||||
local sources_file="$BOOTSTRAP_DIR/plugin_sources.txt"
|
||||
if [ ! -f "$sources_file" ]; then
|
||||
mkdir -p "$BOOTSTRAP_DIR"
|
||||
echo "# Add raw URLs to JSON plugin manifests here, one per line." > "$sources_file"
|
||||
echo "# Official Bootstrap plugin repository" >> "$sources_file"
|
||||
echo "https://git.adityagupta.dev/sortedcord/bootstrap/raw/branch/master/plugins.json" >> "$sources_file"
|
||||
fi
|
||||
}
|
||||
|
||||
# Fetches manifests from sources and generates the cache
|
||||
update_plugin_cache() {
|
||||
ensure_sources_file
|
||||
local cache_file="$BOOTSTRAP_DIR/lib/plugin_cache.sh"
|
||||
local sources_file="$BOOTSTRAP_DIR/plugin_sources.txt"
|
||||
|
||||
@@ -57,6 +71,7 @@ update_plugin_cache() {
|
||||
# Auto-generated plugin cache. Do not edit manually.
|
||||
declare -g -A PLUGIN_URLS
|
||||
declare -g -A PLUGIN_VERSIONS
|
||||
declare -g -A PLUGIN_BOOTSTRAP_VERSIONS
|
||||
EOF
|
||||
|
||||
if [ -f "$sources_file" ]; then
|
||||
@@ -93,11 +108,8 @@ EOF
|
||||
}
|
||||
|
||||
manage_plugin_sources() {
|
||||
ensure_sources_file
|
||||
local sources_file="$BOOTSTRAP_DIR/plugin_sources.txt"
|
||||
if [ ! -f "$sources_file" ]; then
|
||||
touch "$sources_file"
|
||||
echo "# Add raw URLs to JSON plugin manifests here, one per line." > "$sources_file"
|
||||
fi
|
||||
|
||||
local editor="${EDITOR:-}"
|
||||
if [ -z "$editor" ]; then
|
||||
@@ -151,6 +163,18 @@ run_plugin() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check compatibility version
|
||||
local compat_ver="${PLUGIN_BOOTSTRAP_VERSIONS[$plugin_name]:-}"
|
||||
if [ -n "$compat_ver" ]; then
|
||||
local current_ver="0.0.0"
|
||||
if [ -f "$BOOTSTRAP_DIR/VERSION" ]; then
|
||||
current_ver=$(cat "$BOOTSTRAP_DIR/VERSION" | tr -d '[:space:]')
|
||||
fi
|
||||
if version_lt "$compat_ver" "$current_ver"; then
|
||||
log_warn "Plugin '$plugin_name' is only tested up to bootstrap version $compat_ver (current: $current_ver). It may be incompatible."
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$is_ephemeral" = "true" ]; then
|
||||
log_info "Downloading and running plugin '$plugin_name' (ephemeral)..."
|
||||
local script_content
|
||||
|
||||
@@ -200,7 +200,6 @@ for script in "${SCRIPTS[@]}"; do
|
||||
# Handle non-installer commands
|
||||
case "$script" in
|
||||
plugin)
|
||||
shift # consume 'plugin' arg
|
||||
handle_plugin "$@"
|
||||
# Once handle_plugin completes, we should exit so it doesn't process more SCRIPTS
|
||||
exit $?
|
||||
|
||||
22
plugins.json
Normal file
22
plugins.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"plugins": {
|
||||
"weather": {
|
||||
"version": "1.0.0",
|
||||
"url": "https://git.adityagupta.dev/sortedcord/bootstrap/raw/branch/master/plugins/weather.sh",
|
||||
"bootstrap": "2.1.0",
|
||||
"description": "Show weather forecast for your location"
|
||||
},
|
||||
"sysinfo": {
|
||||
"version": "1.0.0",
|
||||
"url": "https://git.adityagupta.dev/sortedcord/bootstrap/raw/branch/master/plugins/sysinfo.sh",
|
||||
"bootstrap": "2.1.0",
|
||||
"description": "Show system information and hardware statistics"
|
||||
},
|
||||
"todo": {
|
||||
"version": "1.0.0",
|
||||
"url": "https://git.adityagupta.dev/sortedcord/bootstrap/raw/branch/master/plugins/todo.sh",
|
||||
"bootstrap": "2.1.0",
|
||||
"description": "A simple command-line todo list manager"
|
||||
}
|
||||
}
|
||||
}
|
||||
74
plugins/sysinfo.sh
Normal file
74
plugins/sysinfo.sh
Normal file
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env bash
|
||||
# System Information Dashboard Plugin for bootstrap CLI
|
||||
|
||||
main() {
|
||||
if [ "${1:-}" = "--help" ] || [ "${1:-}" = "-h" ]; then
|
||||
echo "Usage: b sysinfo"
|
||||
echo ""
|
||||
echo "Displays a beautiful system resource and hardware information dashboard."
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}==================================================${NC}"
|
||||
echo -e " ${GREEN}SYSTEM INFORMATION DASHBOARD${NC}"
|
||||
echo -e "${BLUE}==================================================${NC}"
|
||||
|
||||
# OS Info
|
||||
local os_name="Unknown"
|
||||
if [ -f /etc/os-release ]; then
|
||||
os_name=$(grep "^PRETTY_NAME=" /etc/os-release | cut -d= -f2 | tr -d '"')
|
||||
elif [ "$(uname)" = "Darwin" ]; then
|
||||
os_name="macOS $(sw_vers -productVersion)"
|
||||
else
|
||||
os_name=$(uname -s)
|
||||
fi
|
||||
echo -e "${BLUE}OS:${NC} $os_name"
|
||||
echo -e "${BLUE}Kernel:${NC} $(uname -r)"
|
||||
echo -e "${BLUE}Uptime:${NC} $(uptime | sed 's/^ *//')"
|
||||
|
||||
# CPU Info
|
||||
local cpu_info="Unknown"
|
||||
if [ -f /proc/cpuinfo ]; then
|
||||
cpu_info=$(grep -m1 "model name" /proc/cpuinfo | cut -d: -f2 | sed 's/^ *//')
|
||||
elif [ "$(uname)" = "Darwin" ]; then
|
||||
cpu_info=$(sysctl -n machdep.cpu.brand_string)
|
||||
fi
|
||||
echo -e "${BLUE}CPU:${NC} $cpu_info"
|
||||
|
||||
# Load Average
|
||||
local load_avg
|
||||
load_avg=$(uptime | awk -F'load average:' '{ print $2 }' | sed 's/^ *//')
|
||||
echo -e "${BLUE}Load Avg:${NC} $load_avg"
|
||||
|
||||
# Memory Usage
|
||||
echo -e "${BLUE}Memory:${NC}"
|
||||
if has_command free; then
|
||||
free -h | awk 'NR==2{printf " Used: %s / Total: %s (%.2f%%)\n", $3, $2, $3/$2*100}'
|
||||
elif [ -f /proc/meminfo ]; then
|
||||
local mem_total
|
||||
mem_total=$(grep "MemTotal" /proc/meminfo | awk '{print $2}')
|
||||
local mem_free
|
||||
mem_free=$(grep "MemFree" /proc/meminfo | awk '{print $2}')
|
||||
local mem_used=$((mem_total - mem_free))
|
||||
# Convert to MB
|
||||
local total_mb=$((mem_total / 1024))
|
||||
local used_mb=$((mem_used / 1024))
|
||||
local pct=$((used_mb * 100 / total_mb))
|
||||
echo " Used: ${used_mb}MB / Total: ${total_mb}MB (${pct}%)"
|
||||
elif [ "$(uname)" = "Darwin" ]; then
|
||||
local total_mem
|
||||
total_mem=$(sysctl -n hw.memsize)
|
||||
local total_gb=$((total_mem / 1024 / 1024 / 1024))
|
||||
echo " Total: ${total_gb}GB"
|
||||
else
|
||||
echo " Unavailable"
|
||||
fi
|
||||
|
||||
# Disk Usage
|
||||
echo -e "${BLUE}Disk Space (Root):${NC}"
|
||||
df -h / | awk 'NR==2{printf " Used: %s / Total: %s (%s)\n", $3, $2, $5}'
|
||||
|
||||
echo -e "${BLUE}==================================================${NC}"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
123
plugins/todo.sh
Normal file
123
plugins/todo.sh
Normal file
@@ -0,0 +1,123 @@
|
||||
#!/usr/bin/env bash
|
||||
# Todo List Plugin for bootstrap CLI
|
||||
|
||||
TODO_FILE="$HOME/.local/share/bootstrap/todo.txt"
|
||||
|
||||
main() {
|
||||
mkdir -p "$(dirname "$TODO_FILE")"
|
||||
[ ! -f "$TODO_FILE" ] && touch "$TODO_FILE"
|
||||
|
||||
local action="${1:-list}"
|
||||
case "$action" in
|
||||
add)
|
||||
shift
|
||||
if [ -z "$*" ]; then
|
||||
log_error "Please specify a task to add."
|
||||
echo "Usage: b todo add <task description>"
|
||||
return 1
|
||||
fi
|
||||
echo "[ ] $*" >> "$TODO_FILE"
|
||||
log_success "Added task: $*"
|
||||
;;
|
||||
list)
|
||||
if [ ! -s "$TODO_FILE" ]; then
|
||||
log_info "Your todo list is empty. Add a task with: b todo add <task>"
|
||||
return 0
|
||||
fi
|
||||
echo -e "${BLUE}--- YOUR TODO LIST ---${NC}"
|
||||
local line_num=1
|
||||
while IFS= read -r line || [ -n "$line" ]; do
|
||||
# Highlight completed tasks
|
||||
if [[ "$line" == "[\x]"* || "$line" == "[x]"* ]]; then
|
||||
echo -e " ${line_num}. ${GREEN}${line}${NC}"
|
||||
else
|
||||
echo -e " ${line_num}. ${line}"
|
||||
fi
|
||||
line_num=$((line_num + 1))
|
||||
done < "$TODO_FILE"
|
||||
;;
|
||||
done)
|
||||
shift
|
||||
local task_num="${1:-}"
|
||||
if [[ ! "$task_num" =~ ^[0-9]+$ ]]; then
|
||||
log_error "Please specify a valid task number."
|
||||
echo "Usage: b todo done <number>"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local total_tasks
|
||||
total_tasks=$(wc -l < "$TODO_FILE")
|
||||
if [ "$task_num" -lt 1 ] || [ "$task_num" -gt "$total_tasks" ]; then
|
||||
log_error "Task number out of range (1-$total_tasks)."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Update the task at line task_num to be marked [x]
|
||||
local temp_file
|
||||
temp_file=$(mktemp)
|
||||
local line_num=1
|
||||
while IFS= read -r line || [ -n "$line" ]; do
|
||||
if [ "$line_num" -eq "$task_num" ]; then
|
||||
# Replace [ ] with [x]
|
||||
echo "${line/\[ \]/\[x\]}" >> "$temp_file"
|
||||
else
|
||||
echo "$line" >> "$temp_file"
|
||||
fi
|
||||
line_num=$((line_num + 1))
|
||||
done < "$TODO_FILE"
|
||||
mv "$temp_file" "$TODO_FILE"
|
||||
log_success "Marked task #$task_num as completed."
|
||||
;;
|
||||
rm|remove)
|
||||
shift
|
||||
local task_num="${1:-}"
|
||||
if [[ ! "$task_num" =~ ^[0-9]+$ ]]; then
|
||||
log_error "Please specify a valid task number to remove."
|
||||
echo "Usage: b todo rm <number>"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local total_tasks
|
||||
total_tasks=$(wc -l < "$TODO_FILE")
|
||||
if [ "$task_num" -lt 1 ] || [ "$task_num" -gt "$total_tasks" ]; then
|
||||
log_error "Task number out of range (1-$total_tasks)."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Remove the line at task_num
|
||||
local temp_file
|
||||
temp_file=$(mktemp)
|
||||
local line_num=1
|
||||
while IFS= read -r line || [ -n "$line" ]; do
|
||||
if [ "$line_num" -ne "$task_num" ]; then
|
||||
echo "$line" >> "$temp_file"
|
||||
fi
|
||||
line_num=$((line_num + 1))
|
||||
done < "$TODO_FILE"
|
||||
mv "$temp_file" "$TODO_FILE"
|
||||
log_success "Removed task #$task_num."
|
||||
;;
|
||||
clear)
|
||||
> "$TODO_FILE"
|
||||
log_success "Cleared all tasks from your todo list."
|
||||
;;
|
||||
--help|-h)
|
||||
echo "Usage: b todo [action] [args]"
|
||||
echo ""
|
||||
echo "Actions:"
|
||||
echo " list Show all tasks (default)"
|
||||
echo " add <task> Add a new task"
|
||||
echo " done <number> Mark a task as completed"
|
||||
echo " rm <number> Remove a task"
|
||||
echo " clear Delete all tasks"
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
log_error "Unknown action: $action"
|
||||
echo "Run 'b todo --help' for usage instructions."
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
main "$@"
|
||||
32
plugins/weather.sh
Normal file
32
plugins/weather.sh
Normal file
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env bash
|
||||
# Weather Plugin for bootstrap CLI
|
||||
|
||||
main() {
|
||||
if [ "${1:-}" = "--help" ] || [ "${1:-}" = "-h" ]; then
|
||||
echo "Usage: b weather [location]"
|
||||
echo ""
|
||||
echo "Fetches and displays a neat weather forecast."
|
||||
echo "If no location is specified, it auto-detects based on your IP."
|
||||
return 0
|
||||
fi
|
||||
|
||||
local location="$*"
|
||||
log_info "Fetching weather forecast..."
|
||||
|
||||
if [ -n "$location" ]; then
|
||||
# URL encode the location (replace spaces with +)
|
||||
local encoded_location
|
||||
encoded_location=$(echo "$location" | tr ' ' '+')
|
||||
if ! curl -sS "wttr.in/${encoded_location}?0&m"; then
|
||||
log_error "Failed to fetch weather for '$location'."
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
if ! curl -sS "wttr.in/?0&m"; then
|
||||
log_error "Failed to fetch weather."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
main "$@"
|
||||
24
readme.md
24
readme.md
@@ -115,6 +115,28 @@ Plugins are first-party or third-party applications written to work directly wit
|
||||
|
||||
Downloading and invoking a plugin makes no system modifications other than caching the `.sh` file itself. They are fetched only the very first time you invoke them.
|
||||
|
||||
### Official Plugins
|
||||
|
||||
Bootstrap comes pre-configured with a set of official plugins ready to use out-of-the-box:
|
||||
|
||||
* **`weather`**: Fetches and displays a neat weather forecast using `wttr.in`.
|
||||
```bash
|
||||
b weather
|
||||
b weather New York
|
||||
```
|
||||
* **`sysinfo`**: Displays a system resource dashboard showing CPU, memory, disk usage, and OS/kernel details.
|
||||
```bash
|
||||
b sysinfo
|
||||
```
|
||||
* **`todo`**: A command-line todo list manager. Tasks are persisted to a lightweight text file in your user directory.
|
||||
```bash
|
||||
b todo add "Write a new plugin"
|
||||
b todo list
|
||||
b todo done 1
|
||||
```
|
||||
|
||||
### Adding Third-Party Plugins
|
||||
|
||||
To manage plugin repositories, run:
|
||||
|
||||
```bash
|
||||
@@ -123,7 +145,7 @@ b plugin sources
|
||||
|
||||
This opens a configuration file in your `$EDITOR`. You can add raw URLs pointing to JSON plugin manifests from any repository. Once you close the editor, `bootstrap` automatically parses those manifests using its native JSON parser and generates a fast, zero-latency lookup cache.
|
||||
|
||||
You can then execute a plugin simply by calling its name:
|
||||
You can then execute any plugin simply by calling its name:
|
||||
|
||||
```bash
|
||||
b my_plugin
|
||||
|
||||
Reference in New Issue
Block a user