I asked AI to draft this for me. I've edited it. Any surviving AI smells are my oversight.
Well, that did something.Keep going.Nothing is hidden on this page, but some Weblog pages have letters that burn brighter than others.Congratulations! Hope you enjoyed the fire! 🔥 The fire isn't everything, though. One more click starts it over. When you've found and solved the real puzzle, you'll know.
Not a lot to it, just scripts/new-post and follow the prompts to setup the boilerplate. Then write the content. Then to wire up comments on Popsicle Boat, scripts/companion-prompt That’s it!
Boilerplate, fresh. Kind of like making waffles. Get it? Hehe.
New Post
#!/usr/bin/env bash
#
#
set -euo pipefail
cd "$(git rev-parse --show-toplevel)"
die() { echo "new-post: $1" >&2; exit 1; }
yaml_quote() {
case $1 in
*\"*\'* | *\'*\"*) die "can't hold both quote kinds in front matter: $1" ;;
*\"*) printf "'%s'" "$1" ;;
*) printf '"%s"' "$1" ;;
esac
}
yaml_list() {
local IFS=',' item
for item in $1; do
item=$(printf '%s' "$item" | sed -E 's/^ +| +$//g')
[ -n "$item" ] && printf -- "- %s\n" "$item"
done
}
read -r -p "Title: " title
[ -n "$title" ] || die "a post needs a title"
default_slug=$(printf '%s' "$title" |
tr '[:upper:]' '[:lower:]' |
sed -E "s/'//g; s/[^a-z0-9]+/-/g; s/^-+//; s/-+$//")
read -r -p "Slug [$default_slug]: " slug
slug=${slug:-$default_slug}
[ -n "$slug" ] || die "a post needs a slug"
read -r -p "Page bundle, for images alongside the post? [y/N]: " bundle
case $bundle in
[yY]*) post="content/weblog/$slug/index.md" ;;
*) post="content/weblog/$slug.md" ;;
esac
[ -e "$post" ] && die "$post already exists"
read -r -p "Description (meta/OG line; blank to fill in later): " description
read -r -p "Summary (list-page line; blank to fill in later): " summary
read -r -p "Categories, comma-separated [Projects]: " categories
categories=${categories:-Projects}
read -r -p "Tags, comma-separated (e.g. popsicleboat, hugo): " tags
ts=$(date "+%Y-%m-%dT%H:%M:%S%z")
ts="${ts:0:22}:${ts:22}" # RFC3339 wants a colon in the offset
mkdir -p "$(dirname "$post")"
{
echo "---"
echo "title: $(yaml_quote "$title")"
echo "description: $(yaml_quote "$description")"
echo "date: $ts"
echo "summary: $(yaml_quote "$summary")"
echo 'popsicleboat: "" # wired at commit by scripts/companion-prompt'
echo "categories:"
yaml_list "$categories"
if [ -n "$tags" ]; then
echo "tags:"
yaml_list "$tags"
fi
echo "---"
echo ""
} > "$post"
echo ""
echo "Created $post — write the essay."
echo "Committing it will prompt for its companion thread (empty space answer skips)."
Companion Prompt
#!/usr/bin/env bash
#
#
#
set -uo pipefail
cd "$(git rev-parse --show-toplevel)"
[ "${COMPANION_PROMPT:-1}" = "0" ] && exit 0
new_posts=$(git diff --cached --name-only --diff-filter=A -- \
'content/weblog/*.md' 'content/weblog/*/index.md' | grep -v '_index\.md$' || true)
[ -z "$new_posts" ] && exit 0
needs_thread() {
grep -qE '^popsicleboat: *("")? *(#.*)?$' "$1"
}
pending=()
while IFS= read -r post; do
[ -f "$post" ] && needs_thread "$post" && pending+=("$post")
done <<< "$new_posts"
[ "${#pending[@]}" -eq 0 ] && exit 0
later() { # how to finish the job after a degraded path
echo "companion-prompt: wire it later with: scripts/companion-thread $1 --space <space>" >&2
}
if ! { : < /dev/tty; } 2>/dev/null; then
echo "companion-prompt: no terminal — committing without companion threads." >&2
for post in "${pending[@]}"; do later "$post"; done
exit 0
fi
if [ -z "${POPSICLEBOAT_TOKEN:-}" ]; then
echo "companion-prompt: POPSICLEBOAT_TOKEN not set — committing without companion threads." >&2
for post in "${pending[@]}"; do later "$post"; done
exit 0
fi
insert_after_popsicleboat() {
local file=$1 line=$2
awk -v add="$line" '{ print } !done && /^popsicleboat:/ { print add; done = 1 }' \
"$file" > "$file.tmp" && mv "$file.tmp" "$file"
}
for post in "${pending[@]}"; do
echo ""
echo "New post: $post"
read -r -p " PopsicleBoat space for its thread (empty to skip): " space < /dev/tty
if [ -z "$space" ]; then
later "$post"
continue
fi
read -r -p " Thread title override (empty for the template default): " title < /dev/tty
insert_after_popsicleboat "$post" "popsicleboat_space: \"$space\""
if [ -n "$title" ]; then
case $title in
*\"*\'* | *\'*\"*)
echo " title has both quote kinds — front matter can't hold that; using the template default." >&2
;;
*\"*)
insert_after_popsicleboat "$post" "popsicleboat_title: '$title'"
;;
*)
insert_after_popsicleboat "$post" "popsicleboat_title: \"$title\""
;;
esac
fi
if scripts/companion-thread "$post"; then
git add "$post"
else
echo "companion-prompt: thread creation failed — committing the post unwired." >&2
later "$post"
git add "$post" # keep the space/title answers we wrote either way
fi
done
Your reply is in the thread. It’ll appear right here in about a minute.