mirror of https://github.com/garrytan/gstack.git
fix(setup): make plan-tune hook install non-interactive-safe
The plan-tune consent prompt used a blocking `read -r` with no timeout. Under a forwarded/automated TTY (conductor workspace setup, CI with a pty) it hung setup forever. Move the decision into flags + env + saved config with a smart default: --plan-tune-hooks / --no-plan-tune-hooks / --plan-tune-hooks=yes|no|prompt > GSTACK_PLAN_TUNE_HOOKS env > plan_tune_hooks config > prompt-on-real-TTY. Explicit yes/no act non-interactively. The remaining interactive branch is gated on a real (non-quiet) TTY and uses a time-bounded `read -t 10 </dev/tty` that defaults to skip, so it can never hang. A timeout no longer persists a decline marker, so a later hands-on run can still offer the install. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b1a068e332
commit
adbd609252
101
setup
101
setup
|
|
@ -82,6 +82,7 @@ SKILL_PREFIX=1
|
||||||
SKILL_PREFIX_FLAG=0
|
SKILL_PREFIX_FLAG=0
|
||||||
TEAM_MODE=0
|
TEAM_MODE=0
|
||||||
NO_TEAM_MODE=0
|
NO_TEAM_MODE=0
|
||||||
|
PLAN_TUNE_HOOKS_MODE="" # "" = resolve from env/config/prompt; "yes"/"no" = explicit
|
||||||
while [ $# -gt 0 ]; do
|
while [ $# -gt 0 ]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
--host) [ -z "$2" ] && echo "Missing value for --host (expected claude, codex, kiro, factory, opencode, openclaw, hermes, gbrain, or auto)" >&2 && exit 1; HOST="$2"; shift 2 ;;
|
--host) [ -z "$2" ] && echo "Missing value for --host (expected claude, codex, kiro, factory, opencode, openclaw, hermes, gbrain, or auto)" >&2 && exit 1; HOST="$2"; shift 2 ;;
|
||||||
|
|
@ -91,6 +92,9 @@ while [ $# -gt 0 ]; do
|
||||||
--no-prefix) SKILL_PREFIX=0; SKILL_PREFIX_FLAG=1; shift ;;
|
--no-prefix) SKILL_PREFIX=0; SKILL_PREFIX_FLAG=1; shift ;;
|
||||||
--team) TEAM_MODE=1; shift ;;
|
--team) TEAM_MODE=1; shift ;;
|
||||||
--no-team) NO_TEAM_MODE=1; shift ;;
|
--no-team) NO_TEAM_MODE=1; shift ;;
|
||||||
|
--plan-tune-hooks) PLAN_TUNE_HOOKS_MODE="yes"; shift ;;
|
||||||
|
--no-plan-tune-hooks) PLAN_TUNE_HOOKS_MODE="no"; shift ;;
|
||||||
|
--plan-tune-hooks=*) PLAN_TUNE_HOOKS_MODE="${1#--plan-tune-hooks=}"; shift ;;
|
||||||
-q|--quiet) QUIET=1; shift ;;
|
-q|--quiet) QUIET=1; shift ;;
|
||||||
*) shift ;;
|
*) shift ;;
|
||||||
esac
|
esac
|
||||||
|
|
@ -1304,14 +1308,60 @@ if [ "$NO_TEAM_MODE" -ne 1 ] \
|
||||||
ALREADY_INSTALLED=1
|
ALREADY_INSTALLED=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Resolve the desired action without ever blocking.
|
||||||
|
# Priority: CLI flag (--plan-tune-hooks / --no-plan-tune-hooks)
|
||||||
|
# > env (GSTACK_PLAN_TUNE_HOOKS=yes|no)
|
||||||
|
# > saved config (plan_tune_hooks)
|
||||||
|
# > smart default ("prompt" → timed prompt on a real TTY, else skip).
|
||||||
|
# This guarantees scripted/workspace setups (conductor, CI) are never
|
||||||
|
# interactive: pass --no-plan-tune-hooks (or --plan-tune-hooks) and the
|
||||||
|
# block runs to completion with no `read`.
|
||||||
|
PT_DECISION="$PLAN_TUNE_HOOKS_MODE"
|
||||||
|
[ -z "$PT_DECISION" ] && PT_DECISION="${GSTACK_PLAN_TUNE_HOOKS:-}"
|
||||||
|
[ -z "$PT_DECISION" ] && PT_DECISION="$("$GSTACK_CONFIG" get plan_tune_hooks 2>/dev/null || true)"
|
||||||
|
case "$PT_DECISION" in
|
||||||
|
y|yes|true|install) PT_DECISION="yes" ;;
|
||||||
|
n|no|false|skip) PT_DECISION="no" ;;
|
||||||
|
*) PT_DECISION="prompt" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
_install_plan_tune_hooks() {
|
||||||
|
"$SETTINGS_HOOK" add-event \
|
||||||
|
--event PostToolUse \
|
||||||
|
--matcher '(AskUserQuestion|mcp__.*__AskUserQuestion)' \
|
||||||
|
--command "$PLAN_TUNE_LOG_HOOK" \
|
||||||
|
--source plan-tune-cathedral \
|
||||||
|
--timeout 5
|
||||||
|
"$SETTINGS_HOOK" add-event \
|
||||||
|
--event PreToolUse \
|
||||||
|
--matcher '(AskUserQuestion|mcp__.*__AskUserQuestion)' \
|
||||||
|
--command "$PLAN_TUNE_PREF_HOOK" \
|
||||||
|
--source plan-tune-cathedral \
|
||||||
|
--timeout 5
|
||||||
|
}
|
||||||
|
|
||||||
if [ "$ALREADY_INSTALLED" -eq 1 ]; then
|
if [ "$ALREADY_INSTALLED" -eq 1 ]; then
|
||||||
log ""
|
log ""
|
||||||
log "Plan-tune hooks already installed. Run \`$SETTINGS_HOOK list-sources\` to inspect."
|
log "Plan-tune hooks already installed. Run \`$SETTINGS_HOOK list-sources\` to inspect."
|
||||||
|
elif [ "$PT_DECISION" = "yes" ]; then
|
||||||
|
# Explicit opt-in (flag / env / config). Non-interactive.
|
||||||
|
_install_plan_tune_hooks
|
||||||
|
log ""
|
||||||
|
log "Plan-tune hooks installed. Run /plan-tune anytime to inspect."
|
||||||
|
touch "$PLAN_TUNE_INSTALL_MARKER"
|
||||||
|
elif [ "$PT_DECISION" = "no" ]; then
|
||||||
|
# Explicit opt-out (flag / env / config). Non-interactive.
|
||||||
|
log ""
|
||||||
|
log "Plan-tune cathedral hooks not installed (opted out)."
|
||||||
|
log "Install later with: ./setup --plan-tune-hooks (or /update-config)."
|
||||||
|
touch "$PLAN_TUNE_INSTALL_MARKER"
|
||||||
elif [ -f "$PLAN_TUNE_INSTALL_MARKER" ]; then
|
elif [ -f "$PLAN_TUNE_INSTALL_MARKER" ]; then
|
||||||
# Previously declined. Don't re-ask. User can re-enable via /update-config.
|
# Previously declined. Don't re-ask. User can re-enable via /update-config.
|
||||||
:
|
:
|
||||||
elif [ -t 0 ] && [ -t 1 ]; then
|
elif [ "$QUIET" -ne 1 ] && [ -t 0 ] && [ -t 1 ]; then
|
||||||
# Interactive install with explicit consent + diff preview.
|
# Real interactive terminal with no recorded preference: ask, with explicit
|
||||||
|
# consent + diff preview. The read is time-bounded and defaults to "skip" so
|
||||||
|
# it can never hang an automated/forwarded TTY (the conductor failure mode).
|
||||||
log ""
|
log ""
|
||||||
log "──────────────────────────────────────────────────────────"
|
log "──────────────────────────────────────────────────────────"
|
||||||
log "Plan-tune cathedral: install Claude Code hooks?"
|
log "Plan-tune cathedral: install Claude Code hooks?"
|
||||||
|
|
@ -1336,33 +1386,32 @@ if [ "$NO_TEAM_MODE" -ne 1 ] \
|
||||||
log "Backup: settings.json.bak.<ts> written before any mutation."
|
log "Backup: settings.json.bak.<ts> written before any mutation."
|
||||||
log "Rollback: $SETTINGS_HOOK rollback"
|
log "Rollback: $SETTINGS_HOOK rollback"
|
||||||
log ""
|
log ""
|
||||||
printf "Install both hooks now? [y/N] "
|
printf "Install both hooks now? [y/N] (default: N, auto-skips in 10s): "
|
||||||
read -r PLAN_TUNE_INSTALL_REPLY
|
read -t 10 -r PLAN_TUNE_INSTALL_REPLY </dev/tty 2>/dev/null || PLAN_TUNE_INSTALL_REPLY=""
|
||||||
if [ "$PLAN_TUNE_INSTALL_REPLY" = "y" ] || [ "$PLAN_TUNE_INSTALL_REPLY" = "Y" ]; then
|
case "$PLAN_TUNE_INSTALL_REPLY" in
|
||||||
"$SETTINGS_HOOK" add-event \
|
y|Y)
|
||||||
--event PostToolUse \
|
_install_plan_tune_hooks
|
||||||
--matcher '(AskUserQuestion|mcp__.*__AskUserQuestion)' \
|
log ""
|
||||||
--command "$PLAN_TUNE_LOG_HOOK" \
|
log "Plan-tune hooks installed. Run /plan-tune anytime to inspect."
|
||||||
--source plan-tune-cathedral \
|
touch "$PLAN_TUNE_INSTALL_MARKER"
|
||||||
--timeout 5
|
;;
|
||||||
"$SETTINGS_HOOK" add-event \
|
n|N)
|
||||||
--event PreToolUse \
|
log ""
|
||||||
--matcher '(AskUserQuestion|mcp__.*__AskUserQuestion)' \
|
log "Skipped. Re-run ./setup --plan-tune-hooks or use /update-config to install later."
|
||||||
--command "$PLAN_TUNE_PREF_HOOK" \
|
touch "$PLAN_TUNE_INSTALL_MARKER"
|
||||||
--source plan-tune-cathedral \
|
;;
|
||||||
--timeout 5
|
*)
|
||||||
log ""
|
# Empty / timed out — treat as "ask me again" (don't persist a decline).
|
||||||
log "Plan-tune hooks installed. Run /plan-tune anytime to inspect."
|
log ""
|
||||||
else
|
log "No response — skipped for now. Re-run ./setup --plan-tune-hooks to install."
|
||||||
log ""
|
;;
|
||||||
log "Skipped. Re-run ./setup or use /update-config to install later."
|
esac
|
||||||
fi
|
|
||||||
touch "$PLAN_TUNE_INSTALL_MARKER"
|
|
||||||
else
|
else
|
||||||
# Non-interactive (CI, scripted setup). Don't prompt; print one-liner.
|
# Non-interactive (CI, scripted/workspace setup, quiet). Never prompt.
|
||||||
log ""
|
log ""
|
||||||
log "Plan-tune cathedral hooks not installed (non-interactive setup)."
|
log "Plan-tune cathedral hooks not installed (non-interactive setup)."
|
||||||
log "Install with:"
|
log "Install with: ./setup --plan-tune-hooks"
|
||||||
|
log " (or set GSTACK_PLAN_TUNE_HOOKS=yes, or run the commands below)"
|
||||||
log " $SETTINGS_HOOK add-event --event PostToolUse \\"
|
log " $SETTINGS_HOOK add-event --event PostToolUse \\"
|
||||||
log " --matcher '(AskUserQuestion|mcp__.*__AskUserQuestion)' \\"
|
log " --matcher '(AskUserQuestion|mcp__.*__AskUserQuestion)' \\"
|
||||||
log " --command $PLAN_TUNE_LOG_HOOK --source plan-tune-cathedral --timeout 5"
|
log " --command $PLAN_TUNE_LOG_HOOK --source plan-tune-cathedral --timeout 5"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue