add claude-obsidian
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
#!/usr/bin/env bash
|
||||
# allocate-address.sh — atomic creation-order address allocation for the vault.
|
||||
#
|
||||
# Reserves the next address of the form c-NNNNNN and increments the counter
|
||||
# under an exclusive flock. On missing counter file, recovers by scanning the
|
||||
# vault for the highest existing c-NNNNNN in page frontmatter and resuming from
|
||||
# max+1. Never silently resets to 1 in a non-empty vault.
|
||||
#
|
||||
# Usage:
|
||||
# ./scripts/allocate-address.sh # prints the reserved address (e.g. c-000042) to stdout
|
||||
# ./scripts/allocate-address.sh --peek # prints the next value without incrementing
|
||||
# ./scripts/allocate-address.sh --rebuild # recomputes counter from max observed and exits
|
||||
#
|
||||
# Exit codes:
|
||||
# 0 — success
|
||||
# 1 — lock acquisition failed (another writer is holding the lock)
|
||||
# 2 — vault-meta directory missing and cannot be created
|
||||
# 3 — counter value corrupt or non-numeric
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
VAULT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
COUNTER_FILE="${VAULT_ROOT}/.vault-meta/address-counter.txt"
|
||||
LOCK_FILE="${VAULT_ROOT}/.vault-meta/.address.lock"
|
||||
WIKI_DIR="${VAULT_ROOT}/wiki"
|
||||
|
||||
MODE="${1:-allocate}"
|
||||
|
||||
mkdir -p "$(dirname "$COUNTER_FILE")" || {
|
||||
echo "ERR: cannot create .vault-meta/" >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
# Acquire exclusive lock with 5-second timeout. Release automatically on scope exit.
|
||||
exec 9>"$LOCK_FILE"
|
||||
if ! flock -x -w 5 9; then
|
||||
echo "ERR: could not acquire address allocator lock within 5s" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
scan_max_c_address() {
|
||||
# Emit the largest NNNNNN from "address: c-NNNNNN" lines that appear inside
|
||||
# the FIRST YAML frontmatter block of each wiki .md file. Code-block examples
|
||||
# and body prose are excluded. Returns 0 if none found.
|
||||
if [ ! -d "$WIKI_DIR" ]; then
|
||||
echo 0
|
||||
return
|
||||
fi
|
||||
find "$WIKI_DIR" -type f -name '*.md' -print0 2>/dev/null \
|
||||
| xargs -0 awk '
|
||||
FNR == 1 { state = "pre"; next_is_fm = ($0 == "---") ? 1 : 0 }
|
||||
FNR == 1 && $0 == "---" { state = "fm"; next }
|
||||
state == "fm" && $0 == "---" { state = "body"; nextfile }
|
||||
state == "fm" && match($0, /^address:[[:space:]]+c-[0-9]{6}[[:space:]]*$/) {
|
||||
if (match($0, /c-[0-9]{6}/)) {
|
||||
print substr($0, RSTART, RLENGTH)
|
||||
}
|
||||
}
|
||||
' 2>/dev/null \
|
||||
| sed 's/^c-0*//;s/^$/0/' \
|
||||
| sort -n \
|
||||
| tail -1 \
|
||||
| awk 'BEGIN{n=0} {n=$0} END{print (n+0)}'
|
||||
}
|
||||
|
||||
read_or_recover_counter() {
|
||||
if [ ! -f "$COUNTER_FILE" ]; then
|
||||
local max_c
|
||||
max_c="$(scan_max_c_address)"
|
||||
echo $((max_c + 1)) > "$COUNTER_FILE"
|
||||
echo "INFO: counter file missing; recovered from vault scan, set to $((max_c + 1))" >&2
|
||||
fi
|
||||
local raw
|
||||
raw="$(cat "$COUNTER_FILE")"
|
||||
if ! [[ "$raw" =~ ^[0-9]+$ ]]; then
|
||||
echo "ERR: counter file content is not a positive integer: $raw" >&2
|
||||
exit 3
|
||||
fi
|
||||
echo "$raw"
|
||||
}
|
||||
|
||||
case "$MODE" in
|
||||
--peek)
|
||||
read_or_recover_counter
|
||||
;;
|
||||
--rebuild)
|
||||
max_c="$(scan_max_c_address)"
|
||||
echo $((max_c + 1)) > "$COUNTER_FILE"
|
||||
echo "Counter rebuilt: next = $((max_c + 1))"
|
||||
;;
|
||||
allocate|"")
|
||||
current="$(read_or_recover_counter)"
|
||||
next=$((current + 1))
|
||||
echo "$next" > "$COUNTER_FILE"
|
||||
printf 'c-%06d\n' "$current"
|
||||
;;
|
||||
*)
|
||||
echo "ERR: unknown mode: $MODE" >&2
|
||||
echo "Usage: $0 [allocate|--peek|--rebuild]" >&2
|
||||
exit 3
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user