harness: fleet-wide functional-error + correction + friction logging
Add .claude/scripts/log-skill-error.sh — the canonical agent error log helper (writes errorlog.md in DATE | MACHINE | skill | [type] error format, soft-fails). Three categories: execution failures (default), user corrections (--correction), and preventable self-inflicted friction (--friction; cite ref= when it repeats a documented gotcha). Goal: stop paying tokens twice for the same avoidable mistake. - CLAUDE.md: make logging mandatory for all skills + corrections + friction. - skill-creator: new skills must wire in the helper (guidance + checklist). - Retrofit every skill script's genuine failure branches to call the helper (b2/bitdefender/mailprotector/packetdial/coord python CLIs; remediation-tool + onboard365 bash; vault, rmm-auth, post-bot-alert, agy, grok, 1password, run-onboarding-diagnostic). Handled conditions + self-tests left alone. - errorlog.md: broaden header to cover skills + harness + corrections; seed this session's corrections (INKY, Mail.Send token-audience, omnibox-strictness) and friction (git-bash /tmp, env-persistence, argv-limit, PowerShell var-case). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -83,6 +83,8 @@ WORK="$TMP/work"; mkdir -p "$WORK"
|
||||
PF="$TMP/prompt.txt"; OUT="$TMP/out.json"
|
||||
RUN_CWD="$WORK" # grok's working dir; the 'review' mode overrides to the repo so read_file can reach repo files
|
||||
REPO_ROOT="${CLAUDETOOLS_ROOT:-$(cd "$SCRIPT_DIR/../../../.." 2>/dev/null && pwd)}"
|
||||
# Functional-error logger (skill name "grok"); soft-fails, never breaks the caller.
|
||||
_logerr() { bash "$REPO_ROOT/.claude/scripts/log-skill-error.sh" "grok" "$@" >/dev/null 2>&1 || true; }
|
||||
|
||||
# run grok headless. $1=timeout secs; rest=extra flags. Reads $PF -> $OUT.
|
||||
# Never fails the script on grok's exit code (Cancelled is expected; we read artifacts).
|
||||
@@ -170,7 +172,7 @@ case "$MODE" in
|
||||
run_grok 180 --disable-web-search --max-turns 3
|
||||
txt="$(jfield text)"
|
||||
if [ -n "$txt" ]; then printf '%s\n' "$txt"; else
|
||||
echo "[$SELF] no text (stopReason=$(jfield stopReason)); raw: $OUT" >&2; exit 1; fi
|
||||
echo "[$SELF] no text (stopReason=$(jfield stopReason)); raw: $OUT" >&2; _logerr "grok returned no text" --context "mode=$MODE stopReason=$(jfield stopReason)"; exit 1; fi
|
||||
;;
|
||||
image)
|
||||
[ -z "${1:-}" ] && { echo "usage: $SELF image \"<prompt>\" [out.png]" >&2; exit 2; }
|
||||
@@ -180,7 +182,7 @@ case "$MODE" in
|
||||
sid="$(jfield sessionId)"; art="$(find_artifact "$sid" images)"
|
||||
if [ -n "$art" ] && [ -f "$art" ]; then cp -f "$art" "$out"
|
||||
echo "[$SELF] image OK -> $out (session $sid)"
|
||||
else echo "[$SELF] no image artifact (session=$sid, stopReason=$(jfield stopReason))" >&2; exit 1; fi
|
||||
else echo "[$SELF] no image artifact (session=$sid, stopReason=$(jfield stopReason))" >&2; _logerr "grok produced no image artifact" --context "session=$sid stopReason=$(jfield stopReason)"; exit 1; fi
|
||||
;;
|
||||
video)
|
||||
[ -z "${1:-}" ] || [ -z "${2:-}" ] && { echo "usage: $SELF video \"<prompt>\" <input-image> [out.mp4]" >&2; exit 2; }
|
||||
@@ -192,7 +194,7 @@ case "$MODE" in
|
||||
sid="$(jfield sessionId)"; art="$(find_artifact "$sid" videos)"
|
||||
if [ -n "$art" ] && [ -f "$art" ]; then cp -f "$art" "$out"
|
||||
echo "[$SELF] video OK -> $out (session $sid)"
|
||||
else echo "[$SELF] no video artifact (session=$sid, stopReason=$(jfield stopReason))" >&2; exit 1; fi
|
||||
else echo "[$SELF] no video artifact (session=$sid, stopReason=$(jfield stopReason))" >&2; _logerr "grok produced no video artifact" --context "session=$sid stopReason=$(jfield stopReason)"; exit 1; fi
|
||||
;;
|
||||
xsearch)
|
||||
[ -z "${1:-}" ] && { echo "usage: $SELF xsearch \"<query>\"" >&2; exit 2; }
|
||||
@@ -200,7 +202,7 @@ case "$MODE" in
|
||||
run_grok 150 --max-turns 6
|
||||
txt="$(jfield text)"
|
||||
if [ -n "$txt" ]; then printf '%s\n' "$txt"; else
|
||||
echo "[$SELF] no result (stopReason=$(jfield stopReason))" >&2; exit 1; fi
|
||||
echo "[$SELF] no result (stopReason=$(jfield stopReason))" >&2; _logerr "grok xsearch returned no result" --context "mode=xsearch stopReason=$(jfield stopReason)"; exit 1; fi
|
||||
;;
|
||||
review|file)
|
||||
[ -z "${1:-}" ] && { echo "usage: $SELF review <file-path> [instructions]" >&2; exit 2; }
|
||||
@@ -233,7 +235,7 @@ case "$MODE" in
|
||||
fi
|
||||
fi
|
||||
if [ -n "$txt" ]; then printf '%s\n' "$txt"; else
|
||||
echo "[$SELF] no result (session=$(jfield sessionId), stopReason=$(jfield stopReason))" >&2; exit 1; fi
|
||||
echo "[$SELF] no result (session=$(jfield sessionId), stopReason=$(jfield stopReason))" >&2; _logerr "grok review returned no result" --context "mode=$MODE session=$(jfield sessionId) stopReason=$(jfield stopReason)"; exit 1; fi
|
||||
;;
|
||||
review-files)
|
||||
# review-files [-i "instructions"] <file> [file ...]
|
||||
@@ -283,7 +285,7 @@ case "$MODE" in
|
||||
fi
|
||||
fi
|
||||
if [ -n "$txt" ]; then printf '%s\n' "$txt"; else
|
||||
echo "[$SELF] no result (session=$(jfield sessionId), stopReason=$(jfield stopReason))" >&2; exit 1; fi
|
||||
echo "[$SELF] no result (session=$(jfield sessionId), stopReason=$(jfield stopReason))" >&2; _logerr "grok review returned no result" --context "mode=$MODE session=$(jfield sessionId) stopReason=$(jfield stopReason)"; exit 1; fi
|
||||
;;
|
||||
review-diff)
|
||||
# review-diff [-C <repo-dir>] [-i "instructions"] <gitref> [-- <pathspec...>]
|
||||
@@ -328,7 +330,7 @@ case "$MODE" in
|
||||
fi
|
||||
fi
|
||||
if [ -n "$txt" ]; then printf '%s\n' "$txt"; else
|
||||
echo "[$SELF] no result (session=$(jfield sessionId), stopReason=$(jfield stopReason))" >&2; exit 1; fi
|
||||
echo "[$SELF] no result (session=$(jfield sessionId), stopReason=$(jfield stopReason))" >&2; _logerr "grok review returned no result" --context "mode=$MODE session=$(jfield sessionId) stopReason=$(jfield stopReason)"; exit 1; fi
|
||||
;;
|
||||
raw)
|
||||
"$GROK" "$@"
|
||||
|
||||
Reference in New Issue
Block a user