Initial commit: apkovl deployment source, synced from shell-project main
This directory is what gets packaged into localhost.apkovl.tar.gz and
baked into adaptiveos-vN.iso. It had drifted out of sync with the real
project (root/shell-project/ had gone missing entirely at some point
after being written earlier this session -- cause unconfirmed, Desktop
is a plausible sync-related suspect but not verified) and separately
carried a stale, pre-fix copy of fx.sh.
Current contents:
etc/profile.d/adaptive-loop.sh -- disk-persists p AND p.trace
(fx()'s fix-provenance record)
across reboot, two separate 1MB
blocks on the attached state disk
etc/profile.d/adaptive-setup.sh -- unchanged, network/git/fzf bring-up
root/shell-project/ -- synced from space.seodr.ovh/
Daveswo/self-healing-autopoietic-
shell @ 3c4947e (main), plus three
deployment-only files not in that
repo: contrib/fx/builtin-fixes.txt,
contrib/fx/sources.d/15-builtin-
fixes.sh, contrib/heal/heal.sh
Verified byte-identical to what's actually embedded in the currently
shipping adaptiveos-v6.iso before this commit (full recursive diff),
and every .sh file passes `sh -n`.
.gitattributes (text=auto eol=lf) added to prevent the CRLF corruption
that hit the canonical repo earlier this session from recurring here.
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
#!/bin/sh
|
||||
# fx: automates f()'s "enter a fix" prompt by gathering candidate fixes
|
||||
# from a directory of pluggable sources and letting you pick one (or
|
||||
# auto-picking the top one) before piping it into f's stdin.
|
||||
#
|
||||
# Zero changes to f.sh: this only decides what gets typed at the
|
||||
# "[LEARN] ... Enter a fix" prompt, using the stdin f() already reads.
|
||||
#
|
||||
# Usage:
|
||||
# . src/f.sh
|
||||
# . contrib/fx/fx.sh
|
||||
# fx some-command --that --might --fail
|
||||
#
|
||||
# Env vars:
|
||||
# FX_SOURCES_DIR the sources directory. Defaults to ./contrib/fx/sources.d
|
||||
# (i.e. source this file from the repo root). There is no
|
||||
# portable way for a *sourced* POSIX shell file to learn
|
||||
# its own path -- $0 is the enclosing shell's name, and
|
||||
# bash's BASH_SOURCE has no equivalent in dash/ash, so
|
||||
# this does not try to be clever about it. Anything
|
||||
# other than "source from repo root" (a different cwd,
|
||||
# a temp dir a la bootstrap.sh) must set this explicitly
|
||||
# *before* sourcing this file.
|
||||
# FX_AUTO if set, auto-pick the top candidate instead of
|
||||
# showing a picker
|
||||
# FX_NO_PROBE if set, skip fx's own diagnostic run of the command
|
||||
# (cheaper, but the 30-selfdiag.sh source gets no
|
||||
# output to read and will have no opinion)
|
||||
# FX_TRACE_FILE where chosen fixes' source labels are recorded, one
|
||||
# "cmd=source-file" line per accepted fix. Defaults to
|
||||
# ./p.trace, alongside f()'s own ./p. Written whenever
|
||||
# a non-blank candidate is handed to f() -- same
|
||||
# "wrote intent, not confirmed success" semantics as
|
||||
# p itself (see f.sh). This exists because f() alone
|
||||
# has no notion of *where* a fix came from: once a
|
||||
# fix is in p, a manually-typed fix, a locally-known
|
||||
# fix (10-known.sh), and an LLM-guessed fix
|
||||
# (70/80-*.sh) are byte-for-byte indistinguishable.
|
||||
# 80-remote-api.sh's own docstring is explicit that
|
||||
# LLM-sourced fixes must stay visually distinguishable
|
||||
# from verified ones -- without this file, that
|
||||
# distinction is silently lost the moment a fix is
|
||||
# accepted, and permanently lost if p is disk-persisted
|
||||
# across a reboot (see adaptive-loop.sh). p.trace is
|
||||
# what a caller checks before trusting an auto-applied
|
||||
# fix it didn't personally review.
|
||||
#
|
||||
# Source contract (see sources.d/*.sh):
|
||||
# - any executable file in $FX_SOURCES_DIR
|
||||
# - invoked as: sourcefile "$CMD"
|
||||
# - may read $FX_OUTPUT (captured stdout+stderr of one real attempt,
|
||||
# empty if FX_NO_PROBE was set)
|
||||
# - prints zero or more candidate fix lines to stdout, one per line
|
||||
# - non-zero exit or no output = "no opinion", silently skipped
|
||||
# - filename prefix (NN-name) sets display/consideration order
|
||||
#
|
||||
# Adding a source: drop a new executable file in sources.d/ that follows
|
||||
# the contract above. Nothing else to register or edit.
|
||||
|
||||
# Resolved to an absolute path *now*, at source time -- a relative
|
||||
# default would silently re-resolve against whatever cwd happens to be
|
||||
# active later when fx() is actually called, which is almost never the
|
||||
# repo root in practice.
|
||||
FX_SOURCES_DIR="${FX_SOURCES_DIR:-$(pwd)/contrib/fx/sources.d}"
|
||||
FX_TRACE_FILE="${FX_TRACE_FILE:-p.trace}"
|
||||
|
||||
fx() {
|
||||
if [ ! -d "$FX_SOURCES_DIR" ]; then
|
||||
echo "fx: FX_SOURCES_DIR '$FX_SOURCES_DIR' not found -- no sources will fire." >&2
|
||||
echo "fx: set FX_SOURCES_DIR before sourcing fx.sh if not running from the repo root." >&2
|
||||
fi
|
||||
cmd="$*"
|
||||
|
||||
FX_OUTPUT=""
|
||||
if [ -z "$FX_NO_PROBE" ]; then
|
||||
FX_OUTPUT=$("$@" 2>&1)
|
||||
if [ $? -eq 0 ]; then
|
||||
printf '%s\n' "$FX_OUTPUT"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
export FX_OUTPUT
|
||||
|
||||
# Under FX_AUTO only the first candidate is ever used (head -1
|
||||
# below), so gathering every source unconditionally would mean
|
||||
# always paying for the 25-30s local-LLM/remote-API tiers even
|
||||
# when a free source already answered and that answer is
|
||||
# guaranteed to win -- exactly the cost the NN- numbering claims to
|
||||
# avoid. Stop at the first source that produces anything once
|
||||
# FX_AUTO is set. Without it (the interactive picker), keep
|
||||
# gathering everything: a later, better-verified candidate
|
||||
# shouldn't be hidden behind an earlier weak match when a human is
|
||||
# the one choosing.
|
||||
candidates=$(
|
||||
for src in "$FX_SOURCES_DIR"/*; do
|
||||
[ -x "$src" ] || continue
|
||||
label="${src##*/}"
|
||||
out=$("$src" "$cmd" 2>/dev/null)
|
||||
if [ -n "$out" ]; then
|
||||
printf '%s\n' "$out" | while IFS= read -r line; do
|
||||
[ -n "$line" ] && printf '%s\t%s\n' "$label" "$line"
|
||||
done
|
||||
[ -n "$FX_AUTO" ] && break
|
||||
fi
|
||||
done | awk -F'\t' '
|
||||
{
|
||||
label = $1
|
||||
text = substr($0, length(label) + 2)
|
||||
if (!seen[text]++) print "[" label "] " text
|
||||
}
|
||||
'
|
||||
)
|
||||
|
||||
# chosen_line keeps the "[source-label] fix text" form intact so
|
||||
# provenance can be recovered after picking -- stripping the label
|
||||
# too early (as this used to do in each branch below) throws away
|
||||
# the one piece of information that lets a later reader tell an
|
||||
# LLM-guessed fix apart from a locally-verified one.
|
||||
chosen_line=""
|
||||
if [ -n "$candidates" ]; then
|
||||
if [ -n "$FX_AUTO" ]; then
|
||||
chosen_line=$(printf '%s\n' "$candidates" | head -1)
|
||||
elif command -v fzf >/dev/null 2>&1; then
|
||||
chosen_line=$(printf '%s\n' "$candidates" | fzf --prompt="fix for: $cmd > " --height=40%)
|
||||
else
|
||||
i=0
|
||||
printf '%s\n' "$candidates" | while IFS= read -r line; do
|
||||
i=$((i+1)); printf '%d) %s\n' "$i" "$line"
|
||||
done
|
||||
# "blank to give up", not "type your own": fx already
|
||||
# committed f's stdin to this pipe, so a blank answer here
|
||||
# can't fall through to a real terminal read the way f()'s
|
||||
# own bare prompt does -- it just pipes an empty line into
|
||||
# f(), same as when zero candidates were found at all.
|
||||
printf 'pick a number (blank to give up): '
|
||||
read -r n
|
||||
[ -n "$n" ] && chosen_line=$(printf '%s\n' "$candidates" | sed -n "${n}p")
|
||||
fi
|
||||
fi
|
||||
|
||||
chosen=$(printf '%s\n' "$chosen_line" | sed 's/^\[[^]]*\] //')
|
||||
chosen_source=$(printf '%s\n' "$chosen_line" | sed -n 's/^\[\([^]]*\)\].*/\1/p')
|
||||
|
||||
# Same "record intent, not confirmed success" timing as f()'s own
|
||||
# write to p: logged as soon as a non-blank fix is handed off, not
|
||||
# gated on the retry inside f() actually succeeding.
|
||||
if [ -n "$chosen" ] && [ -n "$chosen_source" ]; then
|
||||
printf '%s=%s\n' "$cmd" "$chosen_source" >> "$FX_TRACE_FILE"
|
||||
fi
|
||||
|
||||
printf '%s\n' "$chosen" | f "$@"
|
||||
}
|
||||
Reference in New Issue
Block a user