#!/bin/sh # Self-diagnosis source: many CLIs print their own corrected invocation # in their error output (git's --set-upstream hint, apt's "did you # mean", etc.). # # IMPORTANT: this must NOT cache the literal suggested line -- that # reintroduces the exact-key staleness problem (e.g. "git push" learned # once on branch A silently misapplies its captured --set-upstream on # branch B, and B never actually gets pushed). Instead it emits a # function that shadows the whole program and re-derives the suggestion # from *live* output on every call, the same trick proven to generalize # correctly across branches/arguments in practice. One taught fix this # way covers every future self-diagnosing failure from that program, not # just the one instance that happened to trigger the teaching prompt. # # The emitted function runs on every future call to that program for # the rest of the session, so its own internal extraction is one awk # pass, not a grep|sed|tail chain -- three fewer forks on every failure # it ever handles, not just this first one. cmd="$1" prog=$(printf '%s' "$cmd" | awk '{print $1}') [ -n "$prog" ] || exit 0 [ -n "$FX_OUTPUT" ] || exit 0 # Literal prefix comparison (substr/index), never a regex built from # $prog: proven broken live for program names containing ERE # metacharacters -- e.g. "g++ foo.cpp" produced the pattern # "^[[:space:]]*g++[[:space:]]", a malformed stacked-quantifier regex, # and this source silently found nothing even when $FX_OUTPUT clearly # started a line with "g++ ". Same fix applied to the emitted function # below, since it runs the identical check on every future call. printf '%s\n' "$FX_OUTPUT" | awk -v p="$prog" ' { line = $0; sub(/^[ \t]*/, "", line); if (substr(line, 1, length(p) + 1) == p " ") { found = 1; exit } } END { exit !found } ' || exit 0 cat <&1); ec=\$?; if [ \$ec -ne 0 ]; then sug=\$(printf '%s\\n' "\$out" | awk -v p="${prog}" '{ line=\$0; sub(/^[ \\t]*/,"",line); if (substr(line,1,length(p)+1)==p" ") s=line } END{print s}'); if [ -n "\$sug" ]; then eval "command \$sug"; return \$?; fi; fi; printf '%s\\n' "\$out"; return \$ec; } FIX