v0.7.4: drop GitHub fallback from auto-update (single-source Gitea)

The v0.7.2 GitHub fallback is now functionally broken: the GitHub mirror
is being made private, so anonymous raw fetches return 401/403.  Rather
than ship a silent-failure path to a dead URL, remove the fallback
entirely.

Changes:
  larry.sh
    - LARRY_BASE_URL_FALLBACK / LARRY_ORIGIN_DEFAULT_GITHUB removed
    - sync_from_manifest_with_fallback and _fetch_with_fallback retained
      by name (call-site compat) but are now single-source wrappers; on
      origin unreachable they warn "auto-update skipped this launch" and
      proceed with locally cached files (no crash)
    - status-line _origin_badge collapses to "" (default) or "custom"
      (user-pinned HTTPS URL); legacy github / fallback badges gone
    - /origin slash command simplified:
        /origin              show effective origin + pin file
        /origin gitea        pin to the default Gitea URL
        /origin auto         clear the pin
        /origin <https-url>  pin to an arbitrary HTTPS mirror
        /origin github       returns a clear error (mirror is private)
    - /help text updated to reflect single-source model
    - LARRY_VERSION 0.7.3 -> 0.7.4

  install-larry.sh
    - LARRY_BASE_URL_FALLBACK removed; single-origin install path
    - fetch() dies with a clear error when origin unreachable:
      "install failed: cannot reach LARRY_BASE_URL=... — verify the URL
       or set LARRY_BASE_URL to a reachable mirror"
    - post-install fallback-warning block removed

  VERSION: 0.7.3 -> 0.7.4

Migration: stale $LARRY_HOME/.origin files containing the legacy keyword
"github" are treated as invalid — Larry warns once at startup and reverts
to the default Gitea origin.  We deliberately do NOT auto-rewrite the
file (so the user can choose) and do NOT translate it to the GitHub raw
URL (which would just 401 on the next fetch).

Verification:
  - bash -n larry.sh / install-larry.sh: pass
  - larry --version: prints 0.7.4
  - LARRY_BASE_URL=https://invalid.example.invalid + stale .last-sync-version:
    logs "warn: ... unreachable, auto-update skipped this launch", no crash
  - /origin auto clears pin file; /origin (no arg) shows current effective
    origin and pin file; /origin <https-url> persisted; /origin github
    returns clear error; /origin gitea re-pins to default
  - stale .origin containing "github" -> startup warn + revert to default

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Bryan Johnson 2026-05-27 18:07:53 -07:00
parent 58e6bf4e03
commit 6a12c3d0f9
3 changed files with 102 additions and 147 deletions

View File

@ -1 +1 @@
0.7.3 0.7.4

View File

