Release: Issues+Systems, milestone-as-plan, plugin reliability/skills/dedup, compaction hygiene #71

Merged
bvandeusen merged 25 commits from dev into main 2026-06-14 15:51:44 -04:00
Showing only changes of commit 700cfc664b - Show all commits
+22 -15
View File
@@ -23,16 +23,22 @@
# vars above are the supported channel; SCRIBE_URL / SCRIBE_TOKEN override for
# the settings.json dogfooding path.
#
# FAIL-OPEN: the dynamic tier injects nothing on any error; the static tier
# still fires. A session is never blocked by Scribe.
# FAIL-OPEN, BUT NOT SILENT: the dynamic tier never blocks a session. A *failed*
# dynamic fetch is surfaced as a short status line (not swallowed), so a session
# can tell "couldn't load live context" apart from "Scribe had nothing to say".
# A fully unconfigured install (no url AND no token) is the intended static-only
# mode and stays quiet.
set -uo pipefail
command -v jq >/dev/null 2>&1 || exit 0 # needed to emit the JSON envelope safely
here=$(CDPATH= cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd) || exit 0
# --- Tier 1: static behavioral mandate (always, keyless, networkless) ---
out=""
# Append $1 to $out, separated by a horizontal rule when $out already has content.
append() { if [ -n "$out" ]; then out="${out}"$'\n\n---\n\n'"$1"; else out="$1"; fi; }
# --- Tier 1: static behavioral mandate (always, keyless, networkless) ---
[ -f "$here/scribe_static_context.md" ] && out=$(cat "$here/scribe_static_context.md")
# --- Tier 2: dynamic rules + active-project context (best-effort) ---
@@ -44,7 +50,9 @@ token=${SCRIBE_TOKEN:-${CLAUDE_PLUGIN_OPTION_api_token:-}}
case "$url" in *'${'*) url="" ;; esac
case "$token" in *'${'*) token="" ;; esac
if command -v curl >/dev/null 2>&1 && [ -n "$url" ] && [ -n "$token" ]; then
dyn=""
status=""
if [ -n "$url" ] && [ -n "$token" ] && command -v curl >/dev/null 2>&1; then
# Resolve the working repo's remote so the server can map it to a project.
repo_dir=${CLAUDE_PROJECT_DIR:-$PWD}
repo=$(git -C "$repo_dir" remote get-url origin 2>/dev/null || true)
@@ -56,19 +64,18 @@ if command -v curl >/dev/null 2>&1 && [ -n "$url" ] && [ -n "$token" ]; then
body=$(curl -fsS --max-time 8 \
-H "Authorization: Bearer ${token}" \
"${url%/}/api/plugin/context${q}" 2>/dev/null) || body=""
if [ -n "$body" ]; then
dyn=$(printf '%s' "$body" | jq -r '.context // empty' 2>/dev/null) || dyn=""
if [ -n "$dyn" ]; then
if [ -n "$out" ]; then
out="${out}"$'\n\n---\n\n'"${dyn}"
else
out="$dyn"
fi
fi
fi
[ -n "$body" ] && dyn=$(printf '%s' "$body" | jq -r '.context // empty' 2>/dev/null)
[ -z "$dyn" ] && status="> ⚠️ Scribe: live rules/project context could not be loaded this session (instance unreachable or request failed). The standing guidance above still applies — pull rules with \`list_always_on_rules()\` and project context with \`enter_project()\` as needed."
elif [ -n "$url" ] && [ -z "$token" ]; then
# Endpoint configured but token absent: the signature of the known Claude Code
# userConfig export gap (sensitive values not always reaching the hook).
status="> ⚠️ Scribe: live context disabled this session — the API token did not reach this hook (a known Claude Code plugin-config gap). Tools still work; pull rules with \`list_always_on_rules()\` and project context with \`enter_project()\`."
fi
# Nothing to inject (no static file AND no dynamic context) → stay silent.
[ -n "$dyn" ] && append "$dyn"
[ -n "$status" ] && append "$status"
# Nothing at all to inject (no static file, no dynamic context, no status) → stay silent.
[ -n "$out" ] || exit 0
jq -n --arg c "$out" \