跳至主要内容
小龙虾小龙虾AI
🤖

Dev Backup

Snapshot con restore distruttivo, trigger stretti e fallback tar sicuro (v1.2.2)

下载1.1k
星标1
版本1.2.2
系统工具
安全通过

技能说明


name: "dev-backup" description: "Snapshot con restore distruttivo, trigger stretti e fallback tar sicuro (v1.2.2)"

dev-backup

Snapshot the current state of a named project for safe rollback.

Explicit Command Usage

⚠️ REGOLA CRITICA: Chiama la skill SOLO quando l'utente emette un comando esplicito di backup o restore. Non attivare mai per frasi generiche come "com'è il progetto?", "stai lavorando a...", o quando "backup" appare casualmente nella conversazione.

Trigger validi (solo questi):

  • "Fai un backup manuale di [nome-progetto]" → crea snapshot
  • "Esegui backup di [nome-progetto]" → crea snapshot
  • "Backup di [nome-progetto]" → crea snapshot
  • "Ripristina il backup N di [nome-progetto]" → restore da snapshot specifico (con conferma interattiva)
  • "Mostra i backup di [nome-progetto]" → lista snapshots

NON triggerare con:

  • Frasi casuali dove "backup" appare come parola nella conversazione
  • "Salva lo stato attuale" (troppo ambiguo — non è un comando esplicito)
  • "Fai un backup dello sviluppo" (non specifica il progetto)
  • "Ripristina il backup di [nome-progetto]" senza numero snapshot (troppo vago, richiede "backup N")
  • Qualsiasi frase che non contenga un comando chiaro di backup/restore + nome progetto
  • Il restore richiede SEMPRE conferma esplicita dell'utente PRIMA di eseguire

Comandi

# Backup any project
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
bash "$SCRIPT_DIR/dev-backup.sh" <project-name> --project-dir /path/to/your/project

# Example: backup a "my-app" project
bash "$SCRIPT_DIR/dev-backup.sh" my-app --project-dir /home/user/projects/my-app

# No --project-dir? Uses the current working directory
cd /home/user/projects/my-app
bash "$SCRIPT_DIR/dev-backup.sh" my-app

Naming

Snapshots are named per project:

  • my-app-snapshot-1, my-app-snapshot-2, …
  • another-project-snapshot-1, another-project-snapshot-2, …

Each project tracks its own counter independently.

Excluded from snapshot

  • .git, node_modules, .vite, .cache, *.log, .env, backups/

Restore (🔴 DISTRUTTIVO — LEGGERE PRIMA)

⛔ PERICOLO: QUESTA OPERAZIONE È DISTRUTTIVA.

Il restore sovrascrive TUTTI i file esistenti nel progetto target con lo stato dello snapshot.

  • Qualsiasi modifica non salvata nel progetto verrà PERDUTA DEFINITIVAMENTE.
  • File nuovi creati dopo l'ultimo backup verranno eliminati.
  • File modificati localmente verranno sovrascritti senza preavviso.

SEMPRE eseguire --dry-run PRIMA del restore reale.

# 🔴 STEP 1: Dry-run OBBLIGATORIO (mostra cosa verrebbe sovrascritto)
bash "$SCRIPT_DIR/dev-backup.sh" my-app --restore --dry-run --project-dir /path/to/your/project

# 🔴 STEP 2: Solo se dry-run è accettabile, esegui il restore
bash "$SCRIPT_DIR/dev-backup.sh" my-app --restore --project-dir /path/to/your/project

# Restore latest snapshot
bash "$SCRIPT_DIR/dev-backup.sh" my-app --restore --project-dir /path/to/your/project

# Restore specific snapshot
bash "$SCRIPT_DIR/dev-backup.sh" my-app --restore --snapshot 2 --project-dir /path/to/your/project

Verifica del checksum: Durante il restore, lo script verifica che lo snapshot non sia corrotto calcolando un checksum SHA256 di tutti i file nello snapshot e confrontandolo con quello salvato durante il backup. Questo NON controlla la compatibilità con lo stato attuale del progetto — solo l'integrità dello snapshot stesso.

