eleven / messenger Public

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>
Paul Campbell 4e8c5926b57bfff26dc36ebfb2f3efae0e25d285 parent fe50529
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