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:
2026-08-22 02:55:40 -04:00
commit 77856f0a09
16 changed files with 705 additions and 0 deletions
@@ -0,0 +1,22 @@
#!/bin/sh
# Fuzzy-known source: surfaces fixes already taught for a command that
# *starts the same way* as this one, since f()'s own p lookup only ever
# matches the exact, literal string.
#
# Matches only against the KEY (left of "="), not the whole line -- an
# earlier version used `grep -F "$first_word " p`, which also matched
# inside a fix's *value*. Proven wrong live: with p containing
# `gti --version=gti(){ command git "$@"; }`, querying "git push" (never
# taught) matched that line anyway, because "git " appears inside the
# value text, not because the key is related.
[ -f p ] || exit 0
cmd="$1"
first_word=$(printf '%s' "$cmd" | awk '{print $1}')
[ -n "$first_word" ] || exit 0
awk -v fw="$first_word " '
substr($0, 1, length(fw)) == fw {
line = $0
sub(/^[^=]*=/, "", line)
if (!seen[line]++) print line
}
' p 2>/dev/null
@@ -0,0 +1,17 @@
#!/bin/sh
# Built-in fixes source: a small, curated, read-only fixes list shipped
# inside the image itself (contrib/fx/builtin-fixes.txt) -- zero network,
# zero API key, zero secrets, works on a completely offline boot. Same
# "cmd=fix" line format as the learned p file and 90-team-shared.sh, exact
# match on the full attempted command line (not fuzzy -- these are curated,
# not guesses, so they should either match precisely or stay out of the way).
#
# Numbered 15: after the user's own learned-prefix fixes (10-known.sh),
# since something the user already solved themselves should always win
# over our shipped default. Before history/self-diag/pathfuzzy (20-40),
# since a verified curated fix beats a blind guess.
BUILTIN_FIXES="${FX_BUILTIN_FIXES:-/root/shell-project/contrib/fx/builtin-fixes.txt}"
[ -f "$BUILTIN_FIXES" ] || exit 0
cmd="$1"
[ -n "$cmd" ] || exit 0
grep -F "${cmd}=" "$BUILTIN_FIXES" 2>/dev/null | cut -d= -f2- | awk '!seen[$0]++'
@@ -0,0 +1,25 @@
#!/bin/sh
# History source: suggests the closest-looking command you've actually
# typed and moved on from before (thefuck's history.py idea). Reads
# HISTFILE directly since a separate process doesn't inherit the parent
# shell's in-memory history.
#
# Single awk pass over the tail of the file: on weak/emulated hardware
# every avoided fork+exec matters (measured: an unoptimized PATH walk in
# 40-pathfuzzy.sh took >30s on this box before being fixed; pipeline
# depth has the same tax, just smaller per-hop) -- a five-process
# tail|grep|grep|awk|tail chain does the same job as one awk script
# reading the file once.
cmd="$1"
first_word=$(printf '%s' "$cmd" | awk '{print $1}')
[ -n "$first_word" ] || exit 0
hf="${HISTFILE:-$HOME/.bash_history}"
[ -r "$hf" ] || exit 0
tail -n 300 "$hf" 2>/dev/null | awk -v first="$first_word" -v full="$cmd" '
index($0, first " ") == 1 && $0 != full && !seen[$0]++ { buf[++n] = $0 }
END {
start = (n > 5) ? n - 4 : 1
for (i = start; i <= n; i++) print buf[i]
}
'
@@ -0,0 +1,39 @@
#!/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 <<FIX
${prog}(){ out=\$(command ${prog} "\$@" 2>&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
@@ -0,0 +1,57 @@
#!/bin/sh
# PATH-fuzzy source: if the first word isn't a known command, alias, or
# function, offer a function wrapping the closest-spelled real command
# as a candidate -- as a fix you approve through the normal f() flow,
# not a silently auto-installed hook. A function, not an alias: aliases
# only expand in interactive shells (need `shopt -s expand_aliases`
# otherwise), so an alias-based fix silently does nothing when f/fx run
# inside a script.
#
# Pure POSIX: walks $PATH directly instead of `compgen -c`, which is a
# bash-only builtin and does not exist under busybox ash -- this source
# used to be dead weight on exactly the minimal/embedded shells this
# project targets. Tested against busybox ash + busybox awk directly,
# not just bash + gawk.
#
# Uses Damerau-Levenshtein-lite (edit distance + adjacent transposition)
# so the canonical "gti" -> "git" typo scores 1, not 2 -- plain Hamming
# or substitution-only distance ties it with unrelated 3-letter commands
# like "ftp" and can pick the wrong one.
cmd="$1"
first_word=$(printf '%s' "$cmd" | awk '{print $1}')
[ -n "$first_word" ] || exit 0
command -v "$first_word" >/dev/null 2>&1 && exit 0
IFS=:
for d in $PATH; do
ls "$d" 2>/dev/null
done | sort -u | awk -v target="$first_word" '
function min3(a, b, c) { return (a < b ? (a < c ? a : c) : (b < c ? b : c)) }
function distance(a, b, n, m, i, j, ca, cb, cost, tmp) {
n = length(a); m = length(b)
if (n == 0) return m
if (m == 0) return n
for (j = 0; j <= m; j++) d[0, j] = j
for (i = 1; i <= n; i++) {
d[i, 0] = i
ca = substr(a, i, 1)
for (j = 1; j <= m; j++) {
cb = substr(b, j, 1)
cost = (ca == cb) ? 0 : 1
tmp = min3(d[i-1, j] + 1, d[i, j-1] + 1, d[i-1, j-1] + cost)
if (i > 1 && j > 1 && ca == substr(b, j-1, 1) && substr(a, i-1, 1) == cb) {
tmp = (tmp < d[i-2, j-2] + 1) ? tmp : d[i-2, j-2] + 1
}
d[i, j] = tmp
}
}
return d[n, m]
}
{
lendiff = length($0) - length(target)
if (lendiff > 2 || lendiff < -2) next
dd = distance(target, $0)
if (dd <= 2 && dd > 0 && (best == "" || dd < bestd)) { best = $0; bestd = dd }
}
END { if (best != "") print target "(){ command " best " \"$@\"; }" }
'
@@ -0,0 +1,20 @@
#!/bin/sh
# thefuck bridge: only fires if thefuck is installed. Note that thefuck
# --yes decides *and executes* its own suggestion, so by the time this
# candidate is shown it may have already run once via thefuck -- treat
# it as informational, not a dry-run.
#
# Wrapped in `timeout`: thefuck has no fast-fail path when no rule
# matches -- fuzz-testing this source found it hanging past 3s on a
# majority of unmatched inputs (well beyond its own ~325ms best-case
# startup cost measured earlier). Every other source in this directory
# either runs in single-digit milliseconds or is itself already
# timeout-wrapped (70/80's HTTP calls); this one wasn't, so a single
# bad input could block the whole fx() pipeline indefinitely. Capped
# at 5s -- generous enough for a real correction (~2.8s measured
# earlier for the git-push case) without being unbounded.
command -v thefuck >/dev/null 2>&1 || exit 0
command -v timeout >/dev/null 2>&1 || exit 0
cmd="$1"
[ -n "$cmd" ] || exit 0
timeout 5 thefuck --yes "$cmd" 2>/dev/null | tr -d '\342\200\213' | tail -1
@@ -0,0 +1,106 @@
#!/bin/sh
# Last-resort source: queries a local LLM inference server (Ollama or
# LM Studio, both common on dev machines) for a fix, only when nothing
# cheaper matched. Silent no-op if no local server is reachable -- this
# never touches the network, never calls a paid API, and costs nothing
# when you don't have a local model running.
#
# Numbered 70, after every deterministic/heuristic source (10-50) and
# before the team-shared source (90): cheap, verified candidates should
# always win first. fx.sh's FX_AUTO picks the *first* candidate in
# source order, so this only gets auto-selected when it's the only
# opinion offered at all -- still review it, this is a guess, not a
# fact. Every other default source is either a cached human decision or
# a deterministic rule; this is the one source capable of confidently
# suggesting something wrong.
#
# Needs python3 (uses urllib, no extra dependency beyond stdlib) --
# silently no-ops without it rather than ship a fragile hand-rolled
# JSON encoder in shell.
cmd="$1"
[ -n "$cmd" ] || exit 0
command -v python3 >/dev/null 2>&1 || exit 0
OLLAMA_URL="${FX_LLM_OLLAMA_URL:-http://127.0.0.1:11434}"
LMSTUDIO_URL="${FX_LLM_LMSTUDIO_URL:-http://127.0.0.1:1234}"
python3 - "$cmd" "$FX_OUTPUT" "$OLLAMA_URL" "$LMSTUDIO_URL" <<'PYEOF'
import sys, json, urllib.request, urllib.error
cmd, output, ollama_url, lmstudio_url = sys.argv[1:5]
PROMPT = f"""You are suggesting a fix for a failed shell command, to be taught to a self-healing shell function called f().
Rules:
- f() will eval your fix ONCE as a precondition, then re-run the ORIGINAL command verbatim. Your fix never replaces the command; it only sets up state so the original command then succeeds.
- If the fix should generalize beyond this one invocation, define a shell function with the same name as the failing program, wrapping the real binary via `command <prog> "$@"`, and only special-case the failure inside it.
- Respond with EXACTLY ONE LINE of POSIX shell and nothing else: no explanation, no markdown, no code fences, no commentary.
Failing command: {cmd}
Its output:
{output}
"""
def http_json(url, payload, timeout):
req = urllib.request.Request(
url, data=json.dumps(payload).encode(),
headers={"Content-Type": "application/json"}, method="POST",
)
with urllib.request.urlopen(req, timeout=timeout) as r:
return json.loads(r.read().decode())
def http_get_json(url, timeout):
with urllib.request.urlopen(url, timeout=timeout) as r:
return json.loads(r.read().decode())
def try_ollama():
tags = http_get_json(ollama_url.rstrip("/") + "/api/tags", 2)
models = tags.get("models") or []
if not models:
return None
model = models[0].get("name")
if not model:
return None
resp = http_json(
ollama_url.rstrip("/") + "/api/generate",
{"model": model, "prompt": PROMPT, "stream": False},
25,
)
return (resp.get("response") or "").strip()
def try_lmstudio():
models = http_get_json(lmstudio_url.rstrip("/") + "/v1/models", 2)
data = models.get("data") or []
if not data:
return None
model = data[0].get("id")
if not model:
return None
resp = http_json(
lmstudio_url.rstrip("/") + "/v1/chat/completions",
{
"model": model,
"messages": [{"role": "user", "content": PROMPT}],
"temperature": 0,
},
25,
)
choices = resp.get("choices") or []
if not choices:
return None
return (choices[0].get("message", {}).get("content") or "").strip()
for attempt in (try_ollama, try_lmstudio):
try:
result = attempt()
except (urllib.error.URLError, TimeoutError, OSError, ValueError, KeyError):
result = None
if result:
# Enforce the one-line contract even if the model ignores instructions.
first_line = result.splitlines()[0].strip()
first_line = first_line.strip("`")
if first_line:
print(first_line)
break
PYEOF
@@ -0,0 +1,101 @@
#!/bin/sh
# Remote-API fallback source: queries any OpenAI-compatible chat
# completions endpoint (OpenAI itself, OpenRouter, Groq, Together,
# Anthropic's OpenAI-compatibility layer, a company-internal proxy,
# etc.) for a fix, only when nothing cheaper -- including the free
# local model in 70-local-llm.sh -- already matched.
#
# Off by default. Requires FX_REMOTE_API_URL, FX_REMOTE_API_KEY, and
# FX_REMOTE_API_MODEL to all be set explicitly; no default model is
# assumed, since guessing one could silently pick something you don't
# want to pay for. Silently no-ops if any of the three is missing.
#
# FX_REMOTE_API_URL is the exact URL to POST to -- no "/chat/completions"
# auto-appended. An earlier version guessed that suffix onto whatever
# base URL was given, which works for OpenAI/OpenRouter/Groq's actual
# convention but broke, silently, against a real third-party API that
# used a different path (a local FastAPI service with a plain "/chat"
# endpoint, not "/chat/.../completions" -- confirmed live: the guessed
# URL 404'd, the real one worked). Silent failure on a wrong guess is
# worse than requiring the full URL up front.
#
# Numbered 80: after the free local-LLM source (70) and before
# 90-team-shared.sh, which is a human-curated source and gets the final
# word. This is the most expensive tier in latency and real dollar
# cost, so it should only ever be the last thing tried.
#
# TRUST WARNING, sharper than every other source here: this is the one
# tier where the text you'd be eval'ing was not authored by you, a tool
# you run, or a URL you personally chose to trust -- it's a third-party
# service's best guess. fx.sh already labels every candidate with its
# source filename in the picker ("[80-remote-api.sh] ..."), so this is
# never visually indistinguishable from a self-diagnosed or locally-
# verified fix. Read that label before accepting.
cmd="$1"
[ -n "$cmd" ] || exit 0
command -v python3 >/dev/null 2>&1 || exit 0
[ -n "$FX_REMOTE_API_URL" ] || exit 0
[ -n "$FX_REMOTE_API_KEY" ] || exit 0
[ -n "$FX_REMOTE_API_MODEL" ] || exit 0
# Some providers want "Authorization: Bearer <key>" (OpenAI, OpenRouter,
# Groq, ...), others want a bare custom header (Anthropic's native API
# uses "x-api-key: <key>" with no prefix). Both are configurable so this
# isn't hardcoded to one vendor's auth scheme.
AUTH_HEADER="${FX_REMOTE_API_AUTH_HEADER:-Authorization}"
AUTH_PREFIX="${FX_REMOTE_API_AUTH_PREFIX-Bearer }"
python3 - "$cmd" "$FX_OUTPUT" "$FX_REMOTE_API_URL" "$FX_REMOTE_API_KEY" "$FX_REMOTE_API_MODEL" "$AUTH_HEADER" "$AUTH_PREFIX" <<'PYEOF'
import sys, json, urllib.request, urllib.error
cmd, output, url, key, model, auth_header, auth_prefix = sys.argv[1:8]
PROMPT = f"""You are suggesting a fix for a failed shell command, to be taught to a self-healing shell function called f().
Rules:
- f() will eval your fix ONCE as a precondition, then re-run the ORIGINAL command verbatim. Your fix never replaces the command; it only sets up state so the original command then succeeds.
- If the fix should generalize beyond this one invocation, define a shell function with the same name as the failing program, wrapping the real binary via `command <prog> "$@"`, and only special-case the failure inside it.
- Respond with EXACTLY ONE LINE of POSIX shell and nothing else: no explanation, no markdown, no code fences, no commentary.
Failing command: {cmd}
Its output:
{output}
"""
payload = {
"model": model,
"messages": [{"role": "user", "content": PROMPT}],
"temperature": 0,
"max_tokens": 200,
}
req = urllib.request.Request(
url,
data=json.dumps(payload).encode(),
headers={
"Content-Type": "application/json",
auth_header: f"{auth_prefix}{key}",
},
method="POST",
)
try:
with urllib.request.urlopen(req, timeout=30) as r:
resp = json.loads(r.read().decode())
except (urllib.error.URLError, TimeoutError, OSError, ValueError):
sys.exit(0)
choices = resp.get("choices") or []
if not choices:
sys.exit(0)
content = (choices[0].get("message", {}).get("content") or "").strip()
if not content:
sys.exit(0)
# Enforce the one-line contract even if the model ignores instructions.
first_line = content.splitlines()[0].strip().strip("`")
if first_line:
print(first_line)
PYEOF
@@ -0,0 +1,15 @@
#!/bin/sh
# EXAMPLE custom source -- a template, not a real dependency. This is
# the entire extension mechanism demonstrated: any executable dropped
# into sources.d/ following the contract in fx.sh is picked up
# automatically, no registration step anywhere else.
#
# Pulls a team-shared p-format corrections file and offers exact-key
# matches. Off by default (no-ops unless FX_TEAM_URL is set) because a
# match here becomes eval'd code the moment you select it -- point this
# at a URL you trust the same way you'd trust an rc file, never a
# random link.
[ -n "$FX_TEAM_URL" ] || exit 0
cmd="$1"
[ -n "$cmd" ] || exit 0
curl -fsSL "$FX_TEAM_URL" 2>/dev/null | grep -F "${cmd}=" | cut -d= -f2-