feat(doctor): add fn doctor CLI + 14 functions for system management
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>
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
#!/usr/bin/env bash
|
||||
# tail_journal — wrapper sobre journalctl con formato consistente
|
||||
|
||||
tail_journal() {
|
||||
local unit="${1:-}"
|
||||
local lines="${2:-100}"
|
||||
local follow="${3:-false}"
|
||||
local since="${4:-}"
|
||||
local priority="${5:-info}"
|
||||
|
||||
if [[ -z "$unit" ]]; then
|
||||
echo "tail_journal: unit requerida" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Normalizar nombre de unit (añadir .service si no tiene extension)
|
||||
local unit_full="$unit"
|
||||
if [[ "$unit" != *.* ]]; then
|
||||
unit_full="${unit}.service"
|
||||
fi
|
||||
|
||||
# Validar prioridad
|
||||
case "$priority" in
|
||||
emerg|alert|crit|err|warning|notice|info|debug) ;;
|
||||
*)
|
||||
echo "tail_journal: prioridad invalida '$priority'. Valores: emerg alert crit err warning notice info debug" >&2
|
||||
return 2
|
||||
;;
|
||||
esac
|
||||
|
||||
# Verificar que journalctl esta disponible
|
||||
if ! command -v journalctl &>/dev/null; then
|
||||
echo "tail_journal: journalctl no disponible" >&2
|
||||
return 5
|
||||
fi
|
||||
|
||||
# Detectar si la unit es de usuario o de sistema
|
||||
local user_flag=""
|
||||
if systemctl --user list-units --all 2>/dev/null | grep -q "$unit_full"; then
|
||||
user_flag="--user"
|
||||
fi
|
||||
|
||||
# Construir comando base
|
||||
local -a cmd
|
||||
if [[ -z "$user_flag" ]]; then
|
||||
cmd=(sudo journalctl)
|
||||
else
|
||||
cmd=(journalctl --user)
|
||||
fi
|
||||
|
||||
cmd+=(-u "$unit_full" -n "$lines" -p "$priority" --output=short-iso)
|
||||
|
||||
if [[ -n "$since" ]]; then
|
||||
cmd+=(--since "$since")
|
||||
fi
|
||||
|
||||
local follow_flag=false
|
||||
if [[ "$follow" == "true" || "$follow" == "-f" ]]; then
|
||||
follow_flag=true
|
||||
cmd+=(-f)
|
||||
fi
|
||||
|
||||
# Verificar que la unit existe (solo si no hay user_flag y no es sudo)
|
||||
if [[ -n "$user_flag" ]]; then
|
||||
if ! systemctl --user list-units --all 2>/dev/null | grep -q "$unit_full"; then
|
||||
echo "tail_journal: unit '$unit_full' no encontrada" >&2
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Ejecutar sin bufferizar si follow=true
|
||||
if [[ "$follow_flag" == "true" ]]; then
|
||||
stdbuf -oL "${cmd[@]}"
|
||||
else
|
||||
"${cmd[@]}"
|
||||
fi
|
||||
}
|
||||
Reference in New Issue
Block a user