vault-sync: 2026-09-16 00:00 (jimmy)
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env bash
|
||||
# =============================================================================
|
||||
# Hook: Validate Frontmatter (PostToolUse on Write)
|
||||
# =============================================================================
|
||||
# After writing a .md file to the vault, checks that YAML frontmatter is
|
||||
# properly formed. Obsidian relies on frontmatter for metadata, Dataview
|
||||
# queries, tags, and search. Broken frontmatter silently breaks all of this.
|
||||
#
|
||||
# Checks:
|
||||
# 1. If the file starts with ---, there must be a closing ---
|
||||
# 2. No tabs in frontmatter (YAML uses spaces only)
|
||||
# 3. Colons in values must be quoted
|
||||
#
|
||||
# Exit codes:
|
||||
# 0 = all good
|
||||
# 1 = warning (issue found, but operation is not blocked)
|
||||
# =============================================================================
|
||||
|
||||
INPUT=$(cat)
|
||||
PLATFORM_DIR=$(echo "$INPUT" | jq -r '.platform_dir // ".claude"' 2>/dev/null)
|
||||
FILE=$(echo "$INPUT" | jq -r '.args.file_path // ""' 2>/dev/null)
|
||||
|
||||
# Skip if we can't extract a path
|
||||
[[ -z "$FILE" ]] && exit 0
|
||||
|
||||
# Only check .md files
|
||||
[[ "$FILE" == *.md ]] || exit 0
|
||||
|
||||
# Skip system files (agents, skills, references)
|
||||
[[ "$FILE" == *"$PLATFORM_DIR/"* ]] && exit 0
|
||||
|
||||
# Skip if file doesn't exist (deleted or moved)
|
||||
[[ -f "$FILE" ]] || exit 0
|
||||
|
||||
# ── Check 1: frontmatter delimiters ─────────────────────────────────────────
|
||||
FIRST_LINE=$(head -1 "$FILE")
|
||||
if [[ "$FIRST_LINE" == "---" ]]; then
|
||||
# Count opening and closing delimiters (lines that are exactly ---)
|
||||
DELIMITER_COUNT=$(grep -c "^---$" "$FILE" 2>/dev/null || echo "0")
|
||||
if [[ "$DELIMITER_COUNT" -lt 2 ]]; then
|
||||
echo "WARNING: Frontmatter in $(basename "$FILE") is missing the closing '---' delimiter. Obsidian will not parse metadata correctly."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Extract frontmatter content (between first and second ---)
|
||||
FRONTMATTER=$(sed -n '2,/^---$/p' "$FILE" | head -n -1)
|
||||
|
||||
# ── Check 2: tabs in frontmatter ────────────────────────────────────────
|
||||
TAB_CHAR="$(printf '\t')"
|
||||
if echo "$FRONTMATTER" | grep -q "$TAB_CHAR"; then
|
||||
TAB_LINES=$(echo "$FRONTMATTER" | grep -n "$TAB_CHAR" | head -3)
|
||||
echo "WARNING: Frontmatter in $(basename "$FILE") contains tabs. YAML requires spaces for indentation. Lines with tabs: $TAB_LINES"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ── Check 3: common YAML errors ────────────────────────────────────────
|
||||
# Unquoted values with colons (e.g., "title: My Note: Part 2" breaks YAML)
|
||||
if echo "$FRONTMATTER" | grep -qE '^[a-zA-Z_-]+: .+: '; then
|
||||
PROBLEM_LINES=$(echo "$FRONTMATTER" | grep -nE '^[a-zA-Z_-]+: .+: ' | head -3)
|
||||
echo "WARNING: Frontmatter in $(basename "$FILE") may have unquoted colons in values. Wrap the value in quotes to avoid YAML parse errors. Problem lines: $PROBLEM_LINES"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
exit 0
|
||||
Reference in New Issue
Block a user