625569485f
Adds `fn doctor` read-only diagnostic command with subcommands artefacts, services, sync, uses-functions, unused, and --json flag for agents. Each subcommand wraps a registry function in functions/infra/. New functions: - artefact_doctor, services_status, pc_locations_drift, audit_uses_functions, find_unused_functions (Go diagnostics) - backup_sqlite_db, rotate_backups, wait_for_http, wait_for_port, port_kill, tail_journal, pre_commit_hook_install (bash utilities) - notify_telegram (Go HTTP) - backup_all pipeline (tag launcher) Plus prior session leftovers (scan_secrets_in_dirty, append_diary_entry, git utilities, http_session_cookie_middleware, compile/full-git pipelines). Fixes pc_locations_drift filepath.Join bug with absolute dir_path. Documents fn doctor in CLAUDE.md, .claude/rules/fn_doctor.md (rule 23), docs/architecture.md, CHANGELOG.md (2026-05-07), and diary entry. First fn doctor uses-functions run found drift in 7/12 apps (deuda para sincronizar app.md con imports reales). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
67 lines
1.9 KiB
Bash
67 lines
1.9 KiB
Bash
#!/usr/bin/env bash
|
|
# backup_sqlite_db — Snapshot atomico de una BD SQLite usando VACUUM INTO.
|
|
# Mas seguro que cp: no corrompe si hay escrituras concurrentes.
|
|
|
|
backup_sqlite_db() {
|
|
local source="$1"
|
|
local dest="$2"
|
|
|
|
# Verificar dependencia sqlite3
|
|
if ! command -v sqlite3 &>/dev/null; then
|
|
echo "backup_sqlite_db: sqlite3 no encontrado en PATH" >&2
|
|
return 5
|
|
fi
|
|
|
|
# Verificar que source existe
|
|
if [[ ! -f "$source" ]]; then
|
|
echo "backup_sqlite_db: source no existe: $source" >&2
|
|
return 1
|
|
fi
|
|
|
|
# Verificar que source es SQLite valido (header magico)
|
|
local header
|
|
header=$(head -c 16 "$source" 2>/dev/null | strings | head -n1)
|
|
if [[ "$header" != "SQLite format 3" ]]; then
|
|
echo "backup_sqlite_db: source no es una BD SQLite valida: $source" >&2
|
|
return 2
|
|
fi
|
|
|
|
# Crear directorio destino si no existe
|
|
local dest_dir
|
|
dest_dir=$(dirname "$dest")
|
|
if [[ ! -d "$dest_dir" ]]; then
|
|
mkdir -p "$dest_dir" || {
|
|
echo "backup_sqlite_db: no se pudo crear directorio: $dest_dir" >&2
|
|
return 3
|
|
}
|
|
fi
|
|
|
|
# Si el destino existe, borrarlo para que VACUUM INTO no falle
|
|
if [[ -f "$dest" ]]; then
|
|
rm -f "$dest"
|
|
fi
|
|
|
|
# Ejecutar VACUUM INTO (escape de comillas simples en el path)
|
|
local escaped_dest="${dest//\'/\'\'}"
|
|
if ! sqlite3 "$source" "VACUUM INTO '${escaped_dest}';" 2>/dev/null; then
|
|
echo "backup_sqlite_db: fallo en VACUUM INTO: source=$source dest=$dest" >&2
|
|
return 3
|
|
fi
|
|
|
|
# Verificar que dest existe y tiene tamaño > 0
|
|
if [[ ! -f "$dest" ]]; then
|
|
echo "backup_sqlite_db: dest no fue creado: $dest" >&2
|
|
return 3
|
|
fi
|
|
|
|
local bytes
|
|
bytes=$(wc -c < "$dest" 2>/dev/null)
|
|
if [[ -z "$bytes" || "$bytes" -eq 0 ]]; then
|
|
echo "backup_sqlite_db: dest tiene tamaño 0: $dest" >&2
|
|
return 4
|
|
fi
|
|
|
|
echo "OK ${bytes} bytes -> ${dest}"
|
|
return 0
|
|
}
|