What happens
focus config set validates its key against _valid_key. focus config unset does not, and the key is interpolated unescaped into a sed address:
env_key="REFOCUS_${key}"
[[ -f "$ENV_FILE" ]] && _rewrite_env "/^${env_key}=/d"
Any / in the key ends the address early and the rest becomes sed program text:
$ focus config set NUDGE_INTERVAL 9
✅ NUDGE_INTERVAL=9
$ focus config unset 'x/d;s/^.*$//'
sed: -e expression #1, char 23: unknown option to `s'
✅ Unset x/d;s/^.*$// (reverts to default)
$ echo $?
0
sed refused the malformed program, so .env survived — but the command still printed ✅ and exited 0.
Why the success message is wrong
_rewrite_env (lib/config.sh:39) ends with rm:
sed "$expr" "$ENV_FILE" > "$tmp" && cat "$tmp" > "$ENV_FILE"
rm -f "$tmp"
The function returns rm's status, not the rewrite's, so a failed rewrite looks like success to the caller.
The two halves fail differently, which is why this hid for so long:
cat "$tmp" > "$ENV_FILE" is the final command of the && list, so set -e catches it. Making .env read-only correctly gives rc=1 and no ✅.
sed ... > "$tmp" is non-final, so set -e skips it, && short-circuits, rm returns 0, and the caller prints ✅.
Why it's needed
.env is not corrupted, so the blast radius is small. The problem is that the tool reports success for work it did not do — and a ✅ that can be a lie devalues every other ✅ the tool prints.
Suggested fix
- Gate
unset on _valid_key, the same as set.
- Make
_rewrite_env return the rewrite's status rather than rm's, so a failed write reaches the caller.
Location
lib/config.sh — _rewrite_env at :32-41, the unset branch at :94-99.
What happens
focus config setvalidates its key against_valid_key.focus config unsetdoes not, and the key is interpolated unescaped into a sed address:Any
/in the key ends the address early and the rest becomes sed program text:sed refused the malformed program, so
.envsurvived — but the command still printed✅and exited 0.Why the success message is wrong
_rewrite_env(lib/config.sh:39) ends withrm:The function returns
rm's status, not the rewrite's, so a failed rewrite looks like success to the caller.The two halves fail differently, which is why this hid for so long:
cat "$tmp" > "$ENV_FILE"is the final command of the&&list, soset -ecatches it. Making.envread-only correctly givesrc=1and no✅.sed ... > "$tmp"is non-final, soset -eskips it,&&short-circuits,rmreturns 0, and the caller prints✅.Why it's needed
.envis not corrupted, so the blast radius is small. The problem is that the tool reports success for work it did not do — and a✅that can be a lie devalues every other✅the tool prints.Suggested fix
unseton_valid_key, the same asset._rewrite_envreturn the rewrite's status rather thanrm's, so a failed write reaches the caller.Location
lib/config.sh—_rewrite_envat :32-41, theunsetbranch at :94-99.