#!/usr/bin/env bash # migrate-brain-halls.sh — move flat brain/wiki/{concepts,entities}/ notes # into the structured brain/wiki/// layout introduced by # hyperguild#1. # # Reads each note's YAML frontmatter: # type: maps to hall (decision, hypothesis, failure, source → eponymous; # concept, entity, anything else → facts) # domain: maps to wing (sanitised: lowercase, alphanumerics + hyphens); # empty → "general" # # Dry-run by default. Pass --commit to actually move files. Idempotent: # already-migrated notes (already under a Wing dir) are left alone. # # Usage: # scripts/migrate-brain-halls.sh /path/to/brain # dry-run # scripts/migrate-brain-halls.sh --commit /path/to/brain # apply set -euo pipefail COMMIT=0 BRAIN="" for arg in "$@"; do case "$arg" in --commit) COMMIT=1 ;; -h|--help) sed -n '2,18p' "$0" exit 0 ;; *) BRAIN="$arg" ;; esac done if [[ -z "$BRAIN" ]]; then echo "error: brain directory required" >&2 echo "usage: $0 [--commit] " >&2 exit 2 fi if [[ ! -d "$BRAIN" ]]; then echo "error: $BRAIN is not a directory" >&2 exit 2 fi WIKI="$BRAIN/wiki" if [[ ! -d "$WIKI" ]]; then echo "no $WIKI/ — nothing to migrate" exit 0 fi sanitise() { # lowercase, replace non-alnum with hyphen, collapse hyphens, trim local s s=$(printf '%s' "$1" | tr '[:upper:]' '[:lower:]' \ | sed -E 's/[^a-z0-9]+/-/g; s/^-+//; s/-+$//; s/-+/-/g') printf '%s' "$s" } # extract_frontmatter_value # Echoes the value (trimmed, unquoted) of `key:` from a leading YAML # frontmatter block. Empty if absent or no frontmatter. extract_frontmatter_value() { awk -v key="$2" ' BEGIN { in_fm = 0; first = 1 } /^---[[:space:]]*$/ { if (first) { in_fm = 1; first = 0; next } if (in_fm) { exit } } in_fm { idx = index($0, ":") if (idx == 0) next k = substr($0, 1, idx-1) v = substr($0, idx+1) gsub(/^[[:space:]]+|[[:space:]]+$/, "", k) gsub(/^[[:space:]]+|[[:space:]]+$/, "", v) gsub(/^["'\'']|["'\'']$/, "", v) if (k == key) { print v; exit } } ' "$1" } hall_for_type() { case "$1" in decision|decisions) echo "decisions" ;; hypothesis|hypotheses) echo "hypotheses" ;; failure|failures) echo "failures" ;; source|sources) echo "sources" ;; *) echo "facts" ;; esac } declare -i moved=0 skipped=0 migrate_source_dir() { local src="$1" [[ -d "$src" ]] || return 0 while IFS= read -r -d '' f; do local typ domain wing hall slug dest typ=$(extract_frontmatter_value "$f" type) domain=$(extract_frontmatter_value "$f" domain) hall=$(hall_for_type "$typ") wing=$(sanitise "${domain:-general}") [[ -z "$wing" ]] && wing="general" slug=$(basename "$f" .md) dest="$WIKI/$wing/$hall/$slug.md" if [[ "$f" == "$dest" ]]; then skipped=$((skipped + 1)) continue fi if [[ -e "$dest" ]]; then echo "skip (target exists): $f → $dest" skipped=$((skipped + 1)) continue fi if [[ "$COMMIT" -eq 1 ]]; then mkdir -p "$(dirname "$dest")" git -C "$BRAIN" mv "$f" "$dest" 2>/dev/null || mv "$f" "$dest" fi echo "move: $f → $dest" moved=$((moved + 1)) done < <(find "$src" -maxdepth 1 -type f -name '*.md' -print0) } migrate_source_dir "$WIKI/concepts" migrate_source_dir "$WIKI/entities" echo if [[ "$COMMIT" -eq 1 ]]; then echo "moved=$moved skipped=$skipped (committed)" else echo "moved=$moved skipped=$skipped (dry-run — pass --commit to apply)" fi