mirror of
https://github.com/sortedcord/bootstrap.git
synced 2026-07-22 20:22:50 +05:30
Compare commits
2 Commits
5ba08f3d20
...
refactor/i
| Author | SHA1 | Date | |
|---|---|---|---|
| 506083b85a | |||
| 6e63e54f1e |
@@ -1,11 +1,11 @@
|
||||
---
|
||||
name: add_installer
|
||||
description: Add a new installer script to the bootstrap CLI project. Use this skill whenever the user asks to create a new installer, add a new tool/package to bootstrap, or register a new `b <name>` command.
|
||||
name: add_tool
|
||||
description: Add a new tool definition script to the bootstrap CLI project. Use this skill whenever the user asks to create a new tool, add a new tool/package to bootstrap, or register a new `b <name>` command.
|
||||
---
|
||||
|
||||
# Add a New Installer to Bootstrap CLI
|
||||
# Add a New Tool to Bootstrap CLI
|
||||
|
||||
This skill provides everything needed to add a new installer to the bootstrap project without reading the entire codebase.
|
||||
This skill provides everything needed to add a new tool to the bootstrap project without reading the entire codebase.
|
||||
|
||||
## Project Overview
|
||||
|
||||
@@ -15,15 +15,15 @@ Bootstrap CLI (`b`) is a bash-based tool installer and system bootstrapper. User
|
||||
|
||||
```
|
||||
bootstrap/
|
||||
├── installers/ # Individual installer scripts (install_<name>.sh)
|
||||
├── lib/ # Shared libraries and router sourced by all installers
|
||||
├── tools/ # Individual tool directories (tools/<name>/tool.sh)
|
||||
├── lib/ # Shared libraries and router sourced by all tools
|
||||
│ ├── common.sh # Logging, confirm(), has_command(), make_temp_dir()
|
||||
│ ├── platform.sh # detect_distro(), detect_arch(), pkg_install(), pkg_check(), pkg_remove()
|
||||
│ ├── rollback.sh # Rollback tracking (track_file, track_dir, add_rollback_cmd)
|
||||
│ ├── shell_config.sh # write_env_snippet, write_alias_snippet, write_completion_snippet
|
||||
│ ├── registry.sh # Dynamically generated installer registry
|
||||
│ ├── registry.sh # Dynamically generated tool registry
|
||||
│ └── routes.sh # Central router script
|
||||
├── commands/ # Non-installer commands (help, con, uninstall)
|
||||
├── commands/ # Non-tool commands (help, con, uninstall)
|
||||
├── assets/ # Assets (logo art, etc.)
|
||||
│ └── pixel_art.ansi
|
||||
├── bootstrap.sh # Metascript for environment setup + library loading
|
||||
@@ -33,12 +33,12 @@ bootstrap/
|
||||
|
||||
## Step-by-Step Checklist
|
||||
|
||||
When adding a new installer named `<name>`:
|
||||
When adding a new tool named `<name>`:
|
||||
|
||||
### Step 1: Analyze user request & gather details
|
||||
|
||||
When the user asks you to create an installer, they often provide either an official `curl` install script or a link to a `.tar.gz` release.
|
||||
You MUST do the following before writing the script:
|
||||
When the user asks you to add a tool, they often provide either an official `curl` install script or a link to a `.tar.gz` release.
|
||||
You MUST do the following before writing the tool script:
|
||||
|
||||
If the user provides an official install or curl script in the prompt, or a link to one:
|
||||
- Execute the `curl` command (or use `read_url_content` or `read_browser_page`) to fetch the script and analyze what it actually does under the hood.
|
||||
@@ -51,13 +51,15 @@ If the user provides an official install or curl script in the prompt, or a link
|
||||
**If the user provides a link to a `.tar.gz` (or `.zip`):**
|
||||
- First, download the archive to a temporary directory and extract it to inspect its contents.
|
||||
- Analyze the extracted folder structure to decide what needs to be installed (e.g., binaries, man pages, completions) and what should be ignored/deleted.
|
||||
- Write the `install_<name>` function to download, extract, and copy only those essential files. (Use `download_file` and temporary directories, see "Resumable Download and Extraction" below).
|
||||
- Write the `install_<name>` function to download, extract, and copy only those essential files. (Use `download_file` and temporary directories, see "GitHub Download and Extraction" below).
|
||||
|
||||
### Step 2: Create the installer script
|
||||
### Step 2: Create the tool script
|
||||
|
||||
### Step 3: Add metadata comments to the top of your installer script
|
||||
Create `tools/<name>/tool.sh` using the template below.
|
||||
|
||||
At the top of your new installer script, right below `#!/usr/bin/env bash`, add the following metadata headers:
|
||||
### Step 3: Add metadata comments to the top of your tool script
|
||||
|
||||
At the top of your new tool script, right below `#!/usr/bin/env bash`, add the following metadata headers:
|
||||
```bash
|
||||
# Tool: <name>
|
||||
# DisplayName: <displayName>
|
||||
@@ -65,7 +67,7 @@ At the top of your new installer script, right below `#!/usr/bin/env bash`, add
|
||||
# Strategy: <strategy> (binary | managed | system)
|
||||
```
|
||||
|
||||
The central router `lib/routes.sh` and autocomplete function in `b.sh` will dynamically parse this metadata from all `install_*.sh` scripts to register the installer and keys automatically! No manual edits to `lib/routes.sh` or `b.sh` are required.
|
||||
The central router `lib/routes.sh` and autocomplete function in `b.sh` will dynamically parse this metadata from all `tools/*/tool.sh` scripts to register the tool and keys automatically! No manual edits to `lib/routes.sh` or `b.sh` are required.
|
||||
|
||||
### Step 4: Implement Rollback Tracking (Crucial)
|
||||
|
||||
@@ -78,16 +80,16 @@ To ensure the user can seamlessly use `b rb <name>` to uninstall or rollback a t
|
||||
|
||||
### Step 5: Verify (optional)
|
||||
|
||||
Verify that the installer works and appears in the help output:
|
||||
Verify that the tool works and appears in the help output:
|
||||
- Run `b all` to confirm it appears in the help list.
|
||||
- Run `b ware <name> -y` to test direct installation.
|
||||
- Run `b ware <name>` to test the interactive editing flow.
|
||||
|
||||
---
|
||||
|
||||
## Installer Script Template
|
||||
## Tool Script Template
|
||||
|
||||
Every installer follows this exact structure. Copy this and fill in the tool-specific logic (notice there are no standalone execution guards or curl checks):
|
||||
Every tool follows this exact structure. Copy this and fill in the tool-specific logic (notice there are no standalone execution guards or curl checks):
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
@@ -152,7 +154,7 @@ main "$@"
|
||||
|
||||
## Available Library Functions
|
||||
|
||||
These are pre-loaded by `bootstrap.sh` — no need to source them manually in installers.
|
||||
These are pre-loaded by `bootstrap.sh` — no need to source them manually in tool scripts.
|
||||
|
||||
### From `lib/common.sh`
|
||||
|
||||
@@ -248,7 +250,7 @@ track_file "$BOOTSTRAP_BIN/binary"
|
||||
|
||||
## Rules & Conventions
|
||||
|
||||
1. **File naming**: Always `install_<name>.sh` in the `installers/` directory.
|
||||
1. **File naming**: Always `tools/<name>/tool.sh`.
|
||||
2. **Confirmation prompts**: Always ask before installing. Check if already installed first.
|
||||
3. **Rollback Tracking**: NEVER omit rollback hooks. If you move a file to `$BOOTSTRAP_BIN`, you MUST call `track_file`. If you build/install manually (e.g. via `makepkg -si`), you MUST call `add_rollback_cmd "sudo pacman -R --noconfirm <pkg>"` or equivalent.
|
||||
4. **Shell Drop-ins**: Always use `write_env_snippet`, `write_alias_snippet`, or `write_completion_snippet` instead of manually injecting code directly into `~/.bashrc`.
|
||||
@@ -20,11 +20,11 @@ When the user asks to "cut a release", "bump the version", or "tag a new version
|
||||
git log $(git describe --tags --abbrev=0)..HEAD --oneline
|
||||
```
|
||||
2. **Determine the bump level** using semantic versioning rules:
|
||||
- Skip any commits that only touch `installers/` or docs — those don't warrant a bump.
|
||||
- Skip any commits that only touch `tools/` or docs — those don't warrant a bump.
|
||||
- If any commit has `BREAKING CHANGE` or `!:` → **major**
|
||||
- If any core-CLI commit has `feat:` → **minor**
|
||||
- Otherwise (only `fix:`, `refactor:`, etc. in core-CLI) → **patch**
|
||||
- If *all* commits are installer-only or docs-only → inform the user no release is needed.
|
||||
- If *all* commits are tool-only or docs-only → inform the user no release is needed.
|
||||
3. **Formulate a verbose, structured description of the changes** based on the analyzed commits. Group the changes into logical sections (such as "Breaking Changes & Major Features:" and "Other Updates:") and list the corresponding commit messages or summaries. Example format:
|
||||
```text
|
||||
Breaking Changes & Major Features:
|
||||
|
||||
8
b.sh
8
b.sh
@@ -93,8 +93,8 @@ _b_completion() {
|
||||
|
||||
local routes_dir="$HOME/.config/bootstrap"
|
||||
local installer_keys=""
|
||||
if [ -d "$routes_dir/installers" ]; then
|
||||
for f in "$routes_dir/installers"/install_*.sh; do
|
||||
if [ -d "$routes_dir/tools" ]; then
|
||||
for f in "$routes_dir/tools"/*/tool.sh; do
|
||||
if [ -f "$f" ]; then
|
||||
local tool
|
||||
tool=$(grep -E "^# Tool:" "$f" | head -n1 | sed -E 's/^# Tool:\s*//I')
|
||||
@@ -135,8 +135,8 @@ _b_completion() {
|
||||
if [ "$COMP_CWORD" -eq 2 ] && { [ "$prev" = "ware" ] || [ "$prev" = "bware" ]; }; then
|
||||
local routes_dir="$HOME/.config/bootstrap"
|
||||
local installer_keys=""
|
||||
if [ -d "$routes_dir/installers" ]; then
|
||||
for f in "$routes_dir/installers"/install_*.sh; do
|
||||
if [ -d "$routes_dir/tools" ]; then
|
||||
for f in "$routes_dir/tools"/*/tool.sh; do
|
||||
if [ -f "$f" ]; then
|
||||
local tool
|
||||
tool=$(grep -E "^# Tool:" "$f" | head -n1 | sed -E 's/^# Tool:\s*//I')
|
||||
|
||||
@@ -120,10 +120,10 @@ EOF
|
||||
fi
|
||||
done
|
||||
|
||||
# Also copy installers if they exist locally
|
||||
if [ -d "$_SCRIPT_DIR/installers" ]; then
|
||||
mkdir -p "$routes_dir/installers"
|
||||
cp -r "$_SCRIPT_DIR/installers/"* "$routes_dir/installers/"
|
||||
# Also copy tools if they exist locally
|
||||
if [ -d "$_SCRIPT_DIR/tools" ]; then
|
||||
mkdir -p "$routes_dir/tools"
|
||||
cp -r "$_SCRIPT_DIR/tools/"* "$routes_dir/tools/"
|
||||
fi
|
||||
|
||||
# Also copy plugins if they exist locally
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# shellcheck shell=bash
|
||||
# Command: help
|
||||
# Lists all available bootstrap commands and installers
|
||||
# Lists all available bootstrap commands and tools
|
||||
|
||||
echo "Available bootstrap commands:"
|
||||
# Non-installers first (aligned to 6 chars width)
|
||||
# Non-tools first (aligned to 6 chars width)
|
||||
printf " %-6s - %s\n" "all" "List all available commands"
|
||||
printf " %-6s - %s\n" "con" "Edit config (e.g. b con nvim)"
|
||||
printf " %-6s - %s\n" "up" "Check for updates and update Bootstrap CLI"
|
||||
printf " %-6s - %s\n" "ware" "Edit and run an installer (e.g. b ware nvim)"
|
||||
printf " %-6s - %s\n" "ware" "Edit and run a tool (e.g. b ware nvim)"
|
||||
printf " %-6s - %s\n" "gone" "Uninstall Bootstrap CLI helper"
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Plugin Development Guide
|
||||
|
||||
Plugins are first-party or third-party applications written to work directly with `bootstrap`. Unlike installers (or packages) which modify your system by compiling code, downloading binaries, and altering shell configuration files, **plugins are lazy-loaded scripts that execute within a sandboxed subshell**.
|
||||
Plugins are first-party or third-party applications written to work directly with `bootstrap`. Unlike tools (or packages) which modify your system by compiling code, downloading binaries, and altering shell configuration files, **plugins are lazy-loaded scripts that execute within a sandboxed subshell**.
|
||||
|
||||
This means 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.
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ If the argument does not match an installed tool in the registry, it is treated
|
||||
## 4. Required Abstractions & Helper Modifications
|
||||
|
||||
### A. Context Initialization
|
||||
Before executing an installer script, the `b` CLI initializes the command list:
|
||||
Before executing a tool script, the `b` CLI initializes the command list:
|
||||
```bash
|
||||
export BOOTSTRAP_UNINSTALLER_CMDS="$HOME/.local/state/bootstrap/uninstallers/nvim.cmds"
|
||||
mkdir -p "$(dirname "$BOOTSTRAP_UNINSTALLER_CMDS")"
|
||||
@@ -97,7 +97,7 @@ log_success "Rollback complete."
|
||||
```
|
||||
|
||||
## 6. Resilience Against User Modifications
|
||||
Because `b ware <tool>` allows users to modify installation scripts:
|
||||
Because `b ware <tool>` allows users to modify tool scripts:
|
||||
1. **Dynamic Adaptation:** The manifest is built *during* execution, adapting to whatever packages the user manually added.
|
||||
2. **Fault Isolation:** The `eval` loop ensures that a syntax error in one custom rollback step doesn't crash the removal of other tracked packages.
|
||||
|
||||
@@ -113,7 +113,7 @@ When a tool is uninstalled:
|
||||
To handle failures during installation (e.g., network drops, script errors, or user cancellation via `Ctrl+C`), the CLI incorporates a transactional approach that balances **automatic rollback** and **resumability**:
|
||||
|
||||
### A. The Interruption Trap & Prompt
|
||||
When running an installer, the central router (`lib/routes.sh`) traps `SIGINT` and `SIGTERM` signals. If the installation fails or is interrupted:
|
||||
When running a tool, the central router (`lib/routes.sh`) traps `SIGINT` and `SIGTERM` signals. If the installation fails or is interrupted:
|
||||
1. The trap catches the event and stops execution.
|
||||
2. The user is prompted interactively:
|
||||
- **Rollback (r)**: Invokes `execute_rollback <tool>` immediately to clean up all partial modifications.
|
||||
@@ -130,6 +130,6 @@ If the user chooses to **keep** the partial state and runs `b <tool>` again:
|
||||
To make rerunning an interrupted script fast and efficient, installers use `download_file <url> <dest>` instead of raw `curl`:
|
||||
1. It downloads the payload to a central cache directory: `~/.local/state/bootstrap/cache/`.
|
||||
2. It uses `curl -C -` to continue the download from the byte offset where it was interrupted.
|
||||
3. Once completed, it copies the cached file to the installer's temp directory.
|
||||
3. Once completed, it copies the cached file to the tool's temp directory.
|
||||
4. Distro package manager commands (`pkg_install`) and shell snippets (`write_env_snippet`) are naturally idempotent, allowing the script to breeze through already completed steps in milliseconds and resume exactly where the heavy work failed.
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ The Bootstrap CLI uses a semantic, git-tag-driven versioning workflow.
|
||||
|
||||
- **Do not manually edit the `VERSION` file.**
|
||||
- Develop normally using [Conventional Commits](https://www.conventionalcommits.org/) (e.g., `feat: Add new tool`, `fix: Typo in script`).
|
||||
- **Note on Installers:** Adding or modifying installers in the `installers/` directory **does not** require a version bump. They are fetched dynamically from the registry when a user runs `b ware <tool>`.
|
||||
- **Note on Tools:** Adding or modifying tools in the `tools/` directory **does not** require a version bump. They are fetched dynamically from the registry when a user runs `b ware <tool>`.
|
||||
|
||||
## 2. When to Cut a Release
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
# GitHub API helper functions for Bootstrap installers
|
||||
# GitHub API helper functions for Bootstrap tools
|
||||
|
||||
# Usage: github_get_latest_release <owner/repo>
|
||||
# Prints the tag_name of the latest release.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
# Central routing script for bootstrap installers.
|
||||
# Central routing script for bootstrap tools.
|
||||
# This file is updated automatically by the 'b' command.
|
||||
|
||||
_LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd 2>/dev/null || pwd)"
|
||||
@@ -69,8 +69,8 @@ run_ware() {
|
||||
display_name="$(echo "${tool:0:1}" | tr '[:lower:]' '[:upper:]')${tool:1}"
|
||||
fi
|
||||
|
||||
# Check for local installer first
|
||||
local local_installer="$BOOTSTRAP_DIR/installers/install_${tool}.sh"
|
||||
# Check for local tool definition first
|
||||
local local_installer="$BOOTSTRAP_DIR/tools/${tool}/tool.sh"
|
||||
|
||||
if [ "$bypass_edit" = "true" ] && [ -f "$local_installer" ]; then
|
||||
log_info "Running ${display_name} installer..."
|
||||
@@ -86,7 +86,7 @@ run_ware() {
|
||||
else
|
||||
BOOTSTRAP_BASE_URL="${BOOTSTRAP_BASE_URL:-https://git.adityagupta.dev/sortedcord/bootstrap/raw/branch/master}"
|
||||
BOOTSTRAP_FALLBACK_URL="${BOOTSTRAP_FALLBACK_URL:-https://raw.githubusercontent.com/sortedcord/bootstrap/refs/heads/master}"
|
||||
local installer_path="installers/install_${tool}.sh"
|
||||
local installer_path="tools/${tool}/tool.sh"
|
||||
local download_status=0
|
||||
|
||||
log_info "Downloading ${display_name} installer..."
|
||||
|
||||
@@ -145,7 +145,7 @@ This retrieves the pending device's public key, prompts the administrator for co
|
||||
|
||||
## Plugins (`b <plugin_name>`)
|
||||
|
||||
Plugins are first-party or third-party applications written to work directly with `bootstrap`. Unlike installers (or packages) which modify your system by compiling code, downloading binaries, and altering shell configuration files, **plugins are lazy-loaded scripts that execute within a subshell**.
|
||||
Plugins are first-party or third-party applications written to work directly with `bootstrap`. Unlike tools (or packages) which modify your system by compiling code, downloading binaries, and altering shell configuration files, **plugins are lazy-loaded scripts that execute within a subshell**.
|
||||
|
||||
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.
|
||||
|
||||
@@ -263,8 +263,8 @@ Running scripts directly from the internet is convenient but should always be ap
|
||||
### Why Bootstrap is More Secure
|
||||
Instead of blindly piping large, third-party installation scripts (often hundreds or thousands of lines of unscrutinized code) directly from the internet into your shell, Bootstrap uses a **scrutinized and simplified** approach:
|
||||
|
||||
1. **Audited & Minimised**: Every script in `installers/` has been scrutinized, refactored, and stripped of redundant compatibility layers (like Windows/macOS support or complex environment checks), leaving only the essential, readable logic required for your setup.
|
||||
2. **Controlled Execution**: Since installer scripts are hosted locally in your cloned repository, you can review every line of code before executing it. You are never subject to silent, upstream changes to installers.
|
||||
1. **Audited & Minimised**: Every script in `tools/` has been scrutinized, refactored, and stripped of redundant compatibility layers (like Windows/macOS support or complex environment checks), leaving only the essential, readable logic required for your setup.
|
||||
2. **Controlled Execution**: Since tool scripts are hosted locally in your cloned repository, you can review every line of code before executing it. You are never subject to silent, upstream changes to tools.
|
||||
3. **No Raw Pipes**: We download official binary releases directly to verified temporary locations rather than running arbitrary third-party script pipelines.
|
||||
|
||||
If you want to audit the core Bootstrap CLI itself before running it:
|
||||
|
||||
@@ -5,7 +5,7 @@ set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
INSTALLERS_DIR="$REPO_DIR/installers"
|
||||
TOOLS_DIR="$REPO_DIR/tools"
|
||||
REGISTRY_FILE="$REPO_DIR/lib/registry.sh"
|
||||
|
||||
echo "==> Generating registry.sh..."
|
||||
@@ -16,7 +16,7 @@ declare -A tools_disp
|
||||
declare -A tools_strat
|
||||
keys=()
|
||||
|
||||
for f in "$INSTALLERS_DIR"/install_*.sh; do
|
||||
for f in "$TOOLS_DIR"/*/tool.sh; do
|
||||
[ -f "$f" ] || continue
|
||||
tool=$(grep -E "^# Tool:" "$f" | head -n1 | sed -E 's/^# Tool:\s*//I')
|
||||
disp_name=$(grep -E "^# DisplayName:" "$f" | head -n1 | sed -E 's/^# DisplayName:\s*//I')
|
||||
|
||||
Reference in New Issue
Block a user