diff --git a/README.md b/README.md index 332cb9a..bc1a415 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,14 @@ # System Scripts -A collection of system administration and development workflow scripts for macOS/Linux environments. +A collection of system administration and development workflow scripts for +macOS/Linux environments. ## 📁 Project Structure ```text system-scripts/ ├── code-backup/ # Repository backup and management +├── git-scripts/ # Git repository utilities ├── tmux/ # Enhanced tmux session management └── README.md # This file ``` @@ -30,6 +32,19 @@ Comprehensive repository backup and management system with: - ✅ Error handling and recovery - ✅ Progress indicators and reporting +### 🔧 Git Utilities (`git-scripts/`) + +Utilities for managing multiple git repositories: + +- `sync-all.sh` - Find all git repos in a path and update their default branch + +**Key Features:** + +- ✅ **Automatic Detection**: Identifies default branch (main/master/HEAD) +- ✅ **Safe Updates**: Skips repositories with uncommitted changes +- ✅ **Recursive Discovery**: Finds all git repos within a given path +- ✅ **Clean Fetch**: Prunes deleted remote branches during fetch + ### 🖥️ Tmux Session Management (`tmux/`) Enhanced tmux session management following bash and tmux best practices: @@ -52,21 +67,7 @@ Enhanced tmux session management following bash and tmux best practices: ## 🚀 Quick Start -### Tmux Sessions - -```bash -# Start main session (general purpose) -./tmux/setup-main.sh - -# Start development session -./tmux/setup-dev.sh - -# Use comprehensive manager -./tmux/session-manager.sh main -./tmux/session-manager.sh dev -``` - -### Code Backup +### Customizing Code Backup ```bash # Run backup for all repositories @@ -112,9 +113,7 @@ All scripts include comprehensive logging: - Colored output for better visibility - Timestamped entries with context -## 🔧 Customization - -### Tmux Sessions +### Customizing Tmux Sessions - Modify window layouts in the respective setup scripts - Add custom commands and working directories diff --git a/code-backup/README.md b/code-backup/README.md index ffe1513..650f689 100644 --- a/code-backup/README.md +++ b/code-backup/README.md @@ -2,8 +2,10 @@ This directory contains two scripts for backing up your GitHub repositories: -1. **`code-backup-local.sh`** - Creates a local, zipped directory of all your non-archived projects -2. **`code-backup-gitlab.sh`** - Mirrors all non-archived public and private projects to similarly named GitLab projects +1. **`code-backup-local.sh`** - Creates a local, zipped directory of all your + non-archived projects +2. **`code-backup-gitlab.sh`** - Mirrors all non-archived public and private + projects to similarly named GitLab projects --- @@ -94,19 +96,14 @@ chmod +x code-backup-local.sh --- -## 📦 Script 2: GitLab Mirror (`code-backup-gitlab.sh`) - -Mirrors all non-archived public and private GitHub repositories to similarly named GitLab projects. - -### Features +### GitLab Mirror Features - Lists all non-archived GitHub repos you can access - Creates/updates a local mirror clone (bare repo) for each - Ensures a same-named GitLab project exists under your namespace - Pushes a full mirror to GitLab (all branches, tags, and refs) -- Automatically creates GitLab projects if they don't exist (optional) -### 🔐 Authentication +### 🔐 GitLab Authentication **Required environment variables:** @@ -121,19 +118,17 @@ export GITLAB_NAMESPACE="your-username" # Your GitLab username or group export GITHUB_TOKEN="your_github_token" # For private GitHub repos export GITHUB_USERNAME="your-username" # Auto-detected if token provided export USE_GITHUB_SSH="true" # Use SSH for GitHub (default: false) -export AUTO_CREATE_GITLAB_PROJECTS="true" # Auto-create missing projects (default: true) -export GITLAB_VISIBILITY="private" # Visibility for new projects: private/internal/public (default: private) -export GITLAB_HOST="https://gitlab.com" # GitLab instance URL (default: gitlab.com) -export BACKUP_ROOT="$HOME/GitHub-GitLab-Backup" # Where to store local mirrors +export AUTO_CREATE_GITLAB_PROJECTS="true" # Auto-create missing +projects (default: true) +export GITLAB_VISIBILITY="private" # Visibility for new +projects: private/internal/public (default: private) +export GITLAB_HOST="https://gitlab.com" # GitLab instance URL +(default: gitlab.com) +export BACKUP_ROOT="$HOME/GitHub-GitLab-Backup" # Where to store local +mirrors ``` -### Creating GitLab Token - -1. Go to GitLab.com → Settings → Access Tokens -2. Create a token with `api` scope (and `write_repository` if needed) -3. Set it as `GITLAB_TOKEN` environment variable - -### Usage +### GitLab Usage ```bash chmod +x code-backup-gitlab.sh @@ -155,9 +150,8 @@ export GITHUB_TOKEN="your_github_token" - Creates/updates a local bare mirror clone - Checks if a GitLab project exists (creates it if `AUTO_CREATE_GITLAB_PROJECTS=true`) - Pushes all branches, tags, and refs to GitLab as a mirror -3. Assumes GitHub and GitLab usernames are the same, and projects have the same name -### Output +### GitLab Output - **Local mirrors**: `$BACKUP_ROOT/mirrors-YYYYMMDD-HHMMSS/` (bare repos) - **Logs**: `logs/gh-gl-backup-YYYYMMDD-HHMMSS.log` @@ -249,7 +243,8 @@ crontab -e 0 3 * * 0 /path/to/code-backup-gitlab.sh ``` -**Note:** When using cron, make sure to set environment variables in your crontab or in a script that sources them: +**Note:** When using cron, make sure to set environment variables in your +crontab or in a script that sources them: ```bash # In crontab @@ -262,12 +257,14 @@ crontab -e ### Repository Filtering -Both scripts only process **non-archived** repositories. Archived repositories are automatically excluded. +Both scripts only process **non-archived** repositories. Archived +repositories are automatically excluded. ### Private Repositories - **Local backup**: Requires `GITHUB_TOKEN` to access private repos -- **GitLab mirror**: Requires both `GITHUB_TOKEN` (for GitHub) and `GITLAB_TOKEN` (for GitLab) +- **GitLab mirror**: Requires both `GITHUB_TOKEN` (for GitHub) and + `GITLAB_TOKEN` (for GitLab) ### SSH vs HTTPS @@ -278,10 +275,12 @@ Both scripts support both SSH and HTTPS for GitHub operations: ### GitLab Project Creation -The GitLab mirror script can automatically create GitLab projects if they don't exist: +The GitLab mirror script can automatically create GitLab projects if they +don't exist: - Set `AUTO_CREATE_GITLAB_PROJECTS="true"` (default) -- New projects will be created with visibility set by `GITLAB_VISIBILITY` (default: `private`) +- New projects will be created with visibility set by + `GITLAB_VISIBILITY` (default: `private`) ### Submodules diff --git a/code-backup/code-backup-gitlab.sh b/code-backup/code-backup-gitlab.sh index 74470c5..a50de4e 100644 --- a/code-backup/code-backup-gitlab.sh +++ b/code-backup/code-backup-gitlab.sh @@ -10,11 +10,13 @@ set -euo pipefail # ---------------------------- # Configuration # ---------------------------- -readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +readonly SCRIPT_DIR +SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) readonly LOG_DIR="$SCRIPT_DIR/logs" mkdir -p "$LOG_DIR" -readonly RUN_TS="$(date +%Y%m%d-%H%M%S)" +readonly RUN_TS +RUN_TS=$( date +%Y%m%d-%H%M%S ) readonly LOG_FILE="$LOG_DIR/gh-gl-backup-$RUN_TS.log" readonly ERROR_LOG="$LOG_DIR/gh-gl-errors-$RUN_TS.log" @@ -277,7 +279,7 @@ process_repo() { local effective_clone_url="$clone_url" if [ "$USE_GITHUB_SSH" != "true" ] && [ -n "${GITHUB_TOKEN:-}" ]; then # GitHub supports token auth via x-access-token username. - effective_clone_url="$(echo "$clone_url" | sed "s#https://#https://x-access-token:${GITHUB_TOKEN}@#")" + effective_clone_url="${clone_url//https:\/\//https:\/\/x-access-token:${GITHUB_TOKEN}@\/}" fi # Clone/update local mirror diff --git a/code-backup/code-backup-local.sh b/code-backup/code-backup-local.sh index 0ee96e8..aed0fa4 100755 --- a/code-backup/code-backup-local.sh +++ b/code-backup/code-backup-local.sh @@ -7,9 +7,11 @@ set -euo pipefail # Configuration -readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +readonly SCRIPT_DIR +SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) readonly LOG_DIR="$SCRIPT_DIR/logs" -readonly RUN_TS="$(date +%Y%m%d-%H%M%S)" +readonly RUN_TS +RUN_TS=$(date +%Y%m%d-%H%M%S) readonly LOG_FILE="$LOG_DIR/code-backup-$RUN_TS.log" readonly ERROR_LOG="$LOG_DIR/errors-$RUN_TS.log" @@ -23,7 +25,8 @@ GITHUB_USERNAME="${GITHUB_USERNAME:-}" USE_GITHUB_SSH="${USE_GITHUB_SSH:-false}" # Backup directory will be created with date format -readonly BACKUP_DATE=$(date +%m-%d-%y) +readonly BACKUP_DATE +BACKUP_DATE=$(date +%m-%d-%y) readonly BACKUP_DIR_NAME="Code-Backup_${BACKUP_DATE}" readonly BACKUP_DIR="$HOME/$BACKUP_DIR_NAME" readonly PROJECTS_DIR="$BACKUP_DIR" @@ -36,7 +39,6 @@ readonly BLUE='\033[0;34m' readonly NC='\033[0m' # No Color # Global variables -TOTAL_REPOS=0 SUCCESSFUL_REPOS=0 FAILED_REPOS=0 @@ -45,7 +47,8 @@ log() { local level="$1" shift local message="$*" - local timestamp=$(date '+%Y-%m-%d %H:%M:%S') + local timestamp + timestamp=$(date '+%Y-%m-%d %H:%M:%S') echo -e "${timestamp} [${level}] ${message}" | tee -a "$LOG_FILE" } @@ -62,7 +65,8 @@ log_warning() { } log_error() { - local timestamp=$(date '+%Y-%m-%d %H:%M:%S') + local timestamp + timestamp=$(date '+%Y-%m-%d %H:%M:%S') log "ERROR" "${RED}$*${NC}" echo -e "${timestamp} [ERROR] $*" >> "$ERROR_LOG" } @@ -76,7 +80,6 @@ error_exit() { # Cleanup function cleanup() { log_info "Cleaning up temporary files..." - # Add any cleanup logic here if needed } # Set up trap for cleanup on exit @@ -139,13 +142,11 @@ get_github_username() { # Create necessary directories setup_directories() { - # Create log directory first (needed for logging) mkdir -p "$LOG_DIR" || { echo "Error: Failed to create log directory: $LOG_DIR" >&2 exit 1 } - # Create Projects directory if [ ! -d "$PROJECTS_DIR" ]; then log_info "Creating Projects directory: $PROJECTS_DIR" mkdir -p "$PROJECTS_DIR" || { @@ -158,39 +159,30 @@ setup_directories() { } # Get all GitHub repositories (non-archived only) -# Returns lines: "" get_github_repos() { log_info "Fetching GitHub repos (excluding archived) for: $GITHUB_USERNAME" local page=1 local per_page=100 - # Check for GitHub token for private repos - if [ -n "${GITHUB_TOKEN:-}" ]; then - log_info "Using GitHub token for authentication" >&2 - fi - while true; do local url local resp if [ -n "${GITHUB_TOKEN:-}" ]; then - # Authenticated: includes private repos you can access url="https://api.github.com/user/repos?page=$page&per_page=$per_page&type=all&sort=updated" resp="$(curl -sS -H "Authorization: token $GITHUB_TOKEN" "$url" 2>>"$ERROR_LOG" || true)" else - # Unauthenticated: only public repos url="https://api.github.com/users/$GITHUB_USERNAME/repos?page=$page&per_page=$per_page&type=all&sort=updated" resp="$(curl -sS "$url" 2>>"$ERROR_LOG" || true)" fi - # Error? if echo "$resp" | jq -e '.message? // empty' >/dev/null 2>&1; then - local msg; msg="$(echo "$resp" | jq -r '.message' 2>>"$ERROR_LOG" || echo "unknown")" + local msg + msg="$(echo "$resp" | jq -r '.message' 2>>"$ERROR_LOG" || echo "unknown")" error_exit "GitHub API error: $msg" fi - # Choose clone URL style local jq_clone_field if [ "$USE_GITHUB_SSH" = "true" ]; then jq_clone_field='.ssh_url' @@ -198,17 +190,11 @@ get_github_repos() { jq_clone_field='.clone_url' fi - # Emit clone URLs, excluding archived local lines - lines="$(echo "$resp" | jq -r --argjson _ 0 \ - ".[] | select(.archived == false) | ${jq_clone_field}" 2>>"$ERROR_LOG" || true)" + lines="$(echo "$resp" | jq -r --argjson _ 0 ".[] | select(.archived == false) | ${jq_clone_field}" 2>>"$ERROR_LOG" || true)" [ -n "$lines" ] || break - # Print for caller - echo "$lines" - - # Last page? local count count="$(echo "$lines" | wc -l | tr -d ' ')" if [ "$count" -lt "$per_page" ]; then @@ -219,54 +205,50 @@ get_github_repos() { done } -# Get default branch for a repository -get_default_branch() { - local repo_url="$1" +# Update an existing repository using the shared sync script +update_repository() { + local repo_path="$1" local repo_name="$2" - - # Try to get default branch from remote - local default_branch - if default_branch=$(git remote show origin 2>/dev/null | awk '/HEAD branch/ {print $NF}' 2>/dev/null); then - if [ -n "$default_branch" ]; then - echo "$default_branch" + local sync_script + sync_script="$(dirname "$SCRIPT_DIR")/git-scripts/sync-all.sh" + + if [[ -f "$sync_script" ]]; then + # shellcheck disable=SC1090,SC1091 + source "$sync_script" + + local sync_output + sync_output=$(sync_repo "$repo_path" 2>&1 || true) + + echo "$sync_output" | while IFS= read -r line; do + if [[ "$line" =~ ^---[[:space:]]Processing:.* ]]; then + log_info "$(echo "$line" | sed 's/--- Processing: //; s/ ---//')" + elif [[ "$line" =~ ^INFO:.* ]]; then + log_info "${line#INFO: }" + elif [[ "$line" =~ ^SUCCESS:.* ]]; then + log_success "${line#SUCCESS: }" + elif [[ "$line" =~ ^WARNING:.* ]]; then + log_warning "${line#WARNING: }" + elif [[ "$line" =~ ^ERROR:.* ]]; then + log_error "${line#ERROR: }" + else + log_info "$line" + fi + done + + if [[ "$sync_output" =~ "SUCCESS: Updated" ]]; then + ((SUCCESSFUL_REPOS++)) return 0 - fi - fi - - # Fallback: check common branch names - for branch in main master develop; do - if git show-ref --verify --quiet "refs/heads/$branch" 2>/dev/null; then - echo "$branch" + elif [[ "$sync_output" =~ "WARNING: Repository has uncommitted changes" ]]; then + log_warning "Repository was skipped due to uncommitted changes." return 0 + else + ((FAILED_REPOS++)) + return 1 fi - done - - # Last resort: use the first available branch - local first_branch - first_branch=$(git branch -r --format='%(refname:short)' | head -1 | sed 's/origin\///') - if [ -n "$first_branch" ]; then - echo "$first_branch" - return 0 - fi - - log_warning "Could not determine default branch for $repo_name" - return 1 -} - -# Clone or update repository -process_repository() { - local repo_url="$1" - local repo_name=$(basename "$repo_url" .git) - local repo_path="$PROJECTS_DIR/$repo_name" - - log_info "Processing repository: $repo_name" - - if [ -d "$repo_path" ]; then - log_info "Repository exists, updating: $repo_name" - update_repository "$repo_path" "$repo_name" else - log_info "Cloning new repository: $repo_name" - clone_repository "$repo_url" "$repo_path" "$repo_name" + log_error "Sync script not found at $sync_script" + ((FAILED_REPOS++)) + return 1 fi } @@ -275,24 +257,31 @@ clone_repository() { local repo_url="$1" local repo_path="$2" local repo_name="$3" - local original_dir=$(pwd) - - # If using HTTPS and token exists, inject it (so private clones work non-interactively) + local original_dir + original_dir=$(pwd) + local sync_script + sync_script="$(dirname "$SCRIPT_DIR")/git-scripts/sync-all.sh" + local effective_clone_url="$repo_url" if [ "$USE_GITHUB_SSH" != "true" ] && [ -n "${GITHUB_TOKEN:-}" ]; then - # GitHub supports token auth via x-access-token username. - effective_clone_url="$(echo "$repo_url" | sed "s#https://#https://x-access-token:${GITHUB_TOKEN}@#")" + effective_clone_url="${repo_url//https:\/\//https:\/\/x-access-token:${GITHUB_TOKEN}@\/}" fi if git clone "$effective_clone_url" "$repo_path" 2>>"$ERROR_LOG"; then log_success "Successfully cloned: $repo_name" ((SUCCESSFUL_REPOS++)) - # Checkout default branch if cd "$repo_path" 2>/dev/null; then - local default_branch - if default_branch=$(get_default_branch "$repo_url" "$repo_name" 2>/dev/null); then - git checkout "$default_branch" 2>>"$ERROR_LOG" || log_warning "Could not checkout $default_branch for $repo_name" + if [[ -f "$sync_script" ]]; then + # shellcheck disable=SC1090,SC1091 + source "$sync_script" + local default_branch + if default_branch=$(get_default_branch 2>/dev/null); then + log_info "Checking out default branch: $default_branch" + git checkout "$default_branch" 2>>"$ERROR_LOG" || log_warning "Could not checkout $default_branch for $repo_name" + else + log_warning "Could not determine default branch for $repo_name. Staying on current branch." + fi fi cd "$original_dir" 2>/dev/null || true fi @@ -302,60 +291,22 @@ clone_repository() { fi } -# Update an existing repository -update_repository() { - local repo_path="$1" - local repo_name="$2" - local original_dir=$(pwd) - - if ! cd "$repo_path" 2>/dev/null; then - log_error "Failed to change to repository directory: $repo_name" - ((FAILED_REPOS++)) - return 1 - fi - - # Fetch latest changes - if ! git fetch origin 2>>"$ERROR_LOG"; then - log_error "Failed to fetch updates for: $repo_name" - ((FAILED_REPOS++)) - cd "$original_dir" 2>/dev/null || true - return 1 - fi - - # Get current branch - local current_branch - current_branch=$(git branch --show-current 2>/dev/null || echo "") - - # Get default branch - local default_branch - if ! default_branch=$(get_default_branch "" "$repo_name" 2>/dev/null); then - log_warning "Could not determine default branch for $repo_name, skipping" - ((FAILED_REPOS++)) - cd "$original_dir" 2>/dev/null || true - return 1 - fi +# Process each repository +process_repository() { + local repo_url="$1" + local repo_name + repo_name=$(basename "$repo_url" .git) + local repo_path="$PROJECTS_DIR/$repo_name" - # Switch to default branch if not already on it - if [ "$current_branch" != "$default_branch" ]; then - log_info "Switching to default branch: $default_branch" - if ! git checkout "$default_branch" 2>>"$ERROR_LOG"; then - log_error "Failed to checkout $default_branch for $repo_name" - ((FAILED_REPOS++)) - cd "$original_dir" 2>/dev/null || true - return 1 - fi - fi + log_info "Processing repository: $repo_name" - # Pull latest changes - if git pull origin "$default_branch" 2>>"$ERROR_LOG"; then - log_success "Successfully updated: $repo_name" - ((SUCCESSFUL_REPOS++)) + if [ -d "$repo_path" ]; then + log_info "Repository exists, updating: $repo_name" + update_repository "$repo_path" "$repo_name" else - log_error "Failed to pull updates for: $repo_name" - ((FAILED_REPOS++)) + log_info "Cloning new repository: $repo_name" + clone_repository "$repo_url" "$repo_path" "$repo_name" fi - - cd "$original_dir" 2>/dev/null || true } # Create backup zip file @@ -365,17 +316,13 @@ create_backup() { local backup_name="${BACKUP_DIR_NAME}.zip" local backup_path="$HOME/$backup_name" - # Change to home directory to create zip - local original_dir=$(pwd) + local original_dir + original_dir=$(pwd) cd "$HOME" || error_exit "Failed to change to home directory" if zip -r "$backup_path" "$BACKUP_DIR_NAME" -x "*.git/*" "*.DS_Store" "*.log" 2>>"$ERROR_LOG"; then log_success "Backup created successfully: $backup_path" log_info "Backup size: $(du -h "$backup_path" | cut -f1)" - - # Optionally remove the directory after zipping (uncomment if desired) - # log_info "Removing backup directory after zipping..." - # rm -rf "$BACKUP_DIR" else error_exit "Failed to create backup zip file" fi @@ -385,7 +332,6 @@ create_backup() { # Main function main() { - # Setup directories first before any logging setup_directories log_info "Starting GitHub Projects Local Backup" @@ -398,7 +344,6 @@ main() { local total=0 ok=0 fail=0 - # Stream repos line-by-line while IFS= read -r repo_url; do [ -n "${repo_url:-}" ] || continue total=$((total + 1)) @@ -410,19 +355,13 @@ main() { fi done < <(get_github_repos) - TOTAL_REPOS=$total - SUCCESSFUL_REPOS=$ok - FAILED_REPOS=$fail - if [ "$total" -eq 0 ]; then log_warning "No repositories found" exit 0 fi - # Create backup create_backup - # Summary log_success "Backup process completed!" log_info "Total repositories: $total" log_info "Successful: $ok" @@ -434,5 +373,4 @@ main() { fi } -# Run main function main "$@" diff --git a/git-scripts/sync-all.sh b/git-scripts/sync-all.sh new file mode 100755 index 0000000..3a0b470 --- /dev/null +++ b/git-scripts/sync-all.sh @@ -0,0 +1,178 @@ +#!/usr/bin/env bash +# Sync All Git Repositories +# Finds all git repositories within a given path, +# switches to the default branch, and pulls latest changes. + +set -euo pipefail + +# This block provides logging functions only when the script is executed directly. +# When sourced by other scripts, they should use their own logging mechanisms. +if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then + # Colors for output + readonly RED='\033[0;31m' + readonly GREEN='\033[0;32m' + readonly YELLOW='\033[1;33m' + readonly BLUE='\033[0;34m' + readonly NC='\033[0m' # No Color + + log_info() { echo -e "${BLUE}[INFO]${NC} $*" >&2; } + log_success() { echo -e "${GREEN}[SUCCESS]${NC} $*" >&2; } + log_warning() { echo -e "${YELLOW}[WARNING]${NC} $*" >&2; } + log_error() { echo -e "${RED}[ERROR]${NC} $*" >&2; } +else + # When sourced, these are no-ops. Sourcing script must provide its own logging. + log_info() { :; } + log_success() { :; } + log_warning() { :; } + log_error() { :; } +fi + +# Usage: get_default_branch +# Echos the default branch name to stdout on success, returns 1 on failure. +get_default_branch() { + local default_branch + + # Try to get default branch from remote HEAD + if default_branch=$(git rev-parse --abbrev-ref origin/HEAD 2>/dev/null | sed 's|origin/||'); then + if [[ -n "$default_branch" && "$default_branch" != "HEAD" ]]; then + echo "$default_branch" + return 0 + fi + fi + + # Try to get default branch from remote show (slower) + if default_branch=$(git remote show origin 2>/dev/null | awk '/HEAD branch/ {print $NF}' 2>/dev/null); then + if [[ -n "$default_branch" ]]; then + echo "$default_branch" + return 0 + fi + fi + + # Fallback: check common branch names (local) + for branch in main master develop; do + if git show-ref --verify --quiet "refs/heads/$branch" 2>/dev/null; then + echo "$branch" + return 0 + fi + done + + return 1 +} + +# Usage: sync_repo +# Echos status messages to stdout/stderr. Returns 0 on success, 1 on failure. +sync_repo() { + local repo_path="$1" + local repo_name + repo_name=$(basename "$repo_path") + local original_dir + original_dir=$(pwd) + + echo "--- Processing: $repo_name ---" + + if ! cd "$repo_path" 2>/dev/null; then + echo "ERROR: Could not enter directory: $repo_path" >&2 + return 1 + fi + + # Skip if no remote origin + if ! git remote get-url origin >/dev/null 2>&1; then + echo "WARNING: No remote 'origin' found. Skipping $repo_name." >&2 + cd "$original_dir" + return 0 + fi + + # Fetch latest remote info + echo "INFO: Fetching latest info for $repo_name..." + if ! git fetch origin --prune >/dev/null 2>&1; then + echo "ERROR: Failed to fetch from origin. Skipping." >&2 + cd "$original_dir" + return 1 + fi + + # Determine default branch + local default_branch + if ! default_branch=$(get_default_branch); then + echo "ERROR: Could not determine default branch. Skipping." >&2 + cd "$original_dir" + return 1 + fi + + echo "INFO: Default branch identified: $default_branch" + + # Check for uncommitted changes + if [[ -n "$(git status --porcelain)" ]]; then + echo "WARNING: Repository has uncommitted changes. Skipping pull to avoid conflicts." >&2 + cd "$original_dir" + return 0 + fi + + # Switch to default branch + local current_branch + current_branch=$(git branch --show-current) + + if [[ "$current_branch" != "$default_branch" ]]; then + echo "INFO: Switching from '$current_branch' to '$default_branch'..." + if ! git checkout "$default_branch" >/dev/null 2>&1; then + echo "ERROR: Failed to checkout $default_branch." >&2 + cd "$original_dir" + return 1 + fi + fi + + # Pull latest changes + echo "INFO: Pulling latest changes for $default_branch..." + if git pull origin "$default_branch" >/dev/null 2>&1; then + echo "SUCCESS: Updated $repo_name successfully." + cd "$original_dir" + return 0 + else + echo "ERROR: Failed to pull changes for $repo_name." >&2 + cd "$original_dir" + return 1 + fi +} + +main() { + local input_dir="${1:-.}" + + if [[ ! -d "$input_dir" ]]; then + log_error "Directory not found: $input_dir" + exit 1 + fi + + local search_dir + search_dir=$(cd "$input_dir" && pwd) + log_info "Searching for git repositories in: $search_dir" + + # Find all .git directories and get their parent directories + find "$search_dir" -name ".git" -type d -prune | while read -r git_dir; do + local repo_path + repo_path=$(dirname "$git_dir") + local result_output + + # Call sync_repo and capture its stdout/stderr + result_output=$(sync_repo "$repo_path" 2>&1 || true) + + # Process the captured output for logging + echo "$result_output" | while IFS= read -r line; do + if [[ "$line" =~ ^---[[:space:]]Processing:.* ]]; then + echo -e "\n${BLUE}$line${NC}" + elif [[ "$line" =~ ^INFO:.* ]]; then + log_info "${line#INFO: }" + elif [[ "$line" =~ ^SUCCESS:.* ]]; then + log_success "${line#SUCCESS: }" + elif [[ "$line" =~ ^WARNING:.* ]]; then + log_warning "${line#WARNING: }" + elif [[ "$line" =~ ^ERROR:.* ]]; then + log_error "${line#ERROR: }" + else + echo "$line" + fi + done + done +} + +if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then + main "$@" +fi diff --git a/package-lock.json b/package-lock.json index 3a97c70..78e5774 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,9 +5,1050 @@ "packages": { "": { "devDependencies": { + "markdownlint-cli": "^0.48.0", "prettier": "^3.7.3" } }, + "node_modules/@types/debug": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", + "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/katex": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.8.tgz", + "integrity": "sha512-trgaNyfU+Xh2Tc+ABIb44a5AYUpicB3uwirOioeOkNPPbmgRNtcWyDeeFRzjPZENO9Vq8gvVqfhaaXWLlevVwg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", + "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", + "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/get-east-asian-width": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/ini": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz", + "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/katex": { + "version": "0.16.46", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.46.tgz", + "integrity": "sha512-WHy4Coo+bGZyH7NwJKHkS04YFsFcarWbAEOAC3EMndzdN6VSZqklLLIgfxzyaW9jDoeGYJX9SWbJPKpecox0Uw==", + "dev": true, + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/katex/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, + "node_modules/markdown-it": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.1.tgz", + "integrity": "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "node_modules/markdownlint": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.40.0.tgz", + "integrity": "sha512-UKybllYNheWac61Ia7T6fzuQNDZimFIpCg2w6hHjgV1Qu0w1TV0LlSgryUGzM0bkKQCBhy2FDhEELB73Kb0kAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "micromark": "4.0.2", + "micromark-core-commonmark": "2.0.3", + "micromark-extension-directive": "4.0.0", + "micromark-extension-gfm-autolink-literal": "2.1.0", + "micromark-extension-gfm-footnote": "2.1.0", + "micromark-extension-gfm-table": "2.1.1", + "micromark-extension-math": "3.1.0", + "micromark-util-types": "2.0.2", + "string-width": "8.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/DavidAnson" + } + }, + "node_modules/markdownlint-cli": { + "version": "0.48.0", + "resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.48.0.tgz", + "integrity": "sha512-NkZQNu2E0Q5qLEEHwWj674eYISTLD4jMHkBzDobujXd1kv+yCxi8jOaD/rZoQNW1FBBMMGQpuW5So8B51N/e0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "~14.0.3", + "deep-extend": "~0.6.0", + "ignore": "~7.0.5", + "js-yaml": "~4.1.1", + "jsonc-parser": "~3.3.1", + "jsonpointer": "~5.0.1", + "markdown-it": "~14.1.1", + "markdownlint": "~0.40.0", + "minimatch": "~10.2.4", + "run-con": "~1.3.2", + "smol-toml": "~1.6.0", + "tinyglobby": "~0.2.15" + }, + "bin": { + "markdownlint": "markdownlint.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "dev": true, + "license": "MIT" + }, + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-directive": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-directive/-/micromark-extension-directive-4.0.0.tgz", + "integrity": "sha512-/C2nqVmXXmiseSSuCdItCMho7ybwwop6RrrRPk0KbOHW21JKoCldC+8rFOaundDoRBUWBnJJcxeA/Kvi34WQXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "parse-entities": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "dev": true, + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", + "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-math": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-math/-/micromark-extension-math-3.1.0.tgz", + "integrity": "sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/katex": "^0.16.0", + "devlop": "^1.0.0", + "katex": "^0.16.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/parse-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/prettier": { "version": "3.7.3", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.3.tgz", @@ -23,6 +1064,115 @@ "funding": { "url": "https://github.com/prettier/prettier?sponsor=1" } + }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/run-con": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/run-con/-/run-con-1.3.2.tgz", + "integrity": "sha512-CcfE+mYiTcKEzg0IqS08+efdnH0oJ3zV0wSUFBNrMHMuxCtXvBCLzCJHatwuXDcu/RlhjTziTo/a1ruQik6/Yg==", + "dev": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~4.1.0", + "minimist": "^1.2.8", + "strip-json-comments": "~3.1.1" + }, + "bin": { + "run-con": "cli.js" + } + }, + "node_modules/smol-toml": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.6.1.tgz", + "integrity": "sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 18" + }, + "funding": { + "url": "https://github.com/sponsors/cyyynthia" + } + }, + "node_modules/string-width": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.1.0.tgz", + "integrity": "sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "dev": true, + "license": "MIT" } } } diff --git a/package.json b/package.json index a53e77b..23f3729 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,6 @@ { "devDependencies": { + "markdownlint-cli": "^0.48.0", "prettier": "^3.7.3" } } diff --git a/tmux/README.md b/tmux/README.md index 17afea6..a0c03af 100644 --- a/tmux/README.md +++ b/tmux/README.md @@ -1,6 +1,7 @@ # Tmux Session Management Scripts -This directory contains enhanced tmux session management scripts that follow bash and tmux best practices. +This directory contains enhanced tmux session management scripts that +follow bash and tmux best practices. ## Scripts Overview diff --git a/tmux/session-manager.sh b/tmux/session-manager.sh index 92f71a1..a06a8bc 100755 --- a/tmux/session-manager.sh +++ b/tmux/session-manager.sh @@ -7,12 +7,13 @@ set -euo pipefail # Source utility functions SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck disable=SC1090,SC1091 source "${SCRIPT_DIR}/tmux-utils.sh" # Configuration readonly MAIN_SESSION='main' readonly DEV_SESSION='dev' -readonly LOG_FILE="${HOME}/.tmux-session-manager.log" +# readonly LOG_FILE # Usage function show_usage() { @@ -101,7 +102,7 @@ handle_session() { # Main function main() { - local verbose=false +# verbose=false local session_type="" # Parse arguments @@ -112,7 +113,7 @@ main() { exit 0 ;; -v|--verbose) - verbose=true + # verbose shift ;; main|dev|list|kill|killall|info)