134 lines
3.9 KiB
Bash
134 lines
3.9 KiB
Bash
#!/usr/bin/env bash
|
|
# u/complete: AI ghost-text code completion for the current acme window.
|
|
set -euo pipefail
|
|
|
|
PREFIX_MAX=4000
|
|
SUFFIX_MAX=1000
|
|
|
|
MOUNT=${OLLIE:-$HOME/mnt/ollie}
|
|
|
|
cmd=${0##*/}
|
|
die() { printf '%s: %s\n' "$cmd" "$*" >&2; exit 1; }
|
|
|
|
usage() {
|
|
cat <<EOF
|
|
usage: $cmd [-model MODEL] [-backend BACKEND]
|
|
|
|
Flags:
|
|
-model MODEL model to use (default: \$OLLIE_COMPLETE_MODEL)
|
|
-backend BACKEND backend to use (default: \$OLLIE_COMPLETE_BACKEND)
|
|
-help show this help
|
|
EOF
|
|
exit 0
|
|
}
|
|
|
|
model=${OLLIE_COMPLETE_MODEL:-}
|
|
backend=${OLLIE_COMPLETE_BACKEND:-}
|
|
|
|
while [ $# -gt 0 ]; do
|
|
case $1 in
|
|
-model) model=$2; shift ;;
|
|
-backend) backend=$2; shift ;;
|
|
-help) usage ;;
|
|
-*) die "unknown flag: $1" ;;
|
|
*) break ;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
[ -z "$model" ] && die "model required: set OLLIE_COMPLETE_MODEL or pass -model"
|
|
[ -z "$backend" ] && die "backend required: set OLLIE_COMPLETE_BACKEND or pass -backend"
|
|
|
|
[ -z "${winid:-}" ] || [ "$winid" = "0" ] && die "must be run from an acme window"
|
|
|
|
# Find or create a copilot session for the current working directory.
|
|
# Reuses an existing *-copilot session in this cwd if one is alive,
|
|
# otherwise spawns a new one.
|
|
find_or_create_session() {
|
|
local target_cwd="$1"
|
|
local id kv deadline
|
|
|
|
# Deterministic name: one copilot session per cwd.
|
|
id="$(printf '%s' "$target_cwd" | cksum | awk '{print $1}')-copilot"
|
|
|
|
if [ -d "$MOUNT/s/$id" ]; then
|
|
local state
|
|
state=$(cat "$MOUNT/s/$id/state" 2>/dev/null) || true
|
|
case "$state" in
|
|
failed*|error*)
|
|
# Dead session — kill and recreate below.
|
|
printf 'kill\n' > "$MOUNT/s/$id/ctl" 2>/dev/null || true
|
|
sleep 0.1
|
|
;;
|
|
*)
|
|
printf '%s\n' "$id"
|
|
return 0
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
kv="name=${id}
|
|
cwd=${target_cwd}
|
|
agent=copilot
|
|
backend=${backend}
|
|
model=${model}"
|
|
# If a concurrent invocation already created it, ignore the error.
|
|
printf '%s\n' "$kv" > "$MOUNT/s/new" 2>/dev/null || true
|
|
|
|
deadline=$(( $(date +%s) + 5 ))
|
|
until [ -d "$MOUNT/s/$id" ] || [ "$(date +%s)" -ge "$deadline" ]; do sleep 0.05; done
|
|
[ -d "$MOUNT/s/$id" ] || die "timeout waiting for copilot session"
|
|
|
|
printf '%s\n' "$id"
|
|
}
|
|
|
|
# Get filename for language context (last field of ctl line 1)
|
|
filename=$(9p read acme/$winid/ctl | awk 'NR==1{print $NF}')
|
|
|
|
# Sync addr to current dot, read rune offsets
|
|
echo "addr=dot" | 9p write acme/$winid/ctl
|
|
addr=$(9p read acme/$winid/addr)
|
|
q0=$(printf '%s' "$addr" | cut -d, -f1 | tr -d '#[:space:]')
|
|
q1=$(printf '%s' "$addr" | cut -d, -f2 | tr -d '#[:space:]')
|
|
|
|
# Read prefix (before dot) and suffix (from dot onward)
|
|
printf '#0,#%s' "$q0" | 9p write acme/$winid/addr
|
|
prefix=$(9p read acme/$winid/data)
|
|
|
|
printf '#%s,$' "$q1" | 9p write acme/$winid/addr
|
|
suffix=$(9p read acme/$winid/data)
|
|
|
|
# Truncate to context budget
|
|
prefix="${prefix: -$PREFIX_MAX}"
|
|
suffix="${suffix:0:$SUFFIX_MAX}"
|
|
|
|
# Find or create the copilot session, then submit
|
|
sid=$(find_or_create_session "$PWD")
|
|
B="$MOUNT/s/$sid"
|
|
|
|
printf '%s\n' "Complete the code at the cursor in ${filename}. Output ONLY the text to insert — no explanation, no markdown, no preamble.
|
|
|
|
<prefix>
|
|
${prefix}
|
|
</prefix>
|
|
<suffix>
|
|
${suffix}
|
|
</suffix>" > "$B/prompt"
|
|
|
|
# Wait for idle
|
|
while true; do
|
|
state=$(cat "$B/statewait" 2>/dev/null | tr -d '[:space:]') || break
|
|
[ "$state" = "idle" ] && break
|
|
done
|
|
|
|
# Read result from offset, then clear context for next completion
|
|
offset=$(cat "$B/offset" 2>/dev/null || echo 0)
|
|
result=$(tail -c +$((offset + 1)) "$B/chat" 2>/dev/null)
|
|
echo "clear" > "$B/ctl"
|
|
|
|
# Write completion to a new acme window
|
|
newid=$(9p read acme/new/ctl | awk 'NR==1{print $1}')
|
|
printf 'name ollie/complete\n' | 9p write acme/$newid/ctl
|
|
printf '%s' "$result" | 9p write acme/$newid/body
|
|
printf 'clean\n' | 9p write acme/$newid/ctl
|