deploy: BW_NOINTERACTION — bw can no longer prompt at all (#1340)
The remaining press-Enter papercut: the FIRST bw get hits the locked vault and bw prompts into the captured pipe — invisible, eating a stray Enter — before failing through to our unlock prompt. bw-lib now exports BW_NOINTERACTION at source time (a locked-vault read fails instantly: 'Vault is locked.', verified live) and pins stdin to /dev/null in bw_run and the unlock call, so nothing bw does can ever wait on the operator's keyboard.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 file changed,
+13
−3
deploy/bw-lib.sh+13 −3
diff --git a/deploy/bw-lib.sh b/deploy/bw-lib.sh| index dbc10a7..50bd9e4 100644 |
| --- a/deploy/bw-lib.sh |
| +++ b/deploy/bw-lib.sh |
| @@ -20,11 +20,21 @@ |
| # `bw unlock` 2026-07-24). perl's alarm is the never-a-hang promise — |
| # the timer survives exec, and macOS ships perl. |
| +# Rule 1, enforced globally: with BW_NOINTERACTION set, a locked-vault |
| +# `bw get`/`bw list` fails immediately instead of prompting — without it, bw's |
| +# invisible in-pipe prompt eats a stray Enter before falling through to OUR |
| +# unlock prompt (the "I still had to press Enter" papercut, 2026-07-25). |
| +# Exported at source time so every bw call in the sourcing script is covered. |
| +BW_NOINTERACTION=true |
| +export BW_NOINTERACTION |
| + |
| # bw_run <seconds> <bw-args...> — run one bw command under a watchdog. |
| -# Exit status is bw's, or SIGALRM's (142) on a stall. |
| +# Exit status is bw's, or SIGALRM's (142) on a stall. stdin is pinned to |
| +# /dev/null — none of our calls (get/list/sync/status) legitimately read it, |
| +# so nothing bw does can ever wait on the operator's keyboard. |
| bw_run() { |
| _bw_t="$1"; shift |
| - perl -e "alarm $_bw_t; exec @ARGV" bw "$@" |
| + perl -e "alarm $_bw_t; exec @ARGV" bw "$@" </dev/null |
| } |
| # bw_unlock_session — unlock the vault with OUR prompt and print the session |
| @@ -48,7 +58,7 @@ bw_unlock_session() { |
| echo >&2 |
| # 90s: the KDF is seconds, but bw's first server round-trip gets headroom. |
| _bw_sess="$(LCHAT_BW_PASSWORD="$LCHAT_BW_PASSWORD" perl -e 'alarm 90; exec @ARGV' \ |
| - bw unlock --raw --passwordenv LCHAT_BW_PASSWORD)" || _bw_sess="" |
| + bw unlock --raw --passwordenv LCHAT_BW_PASSWORD </dev/null)" || _bw_sess="" |
| unset LCHAT_BW_PASSWORD |
| if [ -z "$_bw_sess" ]; then |
| echo "bw: unlock failed or stalled — run 'bw sync' and retry, or export BW_SESSION yourself" >&2 |