Fix four upgrade-path defects the coherence audit found

The ~/.claude.json write was `printf ... > "$CLAUDE_JSON"`, which
truncates before it writes. A write that fails part-way — a full home
volume, which is the exact condition half this release exists to prevent
— leaves the file unparseable, and it never self-heals: the next start's
jq fails on the corrupt file, MERGED is empty, and the guard skips the
write that would have repaired it. That file holds the OAuth account, so
the failure mode is a permanently lost login, in service of a cosmetic
flag that suppresses a tip. Demonstrated: old pattern loses the
credential, new tmp+rename leaves the original intact. The correct
pattern was already in triple-c-task-runner.

The web terminal scoped its xterm key handler to Claude sessions but not
its mobile input bar or its dedicated newline button, so both sent ESC+CR
into `bash -l`, where readline has no binding for it. Silent no-op, and
worse from a button that stays on screen looking live. Both now consult
the active session's type, and the button is disabled with a reason on a
shell tab.

The Config tab claimed "Off overrides a global On" without qualification.
True for the env-var-driven settings, false for TUI mode, Effort level
and Focus mode, whose off state is *removing* a key — an older base
image's entrypoint ignores the instruction to remove it. The copy now
says so and points at the base-image update.

HOW-TO-USE.md said there is no add-task form; AutomationTab renders a
"New task" button. That file is fetched from GitHub at runtime by
help_commands.rs, so the error was live in every user's Help dialog.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GBq2rGum6GX7xXgsas1fDc
This commit is contained in:
2026-08-23 16:45:20 -07:00
co-authored by Claude Opus 5
parent 168b61d632
commit dd23a52b41
4 changed files with 74 additions and 7 deletions
+23 -1
View File
@@ -491,9 +491,31 @@ if [ -f "$CLAUDE_JSON" ]; then
# Only rewrite when the value isn't already true, to avoid a needless jq
# reformat of ~/.claude.json on every single start.
if ! grep -q '"shiftEnterKeyBindingInstalled"[[:space:]]*:[[:space:]]*true' "$CLAUDE_JSON" 2>/dev/null; then
# Write to a temp file and rename, never `> "$CLAUDE_JSON"`.
#
# `>` truncates before it writes, so a write that fails part-way — a
# full home volume is the obvious way, and bounding that volume is
# what half this release is about — leaves the file unparseable. This
# file holds the OAuth account, and the damage does not self-heal: the
# next start's `jq` fails on the corrupt file, `MERGED` is empty, and
# the guard below skips the write that would have repaired it. So the
# failure mode is a permanently lost login, for a purely cosmetic flag
# that suppresses a "run /terminal-setup" tip.
#
# `triple-c-task-runner` already does it this way; this block was
# modelled on the awsAuthRefresh one above, which has the same flaw but
# only fires when a Bedrock SSO command is configured.
MERGED=$(jq '.shiftEnterKeyBindingInstalled = true' "$CLAUDE_JSON" 2>/dev/null)
if [ -n "$MERGED" ]; then
printf '%s\n' "$MERGED" > "$CLAUDE_JSON"
CLAUDE_JSON_TMP="${CLAUDE_JSON}.triple-c-tmp"
if printf '%s\n' "$MERGED" > "$CLAUDE_JSON_TMP" 2>/dev/null; then
mv -f "$CLAUDE_JSON_TMP" "$CLAUDE_JSON" 2>/dev/null || rm -f "$CLAUDE_JSON_TMP"
else
# Out of space, or the volume went read-only. The original is
# untouched, which is the whole point.
rm -f "$CLAUDE_JSON_TMP"
echo "entrypoint: warning — could not set shiftEnterKeyBindingInstalled (leaving ~/.claude.json as it was)"
fi
fi
fi
else