2a3d780347
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>
80 lines
2.7 KiB
Bash
80 lines
2.7 KiB
Bash
#!/usr/bin/env bash
|
|
# append_diary_entry — Añade una entrada al diario del dia en docs/diary/YYYY-MM-DD.md
|
|
|
|
append_diary_entry() {
|
|
local titulo="$1"
|
|
local cuerpo="${2:-}"
|
|
|
|
if [[ -z "$titulo" ]]; then
|
|
echo "append_diary_entry: titulo requerido" >&2
|
|
return 2
|
|
fi
|
|
|
|
local date time diary_dir diary_file
|
|
date=$(date +%Y-%m-%d)
|
|
time=$(date +%H:%M)
|
|
diary_dir="${DIARY_DIR:-docs/diary}"
|
|
diary_file="${diary_dir}/${date}.md"
|
|
|
|
# Crear directorio y cabecera del dia si el archivo no existe
|
|
if [[ ! -f "$diary_file" ]]; then
|
|
mkdir -p "$diary_dir"
|
|
printf '# %s\n' "$date" > "$diary_file"
|
|
fi
|
|
|
|
# Componer bloque de entrada
|
|
if [[ -n "$cuerpo" ]]; then
|
|
printf '\n## %s — %s\n\n%s\n' "$time" "$titulo" "$cuerpo" >> "$diary_file"
|
|
else
|
|
printf '\n## %s — %s\n' "$time" "$titulo" >> "$diary_file"
|
|
fi
|
|
|
|
echo "$diary_file"
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Self-test: bash bash/functions/infra/append_diary_entry.sh --test
|
|
# ---------------------------------------------------------------------------
|
|
if [ "${BASH_SOURCE[0]}" = "$0" ] && [ "${1:-}" = "--test" ]; then
|
|
set -euo pipefail
|
|
|
|
declare -i PASS=0 FAIL=0
|
|
|
|
assert_contains() {
|
|
local test_name="$1" pattern="$2" file="$3"
|
|
if grep -qF "$pattern" "$file"; then
|
|
echo "PASS: $test_name"
|
|
PASS+=1
|
|
else
|
|
echo "FAIL: $test_name — patron '$pattern' no encontrado en $file"
|
|
FAIL+=1
|
|
fi
|
|
}
|
|
|
|
# Setup: directorio temporal
|
|
tmpdir=$(mktemp -d)
|
|
export DIARY_DIR="$tmpdir/diary"
|
|
|
|
# Test 1: crear archivo nuevo con titulo y cuerpo
|
|
diary_file=$(append_diary_entry "primer bloque" "Hecho algo importante hoy.")
|
|
assert_contains "crear archivo nuevo con titulo y cuerpo" "primer bloque" "$diary_file"
|
|
assert_contains "crear archivo nuevo con titulo y cuerpo" "# $(date +%Y-%m-%d)" "$diary_file"
|
|
assert_contains "crear archivo nuevo con titulo y cuerpo" "Hecho algo importante hoy." "$diary_file"
|
|
|
|
# Test 2: append en el mismo dia sin reescribir contenido previo
|
|
append_diary_entry "segundo bloque" "Otro parrafo de trabajo." > /dev/null
|
|
assert_contains "append mismo dia conserva primera entrada" "primer bloque" "$diary_file"
|
|
assert_contains "append mismo dia anade segunda entrada" "segundo bloque" "$diary_file"
|
|
|
|
# Test 3: entrada sin cuerpo (solo header)
|
|
append_diary_entry "solo titulo sin cuerpo" "" > /dev/null
|
|
assert_contains "entrada sin cuerpo escribe header" "solo titulo sin cuerpo" "$diary_file"
|
|
|
|
# Cleanup
|
|
rm -rf "$tmpdir"
|
|
|
|
echo "---"
|
|
echo "Results: $PASS passed, $FAIL failed"
|
|
[[ $FAIL -eq 0 ]] || exit 1
|
|
fi
|