yog 0.0.1

yog: a balls-oriented session manager for lernie loops (egui frontend)
Documentation
#!/bin/sh
# bl-install-main — balls close.post plugin: local CICD, install main to $PATH.
#
# When `bl close` seals its squash-merge to main, compile that new tip and
# install the `yog` binary into $PATH. This is the LOCAL half of delivery;
# `bl-push-main` (also close.post) is the remote half.
#
# Why an ephemeral worktree, not the repo root: `bl close` moves main by
# plumbing and never refreshes the root working tree, so after a landing the
# root is stale and may hold uncommitted work. The `main` REF is the single
# source of truth for "what landed", so we build a throwaway
# `git worktree --detach main` and tear it down. It shares the repo's target/
# (CARGO_TARGET_DIR) so the release build stays incremental.
#
# Contract (mirrors bl-push-main):
#   * answers the balls plugin protocol handshake;
#   * ignores stdin (drains a piped payload, never blocks);
#   * ALWAYS exits 0 on dispatch — a non-zero close.post triggers plugin
#     rollback, un-sealing a commit the remote may already hold; a build or
#     install failure only lands in the log, never fails the close;
#   * DETACHES the build (setsid) so `bl close` returns at once; the outcome
#     lands in <repo>/target/cicd-install.log;
#   * acts on THIS project's repo, resolved from the plugin's own on-disk home
#     (<repo>/scripts/bl-install-main -> <repo>), right regardless of cwd.

self="$(readlink -f "$0" 2>/dev/null || echo "$0")"

# Internal worker mode: build main's tip and install. Detached by dispatch;
# runs synchronously when invoked directly (`bl-install-main __build <repo>`),
# which is how it is tested.
if [ "$1" = __build ]; then
  root="$2"
  git -C "$root" worktree prune 2>/dev/null
  wt="$(mktemp -d "${TMPDIR:-/tmp}/yog-cicd.XXXXXX")" || exit 1
  echo "=== $(date '+%F %T') build+install main $(git -C "$root" rev-parse --short main 2>/dev/null) ==="
  status=1
  if git -C "$root" worktree add --quiet --detach "$wt" main; then
    if CARGO_TARGET_DIR="$root/target" make -C "$wt" install; then status=0; fi
    git -C "$root" worktree remove --force "$wt" 2>/dev/null
  else
    echo "bl-install-main: 'git worktree add main' failed; nothing built." >&2
  fi
  rm -rf "$wt" 2>/dev/null
  echo "=== exit=$status ==="
  exit "$status"
fi

# Protocol handshake: declare the ops we serve.
if [ "$1" = protocol ]; then
  printf '{"protocol":[1],"ops":["close"]}\n'
  exit 0
fi

# Dispatch (close.post). Drain stdin, resolve the repo, launch detached, exit 0.
[ -t 0 ] || cat >/dev/null 2>&1

root="$(CDPATH= cd -- "$(dirname -- "$self")/.." && pwd)" || exit 0
mkdir -p "$root/target" 2>/dev/null || exit 0
log="$root/target/cicd-install.log"

# setsid reparents the build into a new session so it survives bl's exit; nohup
# is the fallback where setsid is absent.
if command -v setsid >/dev/null 2>&1; then
  setsid "$self" __build "$root" </dev/null >>"$log" 2>&1 &
else
  nohup "$self" __build "$root" </dev/null >>"$log" 2>&1 &
fi

echo "bl-install-main: compiling + installing main in background -> $log" >&2
exit 0