List

To list all snapshots for a project:

bash "$SCRIPT_DIR/dev-backup.sh" my-app --list

Retention

By default, only the last 5 snapshots per project are kept. Vecchi snapshot vengono eliminati definitivamente senza conferma. Per cambiare:

# Backup con retention personalizzata (tieni ultimi 10)
bash "$SCRIPT_DIR/dev-backup.sh" my-app --keep 10 --project-dir /path/to/your/project

# Oppure disabilita la retention automatica con un numero enorme
bash "$SCRIPT_DIR/dev-backup.sh" my-app --keep 9999 --project-dir /path/to/your/project

Verification

After backup, confirm:

ls -la <backups-dir>/

You should see the project-prefixed snapshot and .latest symlink.


scripts/dev-backup.sh --- #!/usr/bin/env bash set -euo pipefail

dev-backup: snapshot a named project for safe rollback

Usage: dev-backup <project-name> [options]

Creates a numbered snapshot of a project, prefixed with the project name

so you can distinguish backups across different apps.

Examples:

dev-backup my-app # uses current dir as project dir

dev-backup my-app --project-dir /path # explicit project dir

dev-backup my-app --list # list all snapshots

dev-backup my-app --restore # restore latest snapshot

dev-backup my-app --restore --snapshot 2 # restore specific snapshot

dev-backup my-app --dry-run # dry run restore (show what would change)

Snapshots are named: <project>-snapshot-1, <project>-snapshot-2, …

A .latest symlink always points to the newest snapshot.

Default retention: 5 snapshots per project (use --keep to change).

Project name is mandatory

