stacker: fix PR file-diff links + unify slot release lifecycle
The stack-block renderer was emitting `<sha>..<sha>` Files-changed URLs
(empty diffs) whenever a branch had local commits since init/sync, and
generating 404s for root branches off trunk because the trunk SHA isn't
in the PR's commit graph. Read the live branch ref via a new
`live_heads` map populated from the canonical repo, and emit
`<pr>/files` (no range) for trunk-rooted branches — same shape universe
gitstack's `get_diff_link` produces.
Replace the per-callsite ad-hoc release with a single
`release_if_clean` predicate (worktree has no `tracked_changes` or
`CHERRY_PICK_HEAD`) and an `acquired_for_op` context manager so
push/sync/absorb release the slot uniformly on success, exception, and
KeyboardInterrupt. `ops_slot.acquire` widens its except clause to
`BaseException` so a Ctrl+C between the pool claim and the caller's
try/finally no longer orphans the slot. The cherry-pick driver gets an
outer try/finally + a guard around `advance_downstream` so an interrupt
mid-queue still hands the in-flight slot back. `slot.resolve_slot`
falls back to cwd-reuse when the pool is exhausted, so a user sitting
in a slot of the same repo can still push without manually adding pool
capacity.
`pm check` splits stacker-owned slots into OPS_OWNED (mid-op, hold for
`pm stacker continue`) and STALE_OPS (clean worktree, leaked); `--fix`
releases the latter via the same `try_release_ops_slot` helper that
`release_if_clean` uses, so the dirty-check policy lives in one place.
The shared `git.detach_head` primitive replaces the open-coded
`git checkout --detach HEAD` in `ops_slot.release` and `ops/remove`.