@ -15,16 +15,16 @@
set -eu set -eu
LARRY_HOME="${LARRY_HOME:-$HOME/.larry}" LARRY_HOME="${LARRY_HOME:-$HOME/.larry}"
# Canonical hosting (v0.7.2+): self-hosted Gitea at git.bjnoela.com is primary; # Canonical hosting (v0.7.4): self-hosted Gitea at git.bjnoela.com is the
# bojj27/cloverleaf-larry on GitHub is the unauthenticated fallback used when # single source. The v0.7.2 GitHub fallback was removed after the GitHub
# Gitea is unreachable (DNS failure, repo set to private, server down, etc.). # mirror was made private (anonymous raw fetches now 401/403, so the
# Override either via env if you fork or mirror elsewhere. # fallback was functionally broken). Override LARRY_BASE_URL via env if you
# fork or mirror elsewhere.
# #
# IMPORTANT: the Gitea repo must be set to PUBLIC for unauthenticated raw-URL # IMPORTANT: the Gitea repo must be PUBLIC for unauthenticated raw-URL reads
# reads to succeed. Until Bryan toggles repo visibility, the installer (and # to succeed. If the install fetch fails, set LARRY_BASE_URL to a reachable
# auto-update) will silently fall back to GitHub. # mirror or check repo visibility on git.bjnoela.com.
LARRY_BASE_URL="${LARRY_BASE_URL:-https://git.bjnoela.com/bryan/cloverleaf-larry/raw/branch/main}" LARRY_BASE_URL="${LARRY_BASE_URL:-https://git.bjnoela.com/bryan/cloverleaf-larry/raw/branch/main}"
LARRY_BASE_URL_FALLBACK="${LARRY_BASE_URL_FALLBACK:-https://raw.githubusercontent.com/bojj27/cloverleaf-larry/main}"
LARRY_BIN_DIR="${LARRY_BIN_DIR:-$HOME/bin}" LARRY_BIN_DIR="${LARRY_BIN_DIR:-$HOME/bin}"
C_RESET=$'\033[0m'; C_BOLD=$'\033[1m'; C_GREEN=$'\033[32m' C_RESET=$'\033[0m'; C_BOLD=$'\033[1m'; C_GREEN=$'\033[32m'
@ -76,34 +76,21 @@ ok "created $LARRY_HOME"
# ───────────────────────────────────────────────────────────────────────────── # ─────────────────────────────────────────────────────────────────────────────
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" 2>/dev/null && pwd)" || SCRIPT_DIR="" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" 2>/dev/null && pwd)" || SCRIPT_DIR=""
# v0.7.2: install-larry.sh is the FIRST contact with the origin — it runs # v0.7.4 single-source: install-larry.sh is the FIRST contact with the
# before larry.sh exists, so it has to do its own primary→fallback dance. # origin — it runs before larry.sh exists, so it must succeed in one shot.
# Mirrors larry.sh's _fetch_with_fallback behavior; on every fetch, try # No fallback; if $LARRY_BASE_URL is unreachable we die with a clear error
# primary first, then fallback if the primary curl exits non-zero or the # telling the user to verify the URL or set an alternate mirror.
# resulting file is empty. Records the winning origin in $LAST_FETCH_ORIGIN
# so the post-install summary can tell Bryan which side served the install.
LAST_FETCH_ORIGIN=""
fetch() { fetch() {
# $1 = remote relative path, $2 = local destination # $1 = remote relative path, $2 = local destination
if [ -n "$LARRY_BASE_URL" ]; then if [ -n "$LARRY_BASE_URL" ]; then
say "fetching $1" say "fetching $1"
if curl -fsSL --max-time 30 "$LARRY_BASE_URL/$1" -o "$2" 2>/dev/null && [ -s "$2" ]; then if curl -fsSL --max-time 30 "$LARRY_BASE_URL/$1" -o "$2" 2>/dev/null && [ -s "$2" ]; then
LAST_FETCH_ORIGIN="primary"
ok "$2" ok "$2"
return 0 return 0
fi fi
rm -f "$2" rm -f "$2"
if [ -n "${LARRY_BASE_URL_FALLBACK:-}" ] && [ "$LARRY_BASE_URL_FALLBACK" != "$LARRY_BASE_URL" ]; then die "install failed: cannot reach LARRY_BASE_URL=$LARRY_BASE_URL (fetching $1) — verify the URL or set LARRY_BASE_URL to a reachable mirror"
warn "primary unreachable for $1 — trying fallback"
if curl -fsSL --max-time 30 "$LARRY_BASE_URL_FALLBACK/$1" -o "$2" 2>/dev/null && [ -s "$2" ]; then
LAST_FETCH_ORIGIN="fallback"
ok "$2 (via fallback)"
return 0
fi
rm -f "$2"
fi
die "failed to fetch $1 from primary or fallback"
elif [ -n "$SCRIPT_DIR" ] && [ -f "$SCRIPT_DIR/$1" ]; then elif [ -n "$SCRIPT_DIR" ] && [ -f "$SCRIPT_DIR/$1" ]; then
cp "$SCRIPT_DIR/$1" "$2" && ok "copied $1 (local)" cp "$SCRIPT_DIR/$1" "$2" && ok "copied $1 (local)"
else else
@ -210,12 +197,7 @@ fi
# ───────────────────────────────────────────────────────────────────────────── # ─────────────────────────────────────────────────────────────────────────────
echo "" echo ""
say "install complete (no system changes were made; everything lives under $LARRY_HOME)" say "install complete (no system changes were made; everything lives under $LARRY_HOME)"
if [ "$LAST_FETCH_ORIGIN" = "fallback" ]; then say "origin (single-source, v0.7.4): $LARRY_BASE_URL"
warn "files were served from the FALLBACK origin (primary unreachable)."
warn " primary : $LARRY_BASE_URL"
warn " fallback: $LARRY_BASE_URL_FALLBACK"
warn " if you expected the primary to work, check repo visibility (Gitea repos default to private)."
fi
echo "" echo ""
echo "Next steps:" echo "Next steps:"
echo " 1) export ANTHROPIC_API_KEY=sk-ant-... (or larry will prompt on first run)" echo " 1) export ANTHROPIC_API_KEY=sk-ant-... (or larry will prompt on first run)"

201
larry.sh
View File

@ -11,17 +11,16 @@
# #
# Env vars: # Env vars:
# LARRY_HOME where to cache config/sessions (default: ~/.larry) # LARRY_HOME where to cache config/sessions (default: ~/.larry)
# LARRY_BASE_URL primary root URL of the bundle on the server (default # LARRY_BASE_URL root URL of the bundle on the server (default
# as of v0.7.2: https://git.bjnoela.com/bryan/cloverleaf-larry/raw/branch/main). # as of v0.7.4: https://git.bjnoela.com/bryan/cloverleaf-larry/raw/branch/main).
# Self-update pulls VERSION + MANIFEST from here and # Self-update pulls VERSION + MANIFEST from here and
# refreshes every file listed in MANIFEST. # refreshes every file listed in MANIFEST.
# LARRY_BASE_URL_FALLBACK # v0.7.4: single-source auto-update. The GitHub
# secondary root URL used if the primary is unreachable # fallback added in v0.7.2 was dropped after the GitHub
# (default: https://raw.githubusercontent.com/bojj27/cloverleaf-larry/main). # mirror was made private (anonymous raw fetches now
# v0.7.2: GitHub demoted from primary to fallback so the # 401/403, so the fallback was functionally broken).
# self-hosted Gitea origin (git.bjnoela.com) is the # Users can pin/override via the /origin slash command
# canonical source. Users can pin/override via the # (see $LARRY_HOME/.origin).
# /origin slash command (see $LARRY_HOME/.origin).
# LARRY_UPDATE_URL (legacy override) full URL of latest larry.sh # LARRY_UPDATE_URL (legacy override) full URL of latest larry.sh
# LARRY_AGENTS_URL (legacy override) base URL for agents/ # LARRY_AGENTS_URL (legacy override) base URL for agents/
# LARRY_MODEL Claude model (default: claude-sonnet-4-6) # LARRY_MODEL Claude model (default: claude-sonnet-4-6)
@ -54,42 +53,48 @@ set -o pipefail
# ───────────────────────────────────────────────────────────────────────────── # ─────────────────────────────────────────────────────────────────────────────
# Config # Config
# ───────────────────────────────────────────────────────────────────────────── # ─────────────────────────────────────────────────────────────────────────────
LARRY_VERSION="0.7.3" LARRY_VERSION="0.7.4"
LARRY_HOME="${LARRY_HOME:-$HOME/.larry}" LARRY_HOME="${LARRY_HOME:-$HOME/.larry}"
# ───────────────────────────────────────────────────────────────────────────── # ─────────────────────────────────────────────────────────────────────────────
# Origin defaults (v0.7.2). Gitea is primary; GitHub is fallback. # Origin defaults (v0.7.4 — single-source).
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# The /origin slash-command family (see dispatcher below) lets the user pin # v0.7.2 introduced a Gitea-primary, GitHub-fallback model. v0.7.4 drops the
# either origin or supply a custom URL. Persisted pins live at # fallback: the GitHub mirror was made private, so anonymous raw-URL reads
# $LARRY_HOME/.origin and are applied just below. Env-var overrides still win # now 401/403 — the fallback path was a silent failure waiting to happen.
# over the pinned file (mirroring how LARRY_HOME / LARRY_MODEL etc. behave). # Auto-update is now single-source (Gitea). If Gitea is unreachable the
# client keeps running on the locally cached files and tries again next
# launch. The Gitea push-mirror still fans changes out to GitHub for
# read-only public consumption.
# #
# IMPORTANT: the Gitea repo (git.bjnoela.com/bryan/cloverleaf-larry) MUST be # The /origin slash-command family (see dispatcher below) lets the user pin
# set to PUBLIC for unauthenticated raw-URL reads to succeed. Until then the # a custom URL. Persisted pins live at $LARRY_HOME/.origin and are applied
# fallback path (GitHub) carries all real auto-update traffic. # just below. Env-var overrides still win over the pinned file (mirroring
# how LARRY_HOME / LARRY_MODEL etc. behave).
#
# Migration: stale .origin files containing the legacy keyword "github" are
# treated as invalid (warn + revert to default). Translating to the GitHub
# raw URL would just trip a 401/403 on the next fetch.
# ───────────────────────────────────────────────────────────────────────────── # ─────────────────────────────────────────────────────────────────────────────
LARRY_ORIGIN_DEFAULT_GITEA="https://git.bjnoela.com/bryan/cloverleaf-larry/raw/branch/main" LARRY_ORIGIN_DEFAULT_GITEA="https://git.bjnoela.com/bryan/cloverleaf-larry/raw/branch/main"
LARRY_ORIGIN_DEFAULT_GITHUB="https://raw.githubusercontent.com/bojj27/cloverleaf-larry/main"
# Resolve a pinned origin file BEFORE applying env-var defaults so the env # Resolve a pinned origin file BEFORE applying env-var defaults so the env
# overrides still take precedence. $LARRY_HOME may not exist yet on first # overrides still take precedence. $LARRY_HOME may not exist yet on first
# launch — guard accordingly. # launch — guard accordingly.
_larry_pin_primary="" _larry_pin_primary=""
_larry_pin_fallback=""
if [ -r "$LARRY_HOME/.origin" ]; then if [ -r "$LARRY_HOME/.origin" ]; then
_larry_pin_raw=$(tr -d '[:space:]' < "$LARRY_HOME/.origin" 2>/dev/null) _larry_pin_raw=$(tr -d '[:space:]' < "$LARRY_HOME/.origin" 2>/dev/null)
case "$_larry_pin_raw" in case "$_larry_pin_raw" in
gitea) gitea)
_larry_pin_primary="$LARRY_ORIGIN_DEFAULT_GITEA" _larry_pin_primary="$LARRY_ORIGIN_DEFAULT_GITEA" ;;
_larry_pin_fallback="$LARRY_ORIGIN_DEFAULT_GITHUB" ;;
github) github)
# SWAP: github becomes primary, gitea fallback. # v0.7.4: GitHub is no longer a valid origin (repo went private).
_larry_pin_primary="$LARRY_ORIGIN_DEFAULT_GITHUB" # Warn and treat as no pin — caller will fall through to the Gitea
_larry_pin_fallback="$LARRY_ORIGIN_DEFAULT_GITEA" ;; # default below. We deliberately do NOT auto-rewrite the file; the
# user should re-run /origin explicitly.
printf 'warn: %s/.origin pins legacy "github" origin; the GitHub mirror is private as of v0.7.4. Reverting to default (gitea). Run /origin auto to clear the pin.\n' "$LARRY_HOME" >&2 ;;
https://*) https://*)
_larry_pin_primary="$_larry_pin_raw" _larry_pin_primary="$_larry_pin_raw" ;;
_larry_pin_fallback="$LARRY_ORIGIN_DEFAULT_GITEA" ;;
"") : ;; # empty file → treat as no pin "") : ;; # empty file → treat as no pin
*) *)
printf 'warn: ignoring unrecognised value in %s/.origin: %s\n' "$LARRY_HOME" "$_larry_pin_raw" >&2 ;; printf 'warn: ignoring unrecognised value in %s/.origin: %s\n' "$LARRY_HOME" "$_larry_pin_raw" >&2 ;;
@ -98,12 +103,12 @@ if [ -r "$LARRY_HOME/.origin" ]; then
fi fi
LARRY_BASE_URL="${LARRY_BASE_URL:-${_larry_pin_primary:-$LARRY_ORIGIN_DEFAULT_GITEA}}" LARRY_BASE_URL="${LARRY_BASE_URL:-${_larry_pin_primary:-$LARRY_ORIGIN_DEFAULT_GITEA}}"
LARRY_BASE_URL_FALLBACK="${LARRY_BASE_URL_FALLBACK:-${_larry_pin_fallback:-$LARRY_ORIGIN_DEFAULT_GITHUB}}" unset _larry_pin_primary
unset _larry_pin_primary _larry_pin_fallback
# Tracks which origin actually served the most recent self_update phase (set # Tracks which origin actually served the most recent self_update phase (set
# by sync_from_manifest / phase-B fetch). Read by /origin and the status # by sync_from_manifest / phase-B fetch). Read by /origin and the status
# line's optional origin badge. Values: "" (none yet), "primary", "fallback". # line's optional origin badge. In v0.7.4 the only non-empty value is
# "primary" (single-source); the slot is kept for status-line compatibility.
_LARRY_LAST_ORIGIN="" _LARRY_LAST_ORIGIN=""
_LARRY_LAST_ORIGIN_URL="" _LARRY_LAST_ORIGIN_URL=""
@ -326,27 +331,25 @@ fetch_agents_or_warn
# #
# Skip all of it via --no-update or LARRY_NO_UPDATE=1. # Skip all of it via --no-update or LARRY_NO_UPDATE=1.
# #
# v0.7.2: every network step (manifest fetch in phase A, VERSION + larry.sh # v0.7.4: single-source auto-update. Every network step (manifest fetch in
# fetch in phase B) tries $LARRY_BASE_URL first and transparently falls back # phase A, VERSION + larry.sh fetch in phase B) hits $LARRY_BASE_URL only.
# to $LARRY_BASE_URL_FALLBACK when the primary fails (curl exit non-zero, # If it's unreachable (curl exit non-zero, HTTP error, timeout, DNS failure)
# HTTP error, timeout, DNS failure). The label of whichever origin actually # the client logs a clear warn and proceeds with the locally cached files —
# served the last byte is recorded in $_LARRY_LAST_ORIGIN[_URL] so /origin # no silent failover to a now-private GitHub mirror.
# and the optional status-line badge can display it.
# ───────────────────────────────────────────────────────────────────────────── # ─────────────────────────────────────────────────────────────────────────────
# _origin_label URL — short label ("gitea", "github", or the URL itself) used # _origin_label URL — short label ("gitea" or the URL itself) used in
# in human-facing log lines. Pure string match — no network. # human-facing log lines. Pure string match — no network.
_origin_label() { _origin_label() {
case "$1" in case "$1" in
"$LARRY_ORIGIN_DEFAULT_GITEA") printf 'gitea' ;; "$LARRY_ORIGIN_DEFAULT_GITEA") printf 'gitea' ;;
"$LARRY_ORIGIN_DEFAULT_GITHUB") printf 'github' ;; *) printf '%s' "$1" ;;
*) printf '%s' "$1" ;;
esac esac
} }
# _record_origin SLOT URL — remember the origin (and its URL) that just # _record_origin SLOT URL — remember the origin (and its URL) that just
# served bytes. SLOT is "primary" or "fallback". Persists across the rest # served bytes. SLOT is always "primary" in v0.7.4 (single-source); the
# of the run so /origin and the status line can read it back. # slot arg is retained for status-line compatibility.
_record_origin() { _record_origin() {
_LARRY_LAST_ORIGIN="$1" _LARRY_LAST_ORIGIN="$1"
_LARRY_LAST_ORIGIN_URL="$2" _LARRY_LAST_ORIGIN_URL="$2"
@ -401,27 +404,23 @@ sync_from_manifest() {
return 0 return 0
} }
# sync_from_manifest_with_fallback — try primary then fallback. Returns 0 if # sync_from_manifest_with_fallback — v0.7.4 retains the historical name for
# either succeeded, non-zero if BOTH unreachable. Wraps sync_from_manifest. # call-site compatibility but is now a single-source wrapper around
# sync_from_manifest. Returns 0 on success, non-zero if $LARRY_BASE_URL is
# unreachable (no silent failover — auto-update is just skipped this launch).
sync_from_manifest_with_fallback() { sync_from_manifest_with_fallback() {
if sync_from_manifest "$LARRY_BASE_URL"; then if sync_from_manifest "$LARRY_BASE_URL"; then
_record_origin primary "$LARRY_BASE_URL" _record_origin primary "$LARRY_BASE_URL"
return 0 return 0
fi fi
if [ -n "$LARRY_BASE_URL_FALLBACK" ] && [ "$LARRY_BASE_URL_FALLBACK" != "$LARRY_BASE_URL" ]; then warn "$(_origin_label "$LARRY_BASE_URL") unreachable, auto-update skipped this launch"
warn "$(_origin_label "$LARRY_BASE_URL") unreachable, falling back to $(_origin_label "$LARRY_BASE_URL_FALLBACK")"
if sync_from_manifest "$LARRY_BASE_URL_FALLBACK"; then
_record_origin fallback "$LARRY_BASE_URL_FALLBACK"
return 0
fi
fi
warn "self-update skipped (both origins unreachable)"
return 1 return 1
} }
# _fetch_with_fallback REL_PATH DEST [MAX_TIME] — curl with primary→fallback # _fetch_with_fallback REL_PATH DEST [MAX_TIME] — v0.7.4 single-source fetch
# retry. Returns 0 if either pulled a non-empty file, non-zero otherwise. # (name kept for call-site compatibility). Returns 0 if the file pulled
# Records the winning origin slot in $_LARRY_LAST_ORIGIN. # non-empty, non-zero otherwise. Records the winning origin slot in
# $_LARRY_LAST_ORIGIN (always "primary" in single-source mode).
_fetch_with_fallback() { _fetch_with_fallback() {
local rel="$1" dest="$2" mt="${3:-15}" local rel="$1" dest="$2" mt="${3:-15}"
if curl -fsSL --max-time "$mt" "$LARRY_BASE_URL/$rel" -o "$dest" 2>/dev/null && [ -s "$dest" ]; then if curl -fsSL --max-time "$mt" "$LARRY_BASE_URL/$rel" -o "$dest" 2>/dev/null && [ -s "$dest" ]; then
@ -429,14 +428,6 @@ _fetch_with_fallback() {
return 0 return 0
fi fi
rm -f "$dest" rm -f "$dest"
if [ -n "$LARRY_BASE_URL_FALLBACK" ] && [ "$LARRY_BASE_URL_FALLBACK" != "$LARRY_BASE_URL" ]; then
if curl -fsSL --max-time "$mt" "$LARRY_BASE_URL_FALLBACK/$rel" -o "$dest" 2>/dev/null && [ -s "$dest" ]; then
warn "$(_origin_label "$LARRY_BASE_URL") unreachable for $rel, served from $(_origin_label "$LARRY_BASE_URL_FALLBACK")"
_record_origin fallback "$LARRY_BASE_URL_FALLBACK"
return 0
fi
rm -f "$dest"
fi
return 1 return 1
} }
@ -477,7 +468,7 @@ self_update() {
[ "${LARRY_JUST_UPDATED:-0}" = "1" ] && return 0 [ "${LARRY_JUST_UPDATED:-0}" = "1" ] && return 0
[ -w "$self" ] || return 0 [ -w "$self" ] || return 0
# VERSION fetch with primary→fallback. # VERSION fetch (single-source; v0.7.4).
local ver_tmp="$LARRY_HOME/.VERSION.new" remote_ver="" local ver_tmp="$LARRY_HOME/.VERSION.new" remote_ver=""
if _fetch_with_fallback "VERSION" "$ver_tmp" 5; then if _fetch_with_fallback "VERSION" "$ver_tmp" 5; then
remote_ver=$(tr -d '[:space:]' < "$ver_tmp" 2>/dev/null) remote_ver=$(tr -d '[:space:]' < "$ver_tmp" 2>/dev/null)
@ -2171,33 +2162,19 @@ _render_status_line_apikey() {
"$C_DIM" "$ctx" "$dollars" "$_LARRY_TURNS" "$C_RESET" "$badge" "$C_DIM" "$ctx" "$dollars" "$_LARRY_TURNS" "$C_RESET" "$badge"
} }
# _origin_badge — light-touch v0.7.2 status-line segment. Returns a leading # _origin_badge — status-line segment (v0.7.4 single-source). Returns a
# space + colored fragment when the origin is non-default, otherwise empty. # leading space + colored fragment when the origin is non-default, otherwise
# Default = on defaults AND last-served by primary (or never served yet). # empty. Badge values:
# "" on the default Gitea origin (no pin, no env override)
# "custom" pinned to a user-supplied HTTPS URL via /origin <url>
# The legacy "github" pin and the gitea→github fallback indicator are gone
# in v0.7.4 (the fallback no longer exists).
_origin_badge() { _origin_badge() {
# Suppress on default state.
local pinned="" local pinned=""
[ -r "$LARRY_HOME/.origin" ] && pinned=$(tr -d '[:space:]' < "$LARRY_HOME/.origin" 2>/dev/null) [ -r "$LARRY_HOME/.origin" ] && pinned=$(tr -d '[:space:]' < "$LARRY_HOME/.origin" 2>/dev/null)
if [ -z "$pinned" ] && { [ -z "$_LARRY_LAST_ORIGIN" ] || [ "$_LARRY_LAST_ORIGIN" = "primary" ]; }; then
return 0
fi
# Pinned to github → " github" (dim).
if [ "$pinned" = "github" ]; then
printf ' %sgithub%s' "$C_DIM" "$C_RESET"
return 0
fi
# Pinned to a custom URL → " custom".
case "$pinned" in case "$pinned" in
https://*) printf ' %scustom%s' "$C_DIM" "$C_RESET"; return 0 ;; https://*) printf ' %scustom%s' "$C_DIM" "$C_RESET"; return 0 ;;
esac esac
# Failed over from gitea→github (or other primary→fallback).
if [ "$_LARRY_LAST_ORIGIN" = "fallback" ]; then
printf ' %s%s→%s%s' "$C_RED$C_DIM" \
"$(_origin_label "$LARRY_BASE_URL")" \
"$(_origin_label "$LARRY_BASE_URL_FALLBACK")" \
"$C_RESET"
return 0
fi
return 0 return 0
} }
@ -3214,16 +3191,16 @@ Slash commands:
/hl7-fields <SEG.FIELD> print component breakdown for a field /hl7-fields <SEG.FIELD> print component breakdown for a field
(e.g. /hl7-fields PID.5 → Family, Given, ...) (e.g. /hl7-fields PID.5 → Family, Given, ...)
Auto-update origin (v0.7.2): Auto-update origin (v0.7.4 — single-source):
/origin show current primary + fallback + which /origin show current effective origin (pin or default)
served the last self-update /origin gitea pin to git.bjnoela.com (the default Gitea URL)
/origin gitea pin to git.bjnoela.com (default primary) /origin auto clear the pin (revert to default)
/origin github pin to GitHub raw (swap: github→primary)
/origin auto clear the pin (revert to gitea primary,
github fallback)
/origin <https://...> pin to an arbitrary HTTPS base URL /origin <https://...> pin to an arbitrary HTTPS base URL
(useful for air-gapped mirrors / testing) (useful for air-gapped mirrors / testing)
Pin is persisted to \$LARRY_HOME/.origin and re-read on next launch. Pin is persisted to \$LARRY_HOME/.origin and re-read on next launch.
Note: the v0.7.2 GitHub fallback was removed in v0.7.4 — the GitHub mirror
is private, so anonymous raw fetches no longer work. If Gitea is
unreachable, auto-update is skipped and you keep running on cached files.
Mouse mode (v0.7.0): Mouse mode (v0.7.0):
/mouse on|off toggle xterm mouse + bracketed-paste for the /mouse on|off toggle xterm mouse + bracketed-paste for the
@ -3464,7 +3441,7 @@ _LARRY_SLASH_CMDS_DESC=(
[/hl7]="<SEGMENT> print full field list for an HL7 segment (e.g. /hl7 PID)" [/hl7]="<SEGMENT> print full field list for an HL7 segment (e.g. /hl7 PID)"
[/hl7-fields]="<SEG.FIELD> print component breakdown (e.g. /hl7-fields PID.5)" [/hl7-fields]="<SEG.FIELD> print component breakdown (e.g. /hl7-fields PID.5)"
[/mouse]="on|off toggle xterm mouse mode for this session" [/mouse]="on|off toggle xterm mouse mode for this session"
[/origin]="show/pin auto-update origin (gitea|github|auto|<https URL>)" [/origin]="show/pin auto-update origin (gitea|auto|<https URL>) — v0.7.4 single-source"
[/phi-auto]="on|off|confirm|status — runtime control for v0.7.3 auto PHI detection" [/phi-auto]="on|off|confirm|status — runtime control for v0.7.3 auto PHI detection"
) )
@ -4207,33 +4184,31 @@ main_loop() {
continue ;; continue ;;
# v0.7.0: mouse mode toggle (xterm SGR mouse + bracketed paste). # v0.7.0: mouse mode toggle (xterm SGR mouse + bracketed paste).
/origin|/origin\ *) /origin|/origin\ *)
# v0.7.2: show/pin the auto-update origin. Pin is persisted # v0.7.4 single-source: show/pin the auto-update origin.
# to $LARRY_HOME/.origin and re-read on the NEXT launch (the # Pin is persisted to $LARRY_HOME/.origin and re-read on the
# current run keeps using the resolved $LARRY_BASE_URL). # NEXT launch (the current run keeps using the resolved
# $LARRY_BASE_URL). The GitHub fallback was dropped — the
# "github" keyword is no longer valid (private mirror).
local _arg; _arg=$(_slash_args "/origin" "$input") local _arg; _arg=$(_slash_args "/origin" "$input")
case "${_arg:-status}" in case "${_arg:-status}" in
status) status)
printf '%sauto-update origin:%s\n' "$C_BOLD" "$C_RESET" printf '%sauto-update origin:%s\n' "$C_BOLD" "$C_RESET"
printf ' %sprimary :%s %s %s(%s)%s\n' \ printf ' %seffective:%s %s %s(%s)%s\n' \
"$C_BOLD" "$C_RESET" "$LARRY_BASE_URL" \ "$C_BOLD" "$C_RESET" "$LARRY_BASE_URL" \
"$C_DIM" "$(_origin_label "$LARRY_BASE_URL")" "$C_RESET" "$C_DIM" "$(_origin_label "$LARRY_BASE_URL")" "$C_RESET"
printf ' %sfallback:%s %s %s(%s)%s\n' \ if [ -n "$_LARRY_LAST_ORIGIN_URL" ]; then
"$C_BOLD" "$C_RESET" "$LARRY_BASE_URL_FALLBACK" \ printf ' %slast served by:%s %s\n' \
"$C_DIM" "$(_origin_label "$LARRY_BASE_URL_FALLBACK")" "$C_RESET" "$C_BOLD" "$C_RESET" "$(_origin_label "$_LARRY_LAST_ORIGIN_URL")"
if [ -n "$_LARRY_LAST_ORIGIN" ]; then
printf ' %slast served by:%s %s %s(%s)%s\n' \
"$C_BOLD" "$C_RESET" "$_LARRY_LAST_ORIGIN" \
"$C_DIM" "$(_origin_label "$_LARRY_LAST_ORIGIN_URL")" "$C_RESET"
else else
printf ' %slast served by:%s %s(self-update did not run this session)%s\n' \ printf ' %slast served by:%s %s(self-update did not run this session)%s\n' \
"$C_BOLD" "$C_RESET" "$C_DIM" "$C_RESET" "$C_BOLD" "$C_RESET" "$C_DIM" "$C_RESET"
fi fi
if [ -r "$LARRY_HOME/.origin" ]; then if [ -r "$LARRY_HOME/.origin" ]; then
printf ' %spin file :%s %s/.origin → %s\n' \ printf ' %spin file :%s %s/.origin → %s\n' \
"$C_BOLD" "$C_RESET" "$LARRY_HOME" \ "$C_BOLD" "$C_RESET" "$LARRY_HOME" \
"$(tr -d '[:space:]' < "$LARRY_HOME/.origin" 2>/dev/null)" "$(tr -d '[:space:]' < "$LARRY_HOME/.origin" 2>/dev/null)"
else else
printf ' %spin file :%s %s(none — using defaults)%s\n' \ printf ' %spin file :%s %s(none — using default)%s\n' \
"$C_BOLD" "$C_RESET" "$C_DIM" "$C_RESET" "$C_BOLD" "$C_RESET" "$C_DIM" "$C_RESET"
fi fi
;; ;;
@ -4243,26 +4218,24 @@ main_loop() {
|| err "could not write $LARRY_HOME/.origin" || err "could not write $LARRY_HOME/.origin"
;; ;;
github) github)
printf 'github\n' > "$LARRY_HOME/.origin" 2>/dev/null \ err "/origin github is no longer supported in v0.7.4 — the GitHub mirror is private. Use /origin gitea or /origin <https://...URL>."
&& larry_say "pinned origin: github ($LARRY_ORIGIN_DEFAULT_GITHUB) — SWAP, github becomes primary, gitea fallback. Restart larry to apply." \
|| err "could not write $LARRY_HOME/.origin"
;; ;;
auto) auto)
if [ -f "$LARRY_HOME/.origin" ]; then if [ -f "$LARRY_HOME/.origin" ]; then
rm -f "$LARRY_HOME/.origin" \ rm -f "$LARRY_HOME/.origin" \
&& larry_say "pin cleared. Restart larry to revert to defaults (gitea primary, github fallback)." \ && larry_say "pin cleared. Restart larry to revert to the default (gitea)." \
|| err "could not remove $LARRY_HOME/.origin" || err "could not remove $LARRY_HOME/.origin"
else else
larry_say "no pin in place; already on defaults." larry_say "no pin in place; already on the default."
fi fi
;; ;;
https://*) https://*)
printf '%s\n' "$_arg" > "$LARRY_HOME/.origin" 2>/dev/null \ printf '%s\n' "$_arg" > "$LARRY_HOME/.origin" 2>/dev/null \
&& larry_say "pinned origin: $_arg (gitea kept as fallback). Restart larry to apply." \ && larry_say "pinned origin: $_arg. Restart larry to apply." \
|| err "could not write $LARRY_HOME/.origin" || err "could not write $LARRY_HOME/.origin"
;; ;;
*) *)
err "usage: /origin [gitea|github|auto|<https://...URL>] (no arg → status)" err "usage: /origin [gitea|auto|<https://...URL>] (no arg → status)"
;; ;;
esac esac
continue ;; continue ;;