if [[ $# -lt 1 ]]; then echo "Usage: $0 <project-name> [--project-dir PATH] [--output-dir PATH] [--list|--restore] [--snapshot N] [--keep N] [--dry-run]" echo "Example: $0 my-app --project-dir /home/user/projects/my-app" exit 1 fi

PROJECT_NAME="$1" shift

Sanitize project name: replace spaces and special chars with hyphens

PROJECT_NAME="$(echo "$PROJECT_NAME" | sed 's/[^a-zA-Z0-9_-]/-/g')"

PROJECT_DIR="${PROJECT_DIR:-.}" OUTPUT_DIR="${OUTPUT_DIR:-$(dirname "$PROJECT_DIR")/backups}" PREFIX="${PROJECT_NAME}-snapshot" KEEP=5 ACTION="backup" SNAPSHOT_NUM="" DRY_RUN=false

Parse args

while [[ $# -gt 0 ]]; do case "$1" in --project-dir) PROJECT_DIR="$2"; shift 2 ;; --output-dir) OUTPUT_DIR="$2"; shift 2 ;; --list) ACTION="list"; shift ;; --restore) ACTION="restore"; shift ;; --snapshot) SNAPSHOT_NUM="$2"; shift 2 ;; --keep) KEEP="$2"; shift 2 ;; --dry-run) DRY_RUN=true; shift ;; --help|-h) echo "Usage: $0 <project-name> [--project-dir PATH] [--output-dir PATH] [--list|--restore] [--snapshot N] [--keep N] [--dry-run]" echo "Options:" echo " --project-dir PATH Path to the project (default: current dir)" echo " --output-dir PATH Where to store backups (default: ../backups/)" echo " --list List all snapshots for this project" echo " --restore Restore latest snapshot" echo " --snapshot N Restore specific snapshot number" echo " --keep N Number of snapshots to retain (default: 5)" echo " --dry-run Preview restore without making changes" echo "" echo "Examples:" echo " $0 my-app --project-dir /path/to/app" echo " $0 my-app --list" echo " $0 my-app --restore" echo " $0 my-app --restore --snapshot 2" echo " $0 my-app --restore --dry-run" exit 0 ;; *) echo "Unknown arg: $1"; exit 1 ;; esac done

Resolve to absolute paths

PROJECT_DIR="$(cd "$PROJECT_DIR" && pwd)" OUTPUT_DIR="$(mkdir -p "$OUTPUT_DIR" && cd "$OUTPUT_DIR" && pwd)"

--- LIST MODE ---

if [[ "$ACTION" == "list" ]]; then echo "==> Snapshots for '${PROJECT_NAME}':" echo "" COUNT=0 for dir in "$OUTPUT_DIR"/${PREFIX}-* 2>/dev/null; do if [[ -d "$dir" ]]; then COUNT=$((COUNT + 1)) NAME=$(basename "$dir") SIZE=$(du -sh "$dir" 2>/dev/null | cut -f1 || echo "?") DATE=$(stat -c %y "$dir" 2>/dev/null | cut -d. -f1 || echo "?") # Check if it's the latest LATEST="" if [[ -L "$OUTPUT_DIR/.latest" ]]; then LATEST_TARGET=$(readlink "$OUTPUT_DIR/.latest") if [[ "$LATEST_TARGET" == "$NAME" ]]; then LATEST=" (latest)" fi fi # Checksum if exists CHECKSUM="" if [[ -f "$dir/.checksum" ]]; then CHECKSUM=$(cut -d' ' -f1 "$dir/.checksum") CHECKSUM=" (sha256: ${CHECKSUM:0:12}...)" fi printf " %-30s %6s %s%s%s\n" "$NAME" "$SIZE" "$DATE" "$LATEST" "$CHECKSUM" fi done if [[ $COUNT -eq 0 ]]; then echo " (no snapshots found)" fi echo "" exit 0 fi

--- RESTORE MODE ---

if [[ "$ACTION" == "restore" ]]; then

Determine which snapshot to restore

if [[ -n "$SNAPSHOT_NUM" ]]; then TARGET="$OUTPUT_DIR/${PREFIX}-${SNAPSHOT_NUM}" else # Use .latest symlink LATEST="$OUTPUT_DIR/.latest" if [[ ! -L "$LATEST" ]]; then echo "Error: No .latest symlink found in $OUTPUT_DIR" exit 1 fi TARGET="$OUTPUT_DIR/$(readlink "$LATEST")" fi

if [[ ! -d "$TARGET" ]]; then echo "Error: Snapshot not found: $TARGET" exit 1 fi

echo "==> Restoring snapshot: $(basename "$TARGET")" echo " Source: $TARGET" echo " Target: $PROJECT_DIR"

Verify checksum integrity

if [[ -f "$TARGET/.checksum" ]]; then STORED_CHECKSUM=$(cut -d' ' -f1 "$TARGET/.checksum") CURRENT_CHECKSUM=$(find "$TARGET" -type f ! -name '.checksum' -exec sha256sum {} ; 2>/dev/null | sort | sha256sum | cut -d' ' -f1) if [[ "$STORED_CHECKSUM" == "$CURRENT_CHECKSUM" ]]; then echo " Checksum: ✅ VERIFICATO (${STORED_CHECKSUM:0:16}...) — integrità OK" else echo " Checksum: ⚠️ NON CORRESPONDE! (${STORED_CHECKSUM:0:16}... vs ${CURRENT_CHECKSUM:0:16}...)" echo " ATTENZIONE: Lo snapshot potrebbe essere stato modificato o corrotto!" fi else echo " Checksum: ℹ️ Nessun checksum disponibile per questo snapshot" fi

DRY-RUN mode: show what would change without executing

if [[ "$DRY_RUN" == true ]]; then echo "" echo "==> DRY-RUN: ecco cosa verrebbe sovrascritto:" if command -v rsync &>/dev/null; then rsync -avn --exclude '.checksum' "${TARGET}/" "${PROJECT_DIR}/" 2>&1 | head -50 else diff -rq --exclude='.checksum' "${TARGET}/" "${PROJECT_DIR}/" 2>&1 | head -50 fi echo "" echo "==> Nessuna modifica è stata eseguita. Rimuovi --dry-run per confermare." exit 0 fi

WARNING: destructive operation

echo "" echo "⚠️ ATTENZIONE: Il restore sovrascriverà i file esistenti!" echo " Cambiamenti non salvati andranno persi." echo ""

Copy snapshot back to project dir

if command -v rsync &>/dev/null; then rsync -a
--exclude '.checksum'
"${TARGET}/" "${PROJECT_DIR}/" else cp -a "${TARGET}/." "${PROJECT_DIR}/" fi

echo "==> Restore complete!" echo " Restored: $(basename "$TARGET")" exit 0 fi

--- BACKUP MODE ---

Find next number for THIS project

NEXT=1 if ls "$OUTPUT_DIR/${PREFIX}-"* 1>/dev/null 2>&1; then HIGHEST=$(ls "$OUTPUT_DIR" | grep "^${PROJECT_NAME}-snapshot-" | sed "s/^${PROJECT_NAME}-snapshot-//;s/-.*//" | sort -rn | head -1) if [[ "$HIGHEST" =~ ^[0-9]+$ ]]; then NEXT=$((HIGHEST + 1)) fi fi

SNAPSHOT_NAME="${PREFIX}-${NEXT}" SNAPSHOT_DIR="${OUTPUT_DIR}/${SNAPSHOT_NAME}"

echo "==> Creating dev-backup: ${SNAPSHOT_NAME}" echo " Project: ${PROJECT_NAME}" echo " Source: ${PROJECT_DIR}" echo " Target: ${SNAPSHOT_DIR}"

Copy with rsync (NO --delete to avoid accidental data loss)

if command -v rsync &>/dev/null; then rsync -a
--exclude '.git' --exclude 'node_modules' --exclude '.vite'
--exclude '.cache' --exclude '*.log' --exclude '.env'
--exclude 'backups'
"${PROJECT_DIR}/" "${SNAPSHOT_DIR}/" else mkdir -p "$SNAPSHOT_DIR" tar -C "$(dirname "$PROJECT_DIR")" -cf - "$(basename "$PROJECT_DIR")" | tar -C "$SNAPSHOT_DIR" -xf - fi

Generate checksum for integrity verification

find "$SNAPSHOT_DIR" -type f ! -name '.checksum' -exec sha256sum {} ; 2>/dev/null | sort | sha256sum > "$SNAPSHOT_DIR/.checksum"

Size report

TOTAL_SIZE=$(du -sh "$SNAPSHOT_DIR" 2>/dev/null | cut -f1 || echo "?") echo "==> Snapshot created: ${SNAPSHOT_DIR} (${TOTAL_SIZE})" echo " SHA256: $(cut -d' ' -f1 "$SNAPSHOT_DIR/.checksum" | head -c 16)..."

Update .latest symlink

LATEST="${OUTPUT_DIR}/.latest" rm -f "$LATEST" ln -s "$SNAPSHOT_NAME" "$LATEST"

echo "Done. Latest backup: ${LATEST}"

--- RETENTION ---

Remove old snapshots beyond --keep limit

SNAPSHOT_COUNT=$(ls -1d "$OUTPUT_DIR/${PREFIX}-"* 2>/dev/null | wc -l) if [[ $SNAPSHOT_COUNT -gt $KEEP ]]; then REMOVE_COUNT=$((SNAPSHOT_COUNT - KEEP)) echo "" echo "⚠️ RETENTION: elimino definitivamente $REMOVE_COUNT snapshot vecchi (non recuperabili)." ls -1d "$OUTPUT_DIR/${PREFIX}-"* | sort -t'-' -k$(echo "$PREFIX" | tr -cd '-' | wc -c) -n | head -$REMOVE_COUNT | while read dir; do echo " Removing: $(basename "$dir")" rm -rf "$dir" done echo "==> Retention complete." fi

echo "" echo "To restore: $0 $PROJECT_NAME --restore"

如何使用「Dev Backup」?

  1. 打开小龙虾AI(Web 或 iOS App)
  2. 点击上方「立即使用」按钮,或在对话框中输入任务描述
  3. 小龙虾AI 会自动匹配并调用「Dev Backup技能完成任务
  4. 结果即时呈现,支持继续对话优化

相关技能