fix: review-driven hardening of pos ai hf/server + llamacpp provider
gates / consistency-and-conventions (push) Successful in 2m16s

Adversarial review of the AI tools (commits 387f23f/0856b25) found 2
BLOCKING + 5 REQUIRED defects; all fixed:

- pos-ai-hf --include/--exclude: bash-case glob filtering (array-safe,
  no jq regex interpolation, composes gguf->filename->include->exclude)
- pos-ai-server: ExecStart rebuilt as single-line properly-quoted command
  (systemd_quote for executable + model path; systemd-analyze verify rc=0)
- --branch/--revision aliased (last wins), dead BRANCH variable removed
- parallel download drains all jobs: per-pid wait, honest
  'X of Y files, N failed' summary, rc=1 on partial failure, no .hf-meta
  for half-downloaded models, EXIT-trap temp cleanup
- detect_llama_version guarded; validate_requested_flags errors on
  unsupported explicit flags with version-aware message
- pos ai hf cache [status|clear]: real implementation, fail-closed confirm
- new bin/pos-ai-llamacpp thin forwarder + llamacpp shorthand in bin/pos-ai
  (pos ai llamacpp <subcmd> = pos ai --provider llamacpp <subcmd>)
- docs synced: bin/pos-ai usage(), DOC/POS.md AI_PROVIDER row, howto/ai.md
  (adapter list, --provider backends, shorthand, providers table); gen
  regenerated (tree/dispatch/completions)

