Created
March 30, 2026 18:18
-
-
Save diegomarino/7606993d86f7498b07781ec6e2bb076c to your computer and use it in GitHub Desktop.
macOS System Inventory Generator — YAML snapshots of installed packages (Homebrew, npm, bun, uv, mas, Claude Code plugins)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # ============================================================================= | |
| # System Inventory Generator (macOS) | |
| # ============================================================================= | |
| # | |
| # Generates YAML snapshots of installed packages, organized by hostname. | |
| # Files are saved to data/$(hostname)/ for version control. | |
| # | |
| # Requirements: macOS, bash 4+, Homebrew (optional tools: mas, jq, uv, bun) | |
| # | |
| # Usage: | |
| # ./scripts/inventory.sh # Full inventory | |
| # ./scripts/inventory.sh --brew # Only Homebrew | |
| # ./scripts/inventory.sh --help # Show help | |
| # | |
| # ============================================================================= | |
| set -euo pipefail | |
| # ----------------------------------------------------------------------------- | |
| # Configuration | |
| # ----------------------------------------------------------------------------- | |
| # Use chezmoi source-path if available, otherwise fallback to script location | |
| if command -v chezmoi >/dev/null 2>&1; then | |
| BASE_DIR="$(chezmoi source-path)" | |
| else | |
| SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | |
| BASE_DIR="$(dirname "$SCRIPT_DIR")" | |
| fi | |
| HOSTNAME="$(scutil --get LocalHostName 2>/dev/null || hostname -s)" | |
| DATA_DIR="$BASE_DIR/data/$HOSTNAME" | |
| # TIMESTAMP removed to avoid unnecessary git changes | |
| # Colors | |
| GREEN='\033[0;32m' | |
| YELLOW='\033[1;33m' | |
| BLUE='\033[0;34m' | |
| NC='\033[0m' | |
| # ----------------------------------------------------------------------------- | |
| # Functions | |
| # ----------------------------------------------------------------------------- | |
| info() { printf '%b[info]%b %s\n' "$BLUE" "$NC" "$1"; } | |
| success() { printf '%b[ok]%b %s\n' "$GREEN" "$NC" "$1"; } | |
| warn() { printf '%b[warn]%b %s\n' "$YELLOW" "$NC" "$1"; } | |
| show_help() { | |
| cat <<EOF | |
| Usage: $(basename "$0") [OPTIONS] | |
| Generate system inventory snapshots in YAML format. | |
| Options: | |
| --brew Homebrew packages only (includes taps) | |
| --npm npm global packages only | |
| --mas Mac App Store apps only | |
| --apps /Applications listing only | |
| --python Python packages only | |
| --claude Claude Code plugins only | |
| --bun bun global packages only | |
| --uv uv global tools only | |
| --all All inventories (default) | |
| --restore Show restore commands for a hostname | |
| --markdown Generate a Markdown catalog with descriptions | |
| --help Show this help | |
| Output: | |
| Files saved to: data/$HOSTNAME/ | |
| Examples: | |
| $(basename "$0") # Full inventory | |
| $(basename "$0") --brew --npm # Specific inventories | |
| $(basename "$0") --markdown # Generate Markdown catalog | |
| $(basename "$0") --restore macbook # Show restore commands | |
| EOF | |
| } | |
| # ----------------------------------------------------------------------------- | |
| # YAML Helper | |
| # ----------------------------------------------------------------------------- | |
| yaml_header() { | |
| local name="$1" | |
| echo "# $name inventory for $HOSTNAME" | |
| echo "" | |
| } | |
| yaml_list() { | |
| local indent="${1:-2}" | |
| local prefix="" | |
| for ((i = 0; i < indent; i++)); do prefix+=" "; done | |
| while IFS= read -r line; do | |
| [[ -n "$line" ]] && echo "${prefix}- \"$line\"" | |
| done | |
| } | |
| # ----------------------------------------------------------------------------- | |
| # Inventory Functions | |
| # ----------------------------------------------------------------------------- | |
| inventory_brew() { | |
| if ! command -v brew >/dev/null 2>&1; then | |
| warn "Homebrew not installed" | |
| return 1 | |
| fi | |
| # Brewfile (canonical format for full restore) | |
| brew bundle dump --file="$DATA_DIR/Brewfile" --force 2>/dev/null | |
| # Cache cask list (called once instead of 4+ times) | |
| local all_casks | |
| all_casks=$(brew list --cask 2>/dev/null) | |
| # Taps | |
| { | |
| yaml_header "Homebrew taps" | |
| echo "brew:" | |
| echo " taps:" | |
| brew tap | sort | yaml_list 4 | |
| } >"$DATA_DIR/brew-taps.yaml" | |
| # Leaves (explicitly installed formulae, no dependencies) | |
| { | |
| yaml_header "Homebrew leaves" | |
| echo "brew:" | |
| echo " leaves:" | |
| brew leaves | sort | yaml_list 4 | |
| } >"$DATA_DIR/brew-leaves.yaml" | |
| # Casks (apps, excluding fonts) | |
| { | |
| yaml_header "Homebrew casks" | |
| echo "brew:" | |
| echo " casks:" | |
| echo "$all_casks" | grep -v "^font-" | sort | yaml_list 4 | |
| } >"$DATA_DIR/brew-casks.yaml" | |
| # Fonts | |
| { | |
| yaml_header "Homebrew fonts" | |
| echo "brew:" | |
| echo " fonts:" | |
| echo "$all_casks" | grep "^font-" | sort | yaml_list 4 | |
| } >"$DATA_DIR/brew-fonts.yaml" | |
| local taps leaves casks fonts | |
| taps=$(brew tap | wc -l | xargs) | |
| leaves=$(brew leaves | wc -l | xargs) | |
| casks=$(echo "$all_casks" | grep -cv "^font-" || true) | |
| fonts=$(echo "$all_casks" | grep -c "^font-" || true) | |
| success "Homebrew: $taps taps, $leaves leaves, $casks casks, $fonts fonts" | |
| } | |
| inventory_npm() { | |
| if ! command -v npm >/dev/null 2>&1; then | |
| warn "npm not installed" | |
| return 1 | |
| fi | |
| { | |
| yaml_header "npm global packages" | |
| echo "npm:" | |
| echo " global:" | |
| npm ls -g --depth=0 --json 2>/dev/null | | |
| jq -r '.dependencies | keys[]' 2>/dev/null | | |
| sort | yaml_list 4 | |
| } >"$DATA_DIR/npm.yaml" | |
| local count | |
| count=$(npm ls -g --depth=0 --json 2>/dev/null | jq '.dependencies | length' 2>/dev/null || echo 0) | |
| success "npm: $count global packages" | |
| } | |
| inventory_mas() { | |
| if ! command -v mas >/dev/null 2>&1; then | |
| warn "mas not installed (brew install mas)" | |
| return 1 | |
| fi | |
| { | |
| yaml_header "Mac App Store" | |
| echo "mas:" | |
| echo " apps:" | |
| mas list | sort -t' ' -k2 | while IFS= read -r line; do | |
| local id name version | |
| id=$(echo "$line" | awk '{print $1}') | |
| name=$(echo "$line" | sed -E 's/^[0-9]+ (.*) \([^)]+\)$/\1/') | |
| version=$(echo "$line" | grep -oE '\([^)]+\)$' | tr -d '()') | |
| echo " - id: $id" | |
| echo " name: \"$name\"" | |
| echo " version: \"$version\"" | |
| done | |
| } >"$DATA_DIR/mas.yaml" | |
| local count | |
| count=$(mas list | wc -l | xargs) | |
| success "Mac App Store: $count apps" | |
| } | |
| inventory_apps() { | |
| if [[ ! -d "/Applications" ]]; then | |
| warn "/Applications not found" | |
| return 1 | |
| fi | |
| { | |
| yaml_header "Applications" | |
| echo "applications:" | |
| find /Applications -maxdepth 1 -name "*.app" -type d -print0 2>/dev/null | | |
| xargs -0 -I {} basename {} .app | | |
| sort | yaml_list 2 | |
| } >"$DATA_DIR/applications.yaml" | |
| local count | |
| count=$(find /Applications -maxdepth 1 -name "*.app" -type d 2>/dev/null | wc -l | xargs) | |
| success "Applications: $count apps" | |
| } | |
| inventory_python() { | |
| if ! command -v pip3 >/dev/null 2>&1; then | |
| warn "pip3 not installed" | |
| return 1 | |
| fi | |
| { | |
| yaml_header "Python packages" | |
| echo "python:" | |
| echo " version: \"$(python3 --version 2>&1 | awk '{print $2}')\"" | |
| echo " packages:" | |
| pip3 list --format=freeze 2>/dev/null | sort | yaml_list 4 | |
| } >"$DATA_DIR/python.yaml" | |
| local count | |
| count=$(pip3 list --format=freeze 2>/dev/null | wc -l | xargs) | |
| success "Python: $count packages" | |
| } | |
| inventory_uv() { | |
| if ! command -v uv >/dev/null 2>&1; then | |
| warn "uv not installed" | |
| return 1 | |
| fi | |
| { | |
| yaml_header "uv tools" | |
| echo "uv:" | |
| echo " version: \"$(uv --version 2>/dev/null | awk '{print $2}')\"" | |
| echo " tools:" | |
| uv tool list 2>/dev/null | grep -v '^-' | awk '{print $1}' | sort | yaml_list 4 | |
| } >"$DATA_DIR/uv.yaml" | |
| local count | |
| count=$(uv tool list 2>/dev/null | grep -cv '^-' || true) | |
| success "uv: $count tools" | |
| } | |
| inventory_claude() { | |
| local plugins_file="$HOME/.claude/plugins/installed_plugins.json" | |
| local marketplaces_file="$HOME/.claude/plugins/known_marketplaces.json" | |
| if [[ ! -f "$plugins_file" ]]; then | |
| warn "Claude Code plugins not found" | |
| return 1 | |
| fi | |
| { | |
| yaml_header "Claude Code" | |
| echo "claude:" | |
| # Marketplaces (excluding official) | |
| echo " marketplaces:" | |
| if [[ -f "$marketplaces_file" ]]; then | |
| jq -r 'to_entries[] | select(.key != "claude-plugins-official") | " - name: \"\(.key)\"\n repo: \"\(.value.source.repo)\""' "$marketplaces_file" 2>/dev/null | |
| fi | |
| # Plugins | |
| echo " plugins:" | |
| jq -r '.plugins | to_entries[] | .key as $id | .value[0] | " - id: \"\($id)\"\n version: \"\(.version)\""' "$plugins_file" 2>/dev/null | |
| } >"$DATA_DIR/claude.yaml" | |
| local count | |
| count=$(jq '.plugins | length' "$plugins_file" 2>/dev/null || echo 0) | |
| success "Claude Code: $count plugins" | |
| } | |
| inventory_bun() { | |
| if ! command -v bun >/dev/null 2>&1; then | |
| warn "bun not installed" | |
| return 1 | |
| fi | |
| local bun_global="$HOME/.bun/install/global/node_modules" | |
| { | |
| yaml_header "bun global packages" | |
| echo "bun:" | |
| echo " version: \"$(bun --version 2>/dev/null)\"" | |
| echo " global:" | |
| if [[ -d "$bun_global" ]]; then | |
| for pkg_dir in "$bun_global"/*/; do | |
| [[ -d "$pkg_dir" ]] || continue | |
| local pkg ver | |
| pkg=$(basename "$pkg_dir") | |
| [[ "$pkg" == .* ]] && continue | |
| ver=$(jq -r '.version // "unknown"' "$pkg_dir/package.json" 2>/dev/null) | |
| echo " - \"${pkg}@${ver}\"" | |
| done | |
| fi | |
| } >"$DATA_DIR/bun.yaml" | |
| local count=0 | |
| if [[ -d "$bun_global" ]]; then | |
| for pkg_dir in "$bun_global"/*/; do | |
| [[ -d "$pkg_dir" ]] || continue | |
| local pkg | |
| pkg=$(basename "$pkg_dir") | |
| [[ "$pkg" == .* ]] && continue | |
| ((count++)) | |
| done | |
| fi | |
| success "bun: $count global packages" | |
| } | |
| # ----------------------------------------------------------------------------- | |
| # Markdown Catalog | |
| # ----------------------------------------------------------------------------- | |
| generate_markdown() { | |
| local outfile="$DATA_DIR/catalog.md" | |
| info "Generating Markdown catalog..." | |
| { | |
| echo "# Software Catalog — $HOSTNAME" | |
| echo "" | |
| # --- Homebrew Formulae (leaves only) --- | |
| if command -v brew >/dev/null 2>&1; then | |
| local -a leaves | |
| mapfile -t leaves < <(brew leaves | sort) | |
| if [[ ${#leaves[@]} -gt 0 ]]; then | |
| echo "## Homebrew Formulae" | |
| echo "" | |
| echo "| Package | Description |" | |
| echo "|---------|-------------|" | |
| brew desc --eval-all "${leaves[@]}" 2>/dev/null | sort | while IFS=: read -r name desc; do | |
| desc="${desc# }" | |
| echo "| \`$name\` | $desc |" | |
| done | |
| echo "" | |
| fi | |
| # --- Homebrew Casks (excluding fonts) --- | |
| local -a casks | |
| mapfile -t casks < <(brew list --cask | grep -v "^font-" | sort) | |
| if [[ ${#casks[@]} -gt 0 ]]; then | |
| echo "## Homebrew Casks" | |
| echo "" | |
| echo "| App | Description |" | |
| echo "|-----|-------------|" | |
| brew desc --eval-all "${casks[@]}" 2>/dev/null | sort | while IFS=: read -r name desc; do | |
| desc="${desc# }" | |
| # Strip the "(Display Name) " prefix that casks include | |
| desc=$(echo "$desc" | sed -E 's/^\([^)]+\) //') | |
| echo "| \`$name\` | $desc |" | |
| done | |
| echo "" | |
| fi | |
| # --- Homebrew Fonts --- | |
| local -a fonts | |
| mapfile -t fonts < <(brew list --cask | grep "^font-" | sort) | |
| if [[ ${#fonts[@]} -gt 0 ]]; then | |
| echo "## Homebrew Fonts" | |
| echo "" | |
| echo "| Font | Description |" | |
| echo "|------|-------------|" | |
| brew desc --eval-all "${fonts[@]}" 2>/dev/null | sort | while IFS=: read -r name desc; do | |
| desc="${desc# }" | |
| # Strip cask display name prefix: "(Name (Details)) desc" or "(Name) desc" | |
| desc=$(echo "$desc" | sed -E 's/^\(.*\) *//') | |
| [[ "$desc" == "[no description]" || -z "$desc" ]] && desc="—" | |
| echo "| \`$name\` | $desc |" | |
| done | |
| echo "" | |
| fi | |
| fi | |
| # --- npm global --- | |
| if command -v npm >/dev/null 2>&1; then | |
| local -a npm_pkgs | |
| mapfile -t npm_pkgs < <(npm ls -g --depth=0 --json 2>/dev/null | jq -r '.dependencies | keys[]' 2>/dev/null | sort) | |
| if [[ ${#npm_pkgs[@]} -gt 0 ]]; then | |
| echo "## npm Global Packages" | |
| echo "" | |
| echo "| Package | Description |" | |
| echo "|---------|-------------|" | |
| local npm_root | |
| npm_root=$(npm root -g 2>/dev/null) | |
| for pkg in "${npm_pkgs[@]}"; do | |
| local desc | |
| desc=$(jq -r '.description // "—"' "$npm_root/$pkg/package.json" 2>/dev/null) | |
| echo "| \`$pkg\` | $desc |" | |
| done | |
| echo "" | |
| fi | |
| fi | |
| # --- bun global --- | |
| if command -v bun >/dev/null 2>&1; then | |
| local bun_global="$HOME/.bun/install/global/node_modules" | |
| if [[ -d "$bun_global" ]]; then | |
| local -a bun_pkgs=() | |
| for pkg_dir in "$bun_global"/*/; do | |
| [[ -d "$pkg_dir" ]] || continue | |
| local pkg | |
| pkg=$(basename "$pkg_dir") | |
| [[ "$pkg" == .* ]] && continue | |
| bun_pkgs+=("$pkg") | |
| done | |
| if [[ ${#bun_pkgs[@]} -gt 0 ]]; then | |
| echo "## bun Global Packages" | |
| echo "" | |
| echo "| Package | Description |" | |
| echo "|---------|-------------|" | |
| for pkg in "${bun_pkgs[@]}"; do | |
| local desc | |
| desc=$(jq -r '.description // "—"' "$bun_global/$pkg/package.json" 2>/dev/null) | |
| echo "| \`$pkg\` | $desc |" | |
| done | |
| echo "" | |
| fi | |
| fi | |
| fi | |
| # --- Mac App Store --- | |
| if command -v mas >/dev/null 2>&1; then | |
| local mas_apps | |
| mas_apps=$(mas list 2>/dev/null | sort -t' ' -k2) | |
| if [[ -n "$mas_apps" ]]; then | |
| echo "## Mac App Store" | |
| echo "" | |
| echo "| App | Version |" | |
| echo "|-----|---------|" | |
| while IFS= read -r line; do | |
| local name version | |
| # Format: " 497799835 Xcode (26.4)" | |
| name=$(echo "$line" | sed -E 's/^[[:space:]]*[0-9]+[[:space:]]+(.*)[[:space:]]+\([^)]+\)$/\1/' | sed 's/[[:space:]]*$//') | |
| version=$(echo "$line" | grep -oE '\([^)]+\)$' | tr -d '()') | |
| echo "| \`$name\` | $version |" | |
| done <<< "$mas_apps" | |
| echo "" | |
| fi | |
| fi | |
| # --- uv tools --- | |
| if command -v uv >/dev/null 2>&1; then | |
| local -a uv_tools | |
| # uv tool list outputs "name vX.Y.Z" lines and "- command" lines; keep only tool names | |
| mapfile -t uv_tools < <(uv tool list 2>/dev/null | grep -v '^-' | awk '{print $1}' | sort) | |
| if [[ ${#uv_tools[@]} -gt 0 ]]; then | |
| echo "## uv Tools" | |
| echo "" | |
| echo "| Tool |" | |
| echo "|------|" | |
| for tool in "${uv_tools[@]}"; do | |
| echo "| \`$tool\` |" | |
| done | |
| echo "" | |
| fi | |
| fi | |
| # --- Applications --- | |
| if [[ -d "/Applications" ]]; then | |
| echo "## Applications" | |
| echo "" | |
| echo "| App |" | |
| echo "|-----|" | |
| find /Applications -maxdepth 1 -name "*.app" -type d -print0 2>/dev/null | | |
| xargs -0 -I {} basename {} .app | | |
| sort | while IFS= read -r app; do | |
| echo "| \`$app\` |" | |
| done | |
| echo "" | |
| fi | |
| } > "$outfile" | |
| success "Markdown catalog: $outfile" | |
| } | |
| # ----------------------------------------------------------------------------- | |
| # Restore Commands | |
| # ----------------------------------------------------------------------------- | |
| show_restore() { | |
| local target_host="$1" | |
| local target_dir="$BASE_DIR/data/$target_host" | |
| if [[ ! -d "$target_dir" ]]; then | |
| warn "No inventory found for: $target_host" | |
| echo "" | |
| echo "Available inventories:" | |
| for dir in "$BASE_DIR/data"/*/; do | |
| [[ -d "$dir" ]] && echo " - $(basename "$dir")" | |
| done | |
| exit 1 | |
| fi | |
| echo "" | |
| echo "Restore commands for: $target_host" | |
| echo "==================================" | |
| echo "" | |
| # Homebrew (full) | |
| if [[ -f "$target_dir/Brewfile" ]]; then | |
| echo "# Homebrew (full restore - all packages):" | |
| echo "brew bundle --file=$target_dir/Brewfile" | |
| echo "" | |
| fi | |
| # Homebrew taps | |
| if [[ -f "$target_dir/brew-taps.yaml" ]]; then | |
| echo "# Homebrew taps:" | |
| echo "yq '.brew.taps[]' $target_dir/brew-taps.yaml | xargs -I {} brew tap {}" | |
| echo "" | |
| fi | |
| # Homebrew leaves only | |
| if [[ -f "$target_dir/brew-leaves.yaml" ]]; then | |
| echo "# Homebrew leaves (formulae only, no deps):" | |
| echo "yq '.brew.leaves[]' $target_dir/brew-leaves.yaml | xargs brew install" | |
| echo "" | |
| fi | |
| # Homebrew casks | |
| if [[ -f "$target_dir/brew-casks.yaml" ]]; then | |
| echo "# Homebrew casks (apps):" | |
| echo "yq '.brew.casks[]' $target_dir/brew-casks.yaml | xargs brew install --cask" | |
| echo "" | |
| fi | |
| # Homebrew fonts | |
| if [[ -f "$target_dir/brew-fonts.yaml" ]]; then | |
| echo "# Homebrew fonts:" | |
| echo "yq '.brew.fonts[]' $target_dir/brew-fonts.yaml | xargs brew install --cask" | |
| echo "" | |
| fi | |
| # npm | |
| if [[ -f "$target_dir/npm.yaml" ]]; then | |
| echo "# npm global packages:" | |
| echo "yq '.npm.global[]' $target_dir/npm.yaml | xargs npm install -g" | |
| echo "" | |
| fi | |
| # Mac App Store | |
| if [[ -f "$target_dir/mas.yaml" ]]; then | |
| echo "# Mac App Store apps:" | |
| echo "yq '.mas.apps[].id' $target_dir/mas.yaml | xargs mas install" | |
| echo "" | |
| fi | |
| # Python | |
| if [[ -f "$target_dir/python.yaml" ]]; then | |
| echo "# Python packages:" | |
| echo "yq '.python.packages[]' $target_dir/python.yaml | xargs pip3 install" | |
| echo "" | |
| fi | |
| # Claude Code | |
| if [[ -f "$target_dir/claude.yaml" ]]; then | |
| echo "# Claude Code marketplaces:" | |
| echo "yq '.claude.marketplaces[].repo' $target_dir/claude.yaml | xargs -I {} claude /plugin marketplace add {}" | |
| echo "" | |
| echo "# Claude Code plugins:" | |
| echo "yq '.claude.plugins[].id' $target_dir/claude.yaml | sed 's/@.*//' | xargs -I {} claude /plugin install {}" | |
| echo "" | |
| fi | |
| # bun | |
| if [[ -f "$target_dir/bun.yaml" ]]; then | |
| echo "# bun global packages:" | |
| echo "yq '.bun.global[]' $target_dir/bun.yaml | sed 's/@[^@]*$//' | xargs -I {} bun install -g {}" | |
| echo "" | |
| fi | |
| # uv | |
| if [[ -f "$target_dir/uv.yaml" ]]; then | |
| echo "# uv global tools:" | |
| echo "yq '.uv.tools[]' $target_dir/uv.yaml | xargs -I {} uv tool install {}" | |
| echo "" | |
| fi | |
| } | |
| # ----------------------------------------------------------------------------- | |
| # Main | |
| # ----------------------------------------------------------------------------- | |
| main() { | |
| local run_all=true | |
| local run_brew=false | |
| local run_npm=false | |
| local run_mas=false | |
| local run_apps=false | |
| local run_python=false | |
| local run_claude=false | |
| local run_bun=false | |
| local run_uv=false | |
| local run_markdown=false | |
| local restore_host="" | |
| # Parse arguments | |
| while [[ $# -gt 0 ]]; do | |
| case "$1" in | |
| --brew) | |
| run_all=false | |
| run_brew=true | |
| ;; | |
| --npm) | |
| run_all=false | |
| run_npm=true | |
| ;; | |
| --mas) | |
| run_all=false | |
| run_mas=true | |
| ;; | |
| --apps) | |
| run_all=false | |
| run_apps=true | |
| ;; | |
| --python) | |
| run_all=false | |
| run_python=true | |
| ;; | |
| --claude) | |
| run_all=false | |
| run_claude=true | |
| ;; | |
| --uv) | |
| run_all=false | |
| run_uv=true | |
| ;; | |
| --bun) | |
| run_all=false | |
| run_bun=true | |
| ;; | |
| --restore) | |
| shift | |
| restore_host="${1:-}" | |
| if [[ -z "$restore_host" ]]; then | |
| warn "--restore requires a hostname" | |
| exit 1 | |
| fi | |
| ;; | |
| --markdown) | |
| run_markdown=true | |
| ;; | |
| --all) run_all=true ;; | |
| --help) | |
| show_help | |
| exit 0 | |
| ;; | |
| *) | |
| warn "Unknown option: $1" | |
| show_help | |
| exit 1 | |
| ;; | |
| esac | |
| shift | |
| done | |
| # Handle restore mode | |
| if [[ -n "$restore_host" ]]; then | |
| if ! $run_all; then | |
| warn "Inventory flags ignored when using --restore" | |
| fi | |
| show_restore "$restore_host" | |
| exit 0 | |
| fi | |
| # Handle markdown mode | |
| if $run_markdown; then | |
| if ! $run_all; then | |
| warn "Inventory flags ignored when using --markdown" | |
| fi | |
| mkdir -p "$DATA_DIR" | |
| generate_markdown | |
| exit 0 | |
| fi | |
| echo "" | |
| echo "System Inventory: $HOSTNAME" | |
| echo "=========================" | |
| echo "" | |
| # Create data directory | |
| mkdir -p "$DATA_DIR" | |
| # Run inventories | |
| if $run_all || $run_brew; then inventory_brew || true; fi | |
| if $run_all || $run_npm; then inventory_npm || true; fi | |
| if $run_all || $run_mas; then inventory_mas || true; fi | |
| if $run_all || $run_apps; then inventory_apps || true; fi | |
| if $run_all || $run_python; then inventory_python || true; fi | |
| if $run_all || $run_claude; then inventory_claude || true; fi | |
| if $run_all || $run_bun; then inventory_bun || true; fi | |
| if $run_all || $run_uv; then inventory_uv || true; fi | |
| echo "" | |
| info "Saved to: $DATA_DIR" | |
| echo "" | |
| echo "Next: git add data/ && git commit -m 'Update $HOSTNAME inventory'" | |
| echo "" | |
| } | |
| main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment