front-ends: transparent FUSE remount on I/O errors

All front-ends (sh, b, ls, kill, cleanup, ellie.el, ollie-acme, Kmpl)
now retry file operations after running ollie-remount on failure.
contrib target added to 'all' so ollie-remount is always installed.
This commit is contained in:
Ollie Agent 2026-05-21 09:00:13 +02:00
parent 10760b57bf
commit 68082ad2a6
8 changed files with 35 additions and 15 deletions

2
acme

@ -1 +1 @@
Subproject commit c8e6c50e5382ac51c2fc0957320798be930840ba
Subproject commit 992050d462d823ac2e251a8fb92e9df4ae242b8c

2
el

@ -1 +1 @@
Subproject commit de3d08ce145218db8522c77c81d30248781ade90
Subproject commit d97f4c4f4241f1f9abd30797b76b525a86e3e586

2
mkfile
View File

@ -7,7 +7,7 @@
# mk httpgw # build only httpgw
# mk all # build everything (default)
all:V: core 9p acme httpgw webui data scripts
all:V: core 9p acme httpgw webui data scripts contrib
core:V:
echo === Building ollie-core ===

View File

@ -11,6 +11,11 @@ MOUNT=${OLLIE:-$HOME/mnt/ollie}
cmd=${0##*/}
die() { printf '%s: %s\n' "$cmd" "$*" >&2; exit 1; }
# Retry a command once after remounting on I/O error.
try() { "$@" 2>/dev/null || { ollie-remount && "$@"; }; }
# Write $1 to file $2, retrying after remount on failure.
wf() { printf '%s\n' "$1" > "$2" 2>/dev/null || { ollie-remount && printf '%s\n' "$1" > "$2"; }; }
usage() {
cat <<EOF
usage: $cmd [flags] [prompt...]
@ -87,14 +92,14 @@ agent=${agent}"
backend=${backend}"
[ -n "$model" ] && kv="${kv}
model=${model}"
printf '%s\n' "$kv" > "$MOUNT/s/new" || die "failed to create session"
wf "$kv" "$MOUNT/s/new" || die "failed to create session"
# Poll until the session directory is visible (FUSE entry cache may lag).
local deadline=$(( $(date +%s) + 5 ))
until [ -d "$B" ] || [ "$(date +%s)" -ge "$deadline" ]; do sleep 0.05; done
[ -d "$B" ] || die "timeout waiting for session $id"
printf '%s\n' "$prompt" > "$B/prompt" || die "failed to submit prompt"
wf "$prompt" "$B/prompt" || die "failed to submit prompt"
if [ "$bg" -eq 1 ]; then
printf '%s\n' "$B"
@ -105,7 +110,7 @@ model=${model}"
# when parallel sessions access the same mount).
local state
while true; do
state=$(cat "$B/state" 2>/dev/null | tr -d '[:space:]') || break
state=$(try cat "$B/state" | tr -d '[:space:]') || break
[ "$state" = "idle" ] && break
sleep 0.5
done
@ -117,8 +122,8 @@ model=${model}"
# Print result: chat content from offset onward.
local offset
offset=$(cat "$B/offset" 2>/dev/null || echo 0)
tail -c +$((offset + 1)) "$B/chat" 2>/dev/null
offset=$(try cat "$B/offset" || echo 0)
try tail -c +$((offset + 1)) "$B/chat"
printf '\n'
[ "$keep" -eq 0 ] && rm -r "$B" 2>/dev/null || true

View File

@ -4,8 +4,10 @@ set -euo pipefail
OLLIE=${OLLIE:-$HOME/mnt/ollie}
remount_once() { ollie-remount 2>/dev/null; }
for sess in "$OLLIE"/s/*/; do
[ -d "$sess" ] || continue
[ -d "$sess" ] || { remount_once; [ -d "$sess" ] || continue; }
state=$(awk -F= '$1=="state"{print $2; exit}' "$sess/cfg" 2>/dev/null | tr -d '[:space:]') || continue
[ "$state" = "idle" ] && rm -r "$sess"
done

View File

@ -1,2 +1,3 @@
#!/usr/bin/env bash
rm -r ${OLLIE}/s/$1
OLLIE=${OLLIE:-$HOME/mnt/ollie}
rm -r "${OLLIE}/s/$1" 2>/dev/null || { ollie-remount && rm -r "${OLLIE}/s/$1"; }

View File

@ -1,2 +1,3 @@
#!/usr/bin/env bash
cat ${OLLIE}/s/idx
OLLIE=${OLLIE:-$HOME/mnt/ollie}
cat "$OLLIE/s/idx" 2>/dev/null || { ollie-remount && cat "$OLLIE/s/idx"; }

View File

@ -24,12 +24,17 @@ fn die {
echo $* >[1=2]
exit 1
}
fn remount {
ollie-remount >[2]/dev/null
}
fn cfg_get {
awk -F= -v k=$1 '$1==k{gsub(/^[ \t]+|[ \t]+$/,"",$2); print $2; exit}' $S/cfg >[2]/dev/null
}
fn is_idle {
~ `{cat $S/state >[2]/dev/null} idle
state=`{cat $S/state >[2]/dev/null || { remount; cat $S/state >[2]/dev/null }}
~ $state idle
}
fn show_new {
@ -127,7 +132,13 @@ fn write_new {
if(! ~ $#backend 0) printf 'backend=%s\n' $backend
if(! ~ $#model 0) printf 'model=%s\n' $model
if(! ~ $#agent 0) printf 'agent=%s\n' $agent
} > $MOUNT/s/new
} > $MOUNT/s/new || { remount; {
if(! ~ $#name 0) printf 'name=%s\n' $name
printf 'cwd=%s\n' $_dir
if(! ~ $#backend 0) printf 'backend=%s\n' $backend
if(! ~ $#model 0) printf 'model=%s\n' $model
if(! ~ $#agent 0) printf 'agent=%s\n' $agent
} > $MOUNT/s/new }
}
fn create_session {
@ -199,7 +210,7 @@ chat_off=0
if(test -f $S/chat) chat_off=`{wc -c < $S/chat}
if(! test -t 0) {
cat > $S/prompt || die 'submit failed'
cat > $S/prompt || { remount; cat > $S/prompt } || die 'submit failed'
exit 0
}
@ -271,7 +282,7 @@ done; exit 1'}
case /*
printf 'unknown command: %s\n' `{printf '%s\n' $"input | awk '{print $1}'} >[1=2]
case *
printf '%s\n' $"input > $S/prompt || { printf 'submit failed\n' >[1=2] }
printf '%s\n' $"input > $S/prompt || { remount; printf '%s\n' $"input > $S/prompt } || { printf 'submit failed\n' >[1=2] }
while(! is_idle) {
n=`{wc -c < $S/chat >[2]/dev/null}