Verified: bash -n all bin/pos*; make gen idempotent; make check green;
make lint 0 FAIL, 0 WARN. Reviewer acceptance: APPROVE_WITH_NOTES
(0 REQUIRED). Audit deliverables + agent reports included for context.
This commit is contained in:
Your Name
2026-09-06 03:45:53 -04:00
parent 0856b25b97
commit 528b16676e
23 changed files with 2495 additions and 253 deletions
+153 -107
View File
@@ -47,17 +47,43 @@ find_llamacpp() {
}
# ── Version detection ──────────────────────────────────────────
# detect_llama_version <binary> → X.Y.Z or "unknown". Guarded: a missing
# binary or unreadable --version output yields "unknown", never an errexit.
detect_llama_version() {
local bin="${1:-llama-server}"
command -v "$bin" &>/dev/null || { echo "unknown"; return 0; }
local version
version="$(llama-server --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)"
version="$("$bin" --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true)"
[ -n "$version" ] || version="unknown"
echo "$version"
}
# ── Validate version support for features ──────────────────────
validate_server_features() {
local version="$1"
# Simple validation - in a real implementation we'd check if specific flags are supported
echo "Version $version detected. Feature validation would occur here."
# ── Validate explicitly requested flags ────────────────────────
# validate_requested_flags <binary> <version> <flag...> — for every flag the
# user explicitly requested, check its token appears in the binary's --help
# output and err (version-aware) on the first unsupported one. If --help
# cannot be read, warn once and proceed instead of hard-failing.
validate_requested_flags() {
local bin="$1" version="$2"
shift 2
[ $# -gt 0 ] || return 0
local help_text
help_text="$("$bin" --help 2>/dev/null)" || {
warn "Cannot obtain llama-server --help output — skipping flag validation"
return 0
}
local seen=() flag
for flag in "$@"; do
case " ${seen[*]:-} " in
*" $flag "*) continue ;; # dedupe alias-mapped flags (e.g. --gpu → --n-gpu-layers)
esac
seen+=("$flag")
if ! printf '%s' "$help_text" | grep -qF -- "$flag"; then
err "installed llama.cpp ${version} does not expose ${flag} — remove it or upgrade llama.cpp"
fi
done
}
# ── GPU detection ──────────────────────────────────────────────
@@ -259,74 +285,78 @@ METRICS=""
HEALTH=""
SLOTS=""
# Canonical flag tokens the user explicitly requested (defaults excluded) —
# validated against the installed binary's --help in cmd_start.
REQUESTED_FLAGS=()
while [ $# -gt 0 ]; do
case "$1" in
-h|--help) usage ;;
--port)
[ $# -ge 2 ] || err "--port requires a value"
PORT="$2"; shift 2 ;;
PORT="$2"; REQUESTED_FLAGS+=("--port"); shift 2 ;;
--host)
[ $# -ge 2 ] || err "--host requires a value"
HOST="$2"; shift 2 ;;
HOST="$2"; REQUESTED_FLAGS+=("--host"); shift 2 ;;
--model)
[ $# -ge 2 ] || err "--model requires a value"
MODEL_ARG="$2"; shift 2 ;;
MODEL_ARG="$2"; REQUESTED_FLAGS+=("--model"); shift 2 ;;
--ctx)
[ $# -ge 2 ] || err "--ctx requires a value"
CTX_SIZE="$2"; shift 2 ;;
CTX_SIZE="$2"; REQUESTED_FLAGS+=("--ctx-size"); shift 2 ;;
--gpu)
[ $# -ge 2 ] || err "--gpu requires a value"
GPU_LAYERS="$2"; shift 2 ;;
GPU_LAYERS="$2"; REQUESTED_FLAGS+=("--n-gpu-layers"); shift 2 ;;
--threads)
[ $# -ge 2 ] || err "--threads requires a value"
THREADS="$2"; shift 2 ;;
THREADS="$2"; REQUESTED_FLAGS+=("--threads"); shift 2 ;;
--gpu-layers)
[ $# -ge 2 ] || err "--gpu-layers requires a value"
GPU_LAYERS_FLAG="$2"; shift 2 ;;
GPU_LAYERS_FLAG="$2"; REQUESTED_FLAGS+=("--n-gpu-layers"); shift 2 ;;
--gpu-threads)
[ $# -ge 2 ] || err "--gpu-threads requires a value"
GPU_THREADS="$2"; shift 2 ;;
GPU_THREADS="$2"; REQUESTED_FLAGS+=("--gpu-threads"); shift 2 ;;
--tensor-split)
[ $# -ge 2 ] || err "--tensor-split requires a value"
TENSOR_SPLIT="$2"; shift 2 ;;
TENSOR_SPLIT="$2"; REQUESTED_FLAGS+=("--tensor-split"); shift 2 ;;
--n-gpu-layers)
[ $# -ge 2 ] || err "--n-gpu-layers requires a value"
GPU_LAYERS_FLAG="$2"; shift 2 ;;
GPU_LAYERS_FLAG="$2"; REQUESTED_FLAGS+=("--n-gpu-layers"); shift 2 ;;
--batch-size)
[ $# -ge 2 ] || err "--batch-size requires a value"
BATCH_SIZE="$2"; shift 2 ;;
BATCH_SIZE="$2"; REQUESTED_FLAGS+=("--batch-size"); shift 2 ;;
--ubatch-size)
[ $# -ge 2 ] || err "--ubatch-size requires a value"
UBATCH_SIZE="$2"; shift 2 ;;
UBATCH_SIZE="$2"; REQUESTED_FLAGS+=("--ubatch-size"); shift 2 ;;
--temperature)
[ $# -ge 2 ] || err "--temperature requires a value"
TEMPERATURE="$2"; shift 2 ;;
TEMPERATURE="$2"; REQUESTED_FLAGS+=("--temperature"); shift 2 ;;
--top-k)
[ $# -ge 2 ] || err "--top-k requires a value"
TOP_K="$2"; shift 2 ;;
TOP_K="$2"; REQUESTED_FLAGS+=("--top-k"); shift 2 ;;
--top-p)
[ $# -ge 2 ] || err "--top-p requires a value"
TOP_P="$2"; shift 2 ;;
TOP_P="$2"; REQUESTED_FLAGS+=("--top-p"); shift 2 ;;
--repetition-penalty)
[ $# -ge 2 ] || err "--repetition-penalty requires a value"
REPETITION_PENALTY="$2"; shift 2 ;;
REPETITION_PENALTY="$2"; REQUESTED_FLAGS+=("--repetition-penalty"); shift 2 ;;
--mmap)
MAPPING="true"; shift ;;
MAPPING="true"; REQUESTED_FLAGS+=("--mmap"); shift ;;
--mlock)
LOCKING="true"; shift ;;
LOCKING="true"; REQUESTED_FLAGS+=("--mlock"); shift ;;
--kv-cache)
[ $# -ge 2 ] || err "--kv-cache requires a value"
KV_CACHE_SIZE="$2"; shift 2 ;;
KV_CACHE_SIZE="$2"; REQUESTED_FLAGS+=("--kv-cache"); shift 2 ;;
--ctx-size)
[ $# -ge 2 ] || err "--ctx-size requires a value"
CTX_SIZE="$2"; shift 2 ;;
CTX_SIZE="$2"; REQUESTED_FLAGS+=("--ctx-size"); shift 2 ;;
--metrics)
METRICS="true"; shift ;;
METRICS="true"; REQUESTED_FLAGS+=("--metrics"); shift ;;
--health)
HEALTH="true"; shift ;;
HEALTH="true"; REQUESTED_FLAGS+=("--health"); shift ;;
--slots)
[ $# -ge 2 ] || err "--slots requires a value"
SLOTS="$2"; shift 2 ;;
SLOTS="$2"; REQUESTED_FLAGS+=("--slots"); shift 2 ;;
-*)
err "Unknown option '$1' (see --help)" ;;
*)
@@ -351,6 +381,16 @@ LLAMACPP_THREADS="$THREADS"
# ── Subcommands ────────────────────────────────────────────────
# systemd_quote <value> — wrap a path in double quotes for systemd's
# ExecStart word-splitting (systemd.service(5)), escaping embedded `"` as
# `\"`. Only tokens that may legally contain spaces need this (binary and
# model path); plain numeric/flag tokens like `--port 8088` stay unquoted.
systemd_quote() {
local value="$1"
value="${value//\"/\\\"}"
printf '"%s"' "$value"
}
cmd_start() {
# Resolve the llama-server binary
local llamacpp_bin
@@ -358,11 +398,14 @@ cmd_start() {
local llamacpp_full
llamacpp_full="$(command -v "$llamacpp_bin")"
# Detect version
# Detect version (guarded — never crashes; returns "unknown" when
# unreadable, then basic defaults are used)
local version
version="$(detect_llama_version)"
if [ -n "$version" ]; then
validate_server_features "$version"
version="$(detect_llama_version "$llamacpp_bin")"
# Validate explicitly requested flags against this binary's --help
if [ "${#REQUESTED_FLAGS[@]}" -gt 0 ]; then
validate_requested_flags "$llamacpp_bin" "$version" "${REQUESTED_FLAGS[@]}"
fi
# Resolve model
@@ -391,14 +434,69 @@ cmd_start() {
fi
fi
# Build ONE command line: binary + model + ALL resolved flags. A single
# string keeps the systemd unit's ExecStart on one line (systemd requires
# trailing `\` for multi-line continuations) and makes dry-run show
# exactly what the unit will contain. systemd splits ExecStart on
# unquoted whitespace, so the binary and the model path — the only tokens
# that may contain spaces — are systemd_quote()d; plain flag/number
# tokens stay unquoted.
local exec_cmd
exec_cmd="$(systemd_quote "$llamacpp_full") -m $(systemd_quote "$model") --port $PORT --host $HOST"
exec_cmd+=" --n-gpu-layers $gpu_layers"
exec_cmd+=" --ctx-size $CTX_SIZE"
exec_cmd+=" --threads $THREADS"
if [ -n "$GPU_THREADS" ]; then
exec_cmd+=" --gpu-threads $GPU_THREADS"
fi
if [ -n "$TENSOR_SPLIT" ]; then
exec_cmd+=" --tensor-split $TENSOR_SPLIT"
fi
if [ -n "$BATCH_SIZE" ]; then
exec_cmd+=" --batch-size $BATCH_SIZE"
fi
if [ -n "$UBATCH_SIZE" ]; then
exec_cmd+=" --ubatch-size $UBATCH_SIZE"
fi
if [ -n "$TEMPERATURE" ]; then
exec_cmd+=" --temperature $TEMPERATURE"
fi
if [ -n "$TOP_K" ]; then
exec_cmd+=" --top-k $TOP_K"
fi
if [ -n "$TOP_P" ]; then
exec_cmd+=" --top-p $TOP_P"
fi
if [ -n "$REPETITION_PENALTY" ]; then
exec_cmd+=" --repetition-penalty $REPETITION_PENALTY"
fi
if [ -n "$MAPPING" ]; then
exec_cmd+=" --mmap"
fi
if [ -n "$LOCKING" ]; then
exec_cmd+=" --mlock"
fi
if [ -n "$KV_CACHE_SIZE" ]; then
exec_cmd+=" --kv-cache $KV_CACHE_SIZE"
fi
if [ -n "$METRICS" ]; then
exec_cmd+=" --metrics"
fi
if [ -n "$HEALTH" ]; then
exec_cmd+=" --health"
fi
if [ -n "$SLOTS" ]; then
exec_cmd+=" --slots $SLOTS"
fi
if [ "${DRY_RUN:-0}" -eq 1 ]; then
log "(dry-run) generate systemd unit $USER_SYSTEMD_DIR/$SERVICE"
log "(dry-run) ExecStart: $llamacpp_full -m $model --port $PORT --host $HOST --n-gpu-layers $gpu_layers --ctx-size $CTX_SIZE --threads $THREADS"
log "(dry-run) ExecStart: $exec_cmd"
log "(dry-run) systemctl --user daemon-reload && enable --now $SERVICE"
return 0
fi
# Generate systemd unit
# Generate systemd unit — ExecStart is a single line with the full command
mkdir -p "$USER_SYSTEMD_DIR"
cat > "$USER_SYSTEMD_DIR/$SERVICE" <<EOF
[Unit]
@@ -407,71 +505,16 @@ After=network-online.target
[Service]
Type=simple
ExecStart=$llamacpp_full -m $model --port $PORT --host $HOST
ExecStart=$exec_cmd
Restart=on-failure
RestartSec=5
TimeoutStopSec=10
KillMode=control-group
EnvironmentFile=-%h/.config/linux_post_install/ai.env
[Install]
WantedBy=default.target
EOF
# Add parameters if provided
if [ -n "$gpu_layers" ]; then
echo " --n-gpu-layers $gpu_layers" >> "$USER_SYSTEMD_DIR/$SERVICE"
fi
if [ -n "$CTX_SIZE" ]; then
echo " --ctx-size $CTX_SIZE" >> "$USER_SYSTEMD_DIR/$SERVICE"
fi
if [ -n "$THREADS" ]; then
echo " --threads $THREADS" >> "$USER_SYSTEMD_DIR/$SERVICE"
fi
if [ -n "$GPU_THREADS" ]; then
echo " --gpu-threads $GPU_THREADS" >> "$USER_SYSTEMD_DIR/$SERVICE"
fi
if [ -n "$TENSOR_SPLIT" ]; then
echo " --tensor-split $TENSOR_SPLIT" >> "$USER_SYSTEMD_DIR/$SERVICE"
fi
if [ -n "$BATCH_SIZE" ]; then
echo " --batch-size $BATCH_SIZE" >> "$USER_SYSTEMD_DIR/$SERVICE"
fi
if [ -n "$UBATCH_SIZE" ]; then
echo " --ubatch-size $UBATCH_SIZE" >> "$USER_SYSTEMD_DIR/$SERVICE"
fi
if [ -n "$TEMPERATURE" ]; then
echo " --temperature $TEMPERATURE" >> "$USER_SYSTEMD_DIR/$SERVICE"
fi
if [ -n "$TOP_K" ]; then
echo " --top-k $TOP_K" >> "$USER_SYSTEMD_DIR/$SERVICE"
fi
if [ -n "$TOP_P" ]; then
echo " --top-p $TOP_P" >> "$USER_SYSTEMD_DIR/$SERVICE"
fi
if [ -n "$REPETITION_PENALTY" ]; then
echo " --repetition-penalty $REPETITION_PENALTY" >> "$USER_SYSTEMD_DIR/$SERVICE"
fi
if [ -n "$MAPPING" ]; then
echo " --mmap" >> "$USER_SYSTEMD_DIR/$SERVICE"
fi
if [ -n "$LOCKING" ]; then
echo " --mlock" >> "$USER_SYSTEMD_DIR/$SERVICE"
fi
if [ -n "$KV_CACHE_SIZE" ]; then
echo " --kv-cache $KV_CACHE_SIZE" >> "$USER_SYSTEMD_DIR/$SERVICE"
fi
if [ -n "$METRICS" ]; then
echo " --metrics" >> "$USER_SYSTEMD_DIR/$SERVICE"
fi
if [ -n "$HEALTH" ]; then
echo " --health" >> "$USER_SYSTEMD_DIR/$SERVICE"
fi
if [ -n "$SLOTS" ]; then
echo " --slots $SLOTS" >> "$USER_SYSTEMD_DIR/$SERVICE"
fi
echo " " >> "$USER_SYSTEMD_DIR/$SERVICE"
echo "Restart=on-failure" >> "$USER_SYSTEMD_DIR/$SERVICE"
echo "RestartSec=5" >> "$USER_SYSTEMD_DIR/$SERVICE"
echo "TimeoutStopSec=10" >> "$USER_SYSTEMD_DIR/$SERVICE"
echo "KillMode=control-group" >> "$USER_SYSTEMD_DIR/$SERVICE"
echo "EnvironmentFile=-%h/.config/linux_post_install/ai.env" >> "$USER_SYSTEMD_DIR/$SERVICE"
echo "" >> "$USER_SYSTEMD_DIR/$SERVICE"
echo "[Install]" >> "$USER_SYSTEMD_DIR/$SERVICE"
echo "WantedBy=default.target" >> "$USER_SYSTEMD_DIR/$SERVICE"
chmod 644 "$USER_SYSTEMD_DIR/$SERVICE"
# Enable and start
@@ -514,6 +557,12 @@ cmd_stop() {
}
cmd_status() {
# llama-server must be present for the version probe below — same
# actionable deps message as `start`
if ! find_llamacpp >/dev/null 2>&1; then
err "llama-server not found — install llama.cpp (https://github.com/ggerganov/llama.cpp)"
fi
# Service state
local svc_state="stopped"
if systemctl --user is-active "$SERVICE" &>/dev/null; then
@@ -563,14 +612,11 @@ cmd_status() {
printf 'health: not running\n'
fi
# Version info
local version
version="$(detect_llama_version)"
if [ -n "$version" ]; then
printf 'version: %s\n' "$version"
else
printf 'version: unknown\n'
fi
# Version info (probe the resolved binary; "unknown" if unreadable)
local llamacpp_bin version
llamacpp_bin="$(find_llamacpp)"
version="$(detect_llama_version "$llamacpp_bin")"
printf 'version: %s\n' "$version"
}
cmd_models() {