mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-17 10:25:33 +02:00
fix(hooks): partial upgrades fail closed for freeze and fall back for careful
A hook script and its sourced helper can be copied at different times. With
an older careful/bin/hook-extract.sh that lacks gstack_hook_state_root:
- check-freeze.sh now emits a deny ("fail closed, re-run ./setup or
/unfreeze") instead of dying under set -e with no decision JSON.
- check-careful.sh falls back to ${GSTACK_HOME:-$HOME/.gstack} so project
rules under the plain chain still load and a decision is always emitted
(a warn hook must never break on a stale helper).
gstack_hook_state_root prints its root without a trailing newline and both
callers capture it with a printf-x sentinel, so a GSTACK_HOME ending in a
newline round-trips byte-for-byte with the writer's %q form.
gstack_hook_log_fire stays on ${GSTACK_HOME:-$HOME/.gstack}/analytics, the
same two-step chain every other analytics writer and reader uses, so the
usage log remains one file under a plugin install.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
29237ff9a8
commit
b8d347df35
@@ -265,7 +265,15 @@ fi
|
||||
# ERE per line; blank lines and #-comments skipped; an invalid regex is
|
||||
# skipped (never fatal — the hook must not break on a typo in config).
|
||||
if [ -z "$WARN" ]; then
|
||||
_GSTACK_HOME_DIR="${GSTACK_HOME:-$HOME/.gstack}"
|
||||
# Same state root the writer (/careful via gstack-paths) uses — see
|
||||
# gstack_hook_state_root in hook-extract.sh (#1459 class).
|
||||
if command -v gstack_hook_state_root >/dev/null 2>&1; then
|
||||
_GSTACK_HOME_DIR="$(gstack_hook_state_root; printf x)"; _GSTACK_HOME_DIR="${_GSTACK_HOME_DIR%x}"
|
||||
else
|
||||
# Older hook-extract.sh (partial upgrade): the plain chain beats dying
|
||||
# under set -e with no decision JSON — rules under $HOME/.gstack still load.
|
||||
_GSTACK_HOME_DIR="${GSTACK_HOME:-$HOME/.gstack}"
|
||||
fi
|
||||
_PATTERN_FILES="$_GSTACK_HOME_DIR/careful-patterns.txt"
|
||||
# Short-circuit: resolving the project slug costs a subprocess + git call on
|
||||
# EVERY Bash command while /careful is active — only pay it when some
|
||||
|
||||
@@ -73,25 +73,31 @@ gstack_hook_decision() {
|
||||
# /guard, /unfreeze, /investigate) resolve through gstack-paths; a reader that
|
||||
# used a different chain failed OPEN whenever GSTACK_HOME was set (#1459).
|
||||
# test/hook-scripts.test.ts pins parity against gstack-paths.
|
||||
# Printed WITHOUT a trailing newline: callers capture with a sentinel
|
||||
# (`r="$(gstack_hook_state_root; printf x)"; r="${r%x}"`) so a root that
|
||||
# itself ends in a newline round-trips exactly as gstack-paths' %q does —
|
||||
# otherwise writer and reader would again disagree on the directory.
|
||||
gstack_hook_state_root() {
|
||||
if [ -n "${GSTACK_HOME:-}" ]; then
|
||||
printf '%s\n' "$GSTACK_HOME"
|
||||
printf '%s' "$GSTACK_HOME"
|
||||
elif [ -n "${CLAUDE_PLUGIN_DATA:-}" ] && printf '%s' "${CLAUDE_PLUGIN_ROOT:-}" | grep -qi "gstack"; then
|
||||
printf '%s\n' "$CLAUDE_PLUGIN_DATA"
|
||||
printf '%s' "$CLAUDE_PLUGIN_DATA"
|
||||
elif [ -n "${HOME:-}" ]; then
|
||||
printf '%s\n' "$HOME/.gstack"
|
||||
printf '%s' "$HOME/.gstack"
|
||||
else
|
||||
printf '%s\n' ".gstack"
|
||||
printf '%s' ".gstack"
|
||||
fi
|
||||
}
|
||||
|
||||
# gstack_hook_log_fire SKILL PATTERN
|
||||
# Append a hook_fire analytics record (pattern name only, never command
|
||||
# content). Resolves the state root through gstack_hook_state_root so tests
|
||||
# never pollute the operator's real analytics file. Best-effort: failures
|
||||
# never affect the hook decision.
|
||||
# content). Respects GSTACK_HOME so tests never pollute the operator's real
|
||||
# analytics file. Deliberately NOT gstack_hook_state_root: every other
|
||||
# analytics writer and reader (gstack-skill-start, gstack-retro-metrics,
|
||||
# gstack-analytics) uses this two-step chain, and the usage log must stay one
|
||||
# file. Best-effort: failures never affect the hook decision.
|
||||
gstack_hook_log_fire() {
|
||||
_ghlf_dir="$(gstack_hook_state_root)/analytics"
|
||||
_ghlf_dir="${GSTACK_HOME:-$HOME/.gstack}/analytics"
|
||||
mkdir -p "$_ghlf_dir" 2>/dev/null || true
|
||||
# Fields are JSON-encoded (a repo basename can carry quotes/backslashes) —
|
||||
# same rule this file states for decisions: never raw-interpolate into JSON.
|
||||
|
||||
Reference in New Issue
Block a user